# TicTacToe MiniMax Algorithmus geht nicht



## Fabel (3. Jan 2022)

Ich wollte ein Tic-Tac-Toe mit einem Computer gesteuerten Gegenspieler programmieren, dafür habe ich einen zwei dimensionalen JButton Array verwendet. Leider geht der Computer immer das Array durch und macht seinen Zug bei der nächsten freien Stelle. Ich habe mir auch schon den Code auf Wikipedia angsehen, allerdings finde ich meinen Fehler nicht.

Hier macht der Computer seinen Zug:
*


		Java:In die Zwischenablage kopieren


public void hardgame() {

    int bestscore = Integer.MIN_VALUE;
    int movei= 0;
    int movej= 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            buttons[i][j].setForeground(new Color(245, 248, 255));
            if (buttons[i][j].getText() == "") {
            buttons[i][j].setText("O");
            int score = minimax(buttons, 0, false);
            buttons[i][j].setText("");
            if (score > bestscore) {
                bestscore = score;
               movei = i;
               movej = j;

            }
            }
        }
    }
    buttons[movei][movej].setText("O");
    check();
    if (!ende) {
        textfield.setText("X am Zug");
        player1_turn = true;
    }
}

*Und hier soll der Computer seinen Zug machen:
*


		Java:In die Zwischenablage kopieren


[/B]
public int minimax(JButton[][] buttons, int depth, boolean isMax) {
    if(victor != 0){
        return victor;
    }

    if (isMax) {
        int bestscore = Integer.MIN_VALUE;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j<3;j++) {
                buttons[i][j].setForeground(new Color(245, 248, 255));
                if (buttons[i][j].getText() == "") {

                    buttons[i][j].setText("O");
                    int score = minimax(buttons, depth + 1, false);
                    buttons[i][j].setText("");
                    bestscore = Math.max(score, bestscore);
                }
            }
        }


        return bestscore;
    } else {
        int bestscore = Integer.MAX_VALUE;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j<3; j++) {
                buttons[i][j].setForeground(new Color(245, 248, 255));
                if (buttons[i][j].getText() == "") {

                    buttons[i][j].setText("X");
                    int score = minimax(buttons, depth + 1, true);
                    buttons[i][j].setText("");
                    bestscore = Math.min(score, bestscore);
                }
            }
        }
        return bestscore;
    }

}
[B]

*


----------



## kneitzel (3. Jan 2022)

Zeige mL den ganze Code. Aber was so erst einmal auffällt: Du hast eine Prüfung auf Victor aber diese Variable wird  icht gesetzt. Er läuft also immer in ein return hinein, dass in den Felder nichts mehr frei ist so dass er die verschachtelten Schleifen durchläuft um dann denn Initialisierten Wert zurück zu geben.


----------



## Fabel (3. Jan 2022)

Hier ist mein ganzer Code, und schonmal danke für den Tipp:
*


		Java:In die Zwischenablage kopieren


[/B]
package tictac;

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class TicTacToe implements ActionListener {
    Random random = new Random();
    JFrame frame = new JFrame("TicTacToe");
    JPanel title_panel = new JPanel();
    JPanel button_panel = new JPanel();
    JPanel options = new JPanel();
    JLabel textfield = new JLabel();
    JButton ai = new JButton();
    JButton twoplayer = new JButton();
    JCheckBox easy = new JCheckBox();
    JCheckBox medium = new JCheckBox();
    JCheckBox hard = new JCheckBox();
    ButtonGroup gruppe = new ButtonGroup();
    JLabel turn = new JLabel();
    JLabel difficulty = new JLabel();
    JButton[][] buttons = new JButton[3][3];
    boolean player1_turn;
    boolean realplayer;
    boolean jmdgewonnen = false;
    int victor = 0;
    boolean ende = false;
    boolean unentschieden = false;

    TicTacToe() {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(730, 800);
        frame.getContentPane().setBackground(new Color(245, 248, 255));
        frame.setLayout(new BorderLayout());
        frame.setVisible(true);
        gruppe.add(easy);
        gruppe.add(medium);
        gruppe.add(hard);
        textfield.setBackground(new Color(161, 189, 255));
        textfield.setForeground(new Color(245, 248, 255));
        textfield.setFont(new Font("Arial", Font.BOLD, 70));
        textfield.setHorizontalAlignment(JLabel.CENTER);
        textfield.setText("Tic-Tac-Toe");
        textfield.setOpaque(true);
        title_panel.setLayout(new BorderLayout());
        title_panel.setBounds(0, 0, 800, 100);
        options.setBounds(0, 0, 800, 300);
        button_panel.setLayout(new GridLayout(3, 3));
        button_panel.setBackground(new Color(245, 248, 255));
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j <3; j++){
                buttons[i][j] = new JButton();
                button_panel.add(buttons[i][j]);
                buttons[i][j].setFont(new Font("Arial", Font.BOLD, 120));
                buttons[i][j].setFocusable(false);
                buttons[i][j].addActionListener(this);
                buttons[i][j].setBackground(new Color(161, 189, 255));
            }

        }
        turn.setBackground(new Color(161, 189, 255));
        turn.setForeground(new Color(245, 248, 255));
        turn.setFont(new Font("Arial", Font.BOLD, 56));
        turn.setHorizontalAlignment(JLabel.CENTER);
        turn.setText("2 Spieler oder gegen KI?");
        turn.setOpaque(true);
        ai.setBackground(new Color(181, 203, 255));
        ai.setFont(new Font("Arial", Font.BOLD, 50));
        ai.setHorizontalAlignment(JLabel.CENTER);
        ai.setFocusable(false);
        ai.setSize(50, 50);
        ai.setText("Einzelspieler");
        ai.setForeground(new Color(245, 248, 255));
        twoplayer.setBackground(new Color(181, 203, 255));
        twoplayer.setFont(new Font("Arial", Font.BOLD, 50));
        twoplayer.setHorizontalAlignment(JLabel.CENTER);
        twoplayer.setFocusable(false);
        twoplayer.setSize(50, 50);
        twoplayer.setText("Mehrspieler");
        twoplayer.setForeground(new Color(245, 248, 255));

        // ai difficluty
        difficulty.setBackground(new Color(161, 189, 255));
        difficulty.setForeground(new Color(245, 248, 255));
        difficulty.setFont(new Font("Arial", Font.BOLD, 56));
        difficulty.setHorizontalAlignment(JLabel.CENTER);
        difficulty.setText(" Schwierigkeitsgrad: ");
        difficulty.setOpaque(true);

        easy.setBackground(new Color(161, 189, 255));
        easy.setForeground(new Color(245, 248, 255));
        easy.setFont(new Font("Arial", Font.BOLD, 40));
        easy.setHorizontalAlignment(JLabel.CENTER);
        easy.setText("Easy");
        easy.setOpaque(true);

        medium.setBackground(new Color(161, 189, 255));
        medium.setForeground(new Color(245, 248, 255));
        medium.setFont(new Font("Arial", Font.BOLD, 40));
        medium.setHorizontalAlignment(JLabel.CENTER);
        medium.setText("Medium");
        medium.setOpaque(true);

        hard.setBackground(new Color(161, 189, 255));
        hard.setForeground(new Color(245, 248, 255));
        hard.setFont(new Font("Arial", Font.BOLD, 40));
        hard.setHorizontalAlignment(JLabel.CENTER);
        hard.setText("Hard");
        hard.setOpaque(true);

        title_panel.add(textfield);
        frame.add(title_panel, BorderLayout.NORTH);
        options.add(turn);
        options.add(ai);
        options.add(twoplayer);
        options.add(difficulty);
        options.add(easy);
        options.add(medium);
        options.add(hard);

        frame.add(options, BorderLayout.CENTER);
        medium.setSelected(true);
        check();
        firstTurn();

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        jmdgewonnen = false;
        unentschieden = false;
        check();

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3;j++){
                if (e.getSource() == buttons[i][j]) {
                    if (player1_turn) { // erster Spieler
                        if (buttons[i][j].getText() == "") {

                            buttons[i][j].setForeground(new Color(245, 248, 255));
                            buttons[i][j].setText("X");
                            check();

                            player1_turn = false;

                            if (realplayer) {
                                check();

                                textfield.setText("O am Zug");
                                check();

                            } else {
                                textfield.setText("Der Computer zieht");
                                if (easy.isSelected()) {
                                    easygame();
                                } else if (hard.isSelected()) {
                                    hardgame();
                                } else {
                                    mediumgame();
                                }
                                check();

                            }

                        }

                    } else if (realplayer) { // zweiter Spieler
                        check();

                        if (buttons[i][j].getText() == "") {
                            buttons[i][j].setForeground(new Color(245, 248, 255));
                            buttons[i][j].setText("O");
                            player1_turn = true;
                            textfield.setText("X am Zug");
                            check();

                        }
                        check();


                    }

                }

            }

        }
    }

    public void firstTurn() {
        twoplayer.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                jmdgewonnen = false;
                unentschieden = false;
                realplayer = true;
                for (int i = 0; i < 3; i++) {
                    for(int j = 0; j < 3; j++){
                        buttons[i][j].setText("");
                        buttons[i][j].setBackground(new Color(161, 189, 255));
                        buttons[i][j].setEnabled(true);
                    }

                }
                frame.add(button_panel);
                options.setVisible(false);
                button_panel.setVisible(true);
                realplayer = true;
                check();
                draw();
                if (random.nextInt(2) == 0) {
                    player1_turn = true;
                    textfield.setText("X am Zug");
                } else {
                    player1_turn = false;
                    textfield.setText("O am Zug");
                }

            }
        });

        ai.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                unentschieden = false;
                ende = false;
                victor = 0;
                realplayer = false;
                check();
                for (int i = 0; i < 3; i++) {
                    for(int j = 0; j < 3; j++){
                        buttons[i][j].setText("");
                        buttons[i][j].setBackground(new Color(161, 189, 255));
                        buttons[i][j].setEnabled(true);
                    }

                }
                frame.add(button_panel);
                options.setVisible(false);
                button_panel.setVisible(true);
                realplayer = false;

                if (random.nextInt(2) == 1) {
                    player1_turn = true;
                    textfield.setText("Du bist am Zug");
                } else {
                    player1_turn = false;
                    textfield.setText("Der Computer zieht");
                    if (easy.isSelected()) {
                        easygame();
                    } else if (hard.isSelected()) {

                        hardgame();
                    } else {
                        mediumgame();
                    }

                }

            }
        });
    }

    public void check() {
        // x com
        //horizontal

        if (buttons[0][0].getText() == "X" && buttons[1][0].getText() == "X" && buttons[2][0].getText() == "X") {
            xWins();

        }
        if (buttons[0][1].getText() == "X" && buttons[1][1].getText() == "X" && buttons[2][1].getText() == "X") {
            xWins();

        }
        if (buttons[0][2].getText() == "X" && buttons[1][2].getText() == "X" && buttons[2][2].getText() == "X") {
            xWins();

        }
        // vertikal
        if (buttons[0][0].getText() == "X" && buttons[0][1].getText() == "X" && buttons[0][2].getText() == "X") {
            xWins();

        }
        if (buttons[1][1].getText() == "X" && buttons[1][2].getText() == "X" && buttons[1][0].getText() == "X") {
            xWins();

        }
        if (buttons[2][1].getText() == "X" && buttons[2][2].getText() == "X" && buttons[2][0].getText() == "X") {
            xWins();

        }
        // diagonal
        if (buttons[0][0].getText() == "X" && buttons[1][1].getText() == "X" && buttons[2][2].getText() == "X") {
            xWins();
        }
        if (buttons[2][0].getText() == "X" && buttons[1][1].getText() == "X" && buttons[0][2].getText() == "X") {
            xWins();
        }
        // O Wins
        //horizontal

        if (buttons[0][0].getText() == "O" && buttons[1][0].getText() == "O" && buttons[2][0].getText() == "O") {
                oWins();

        }
        if (buttons[0][1].getText() == "O" && buttons[1][1].getText() == "O" && buttons[2][1].getText() == "O") {
            oWins();

        }
        if (buttons[0][2].getText() == "O" && buttons[1][2].getText() == "O" && buttons[2][2].getText() == "O") {
            oWins();

        }
        // vertikal
        if (buttons[0][0].getText() == "O" && buttons[0][1].getText() == "O" && buttons[0][2].getText() == "O") {
            oWins();

        }
        if (buttons[1][1].getText() == "O" && buttons[1][2].getText() == "O" && buttons[1][0].getText() == "O") {
            oWins();

        }
        if (buttons[2][1].getText() == "O" && buttons[2][2].getText() == "O" && buttons[2][0].getText() == "O") {
            oWins();

        }
        // diagonal
        if (buttons[0][0].getText() == "O" && buttons[1][1].getText() == "O" && buttons[2][2].getText() == "O") {
            oWins();
        }
        if (buttons[2][0].getText() == "O" && buttons[1][1].getText() == "O" && buttons[0][2].getText() == "O") {
            oWins();
        }
        draw();
    }

    public void xWins() {
        victor= 10;
        jmdgewonnen = true;
        ende = true;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                buttons[i][j].setEnabled(false);
            }
        }
        textfield.setText("Tic-Tac-Toe");
        if (realplayer) {
            turn.setText("X hat gewonnen");
        } else {
            turn.setText("Mensch hat gewonnen");
        }
        button_panel.setVisible(false);
        options.setVisible(true);
        firstTurn();
    }

    public void oWins() {
        victor = -10;
        jmdgewonnen = true;
        ende = true;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                buttons[i][j].setEnabled(false);
            }
        }

        button_panel.setVisible(false);
        options.setVisible(true);
        textfield.setText("Tic-Tac-Toe");
        if (realplayer) {
            turn.setText("O hat gewonnen");

        } else {
            turn.setText("Die AI hat gewonnen");
        }
        firstTurn();
    }

    public void draw() {
        victor=0;
        if (buttons[0][0].getText() != "" && buttons[1][1].getText() != "" && buttons[2][2].getText() != ""
                && buttons[0][1].getText() != "" && buttons[0][2].getText() != "" && buttons[1][0].getText() != ""
                && buttons[1][2].getText() != "" && buttons[2][0].getText() != "" && buttons[2][1].getText() != ""){
        for (int i = 0; i <3; i++){
            for (int j = 0; j <3; j++) {

                    if (!jmdgewonnen) {
                        victor = 0;
                        buttons[i][j].setEnabled(false);
                        button_panel.setVisible(false);

                        }
                    options.setVisible(true);
                    textfield.setText("Tic-Tac-Toe");
                    ende = true;
                    unentschieden = true;
                    turn.setText("Keiner hat gewonnen");
                    firstTurn();
                    }
                }
                }
            }
    public void easygame() {
        check();
        if(!ende){


        for (int i = 0; i <3; i++) {
            for (int j = 0; j < 3; j++) {
                buttons[i][j].setForeground(new Color(245, 248, 255));
            }
        }
        Random rand = new Random();
        int random1;
        int random2;
        random1 = rand.nextInt(3);
        random2 = rand.nextInt(3);
        if (buttons[0][0].getText() != "" && buttons[1][1].getText() != "" && buttons[2][2].getText() != ""
                && buttons[0][1].getText() != "" && buttons[0][2].getText() != "" && buttons[1][0].getText() != ""
                && buttons[1][2].getText() != "" && buttons[2][0].getText() != "" && buttons[2][1].getText() != "") {

        } else {

            while (buttons[random1][random2].getText() != "") {
                random1 = rand.nextInt(3);
                random2 = rand.nextInt(3);
            }
            buttons[random1][random2].setText("O");
            check();

            if (!ende) {
                textfield.setText("X am Zug");
                player1_turn = true;
            }
        }
        }
    }

    public void mediumgame() {
        check();


        Random rand = new Random();
        int random;
        random = rand.nextInt(2);

        if (random == 1) {
            easygame();
        }
        if (random == 0) {
            hardgame();
        }
        check();

        if (!ende) {
            textfield.setText("X am Zug");
            player1_turn = true;
        }
    }

    public void hardgame() {

        int bestscore = Integer.MIN_VALUE;
        int movei= 0;
        int movej= 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                buttons[i][j].setForeground(new Color(245, 248, 255));
                if (buttons[i][j].getText() == "") {
                buttons[i][j].setText("O");
                int score = minimax(buttons, 0, false);
                buttons[i][j].setText("");
                if (score > bestscore) {
                    bestscore = score;
                   movei = i;
                   movej = j;

                }
                }
            }
        }
        buttons[movei][movej].setText("O");
        check();
        if (!ende) {
            textfield.setText("X am Zug");
            player1_turn = true;
        }
    }

    /*
     * public void scores() {
     * Map<String, Integer> map = new Hashmap<>();
     * map.put(X, 10);
     * map.put(O, -10);
     * map.put(tie, 0);
     * }
     */
    public int minimax(JButton[][] buttons, int depth, boolean isMax) {
        if(victor != 0){
            return victor;
        }

        if (isMax) {
            int bestscore = Integer.MIN_VALUE;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j<3;j++) {
                    buttons[i][j].setForeground(new Color(245, 248, 255));
                    if (buttons[i][j].getText() == "") {
                        buttons[i][j].setText("O");
                        int score = minimax(buttons, depth + 1, false);
                        buttons[i][j].setText("");
                        bestscore = Math.max(score, bestscore);
                    }
                }
            }


            return bestscore;
        } else {
            int bestscore = Integer.MAX_VALUE;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j<3; j++) {
                    buttons[i][j].setForeground(new Color(245, 248, 255));
                    if (buttons[i][j].getText() == "") {

                        buttons[i][j].setText("X");
                        int score = minimax(buttons, depth + 1, true);
                        buttons[i][j].setText("");
                        bestscore = Math.min(score, bestscore);
                    }
                }
            }
            return bestscore;
        }

    }
}

[B]

*


----------



## kneitzel (3. Jan 2022)

Der Code ist recht unübersichtlich. Was Dir fehlt ist auf jeden Fall die korrekte Prüfung. Wenn das Spiel beendet ist, dann gibst Du den Victor Wert zurück.
Daher wird vom Prinzip her ein check() notwendig. Du hast aber das Problem, dass check nicht nur etwas prüft sondern auch etwas macht. Es ruft halt draw auf, das prinzipiell prüft, ob noch Züge möglich sind. Aber dabei wird dann auch das Spielfeld verändert, so dem nicht mehr so sein sollte. Oder wenn jemand gewonnen hat, werden Variablen umgesetzt. Und das ist halt weniger geschickt. Hier muss vermutlich der Code generell noch weiter angepasst werden, so dass Du da eine saubere Trennung hast bezüglich eine Stellung prüfen und auf die Prüfung zu reagieren.


----------



## fhoffmann (3. Jan 2022)

Fabel hat gesagt.:


> buttons_[j].getText() == ""_


Einen Punkt habe ich herausgepickt: Strings werden nicht mit "==" sondern mit "equals()" verglichen.

Allgemein würde ich aber (zustimmend zu der Bemerkung von @kneitzel "Der Code ist recht unübersichtlich.") noch sagen: Du solltest die Oberfläche von der Logik trennen! Alles in eine Klasse zu packen, führt automatisch zu Problemen.


----------

