# Tic Tac Toe



## Sonnenschein (26. Mrz 2011)

Hallo liebe Mitglieder,

ich beschäftige mich seit einigen Tagen mit dem Algorithmus für ein "TicTacToe" Programm ( 3 gewinnt). Es spielt"Mensch gegen Computer"..bzw sollte, allerdings kommt bei meiner Eingabe immer der Fehler, dass dieses ein ungültiger Zug ist. Desweiteren würde ich gerne, dass durch Zufall bestimmt wird, ob der Computer oder Mensch den ersten Zug macht. Kann mir jemand helfen ? Vielen Danke im Voraus.

Hier der Code :


```
import java.io.*;

public class TicTacToe {
private int[][] board; 
private int spielerAmZug;
private int spielTiefe; 


public TicTacToe(){
// Spielfeld von TicTacToe wird ausgeben!
System.out.println("Hier das Spielfeld :");
board = new int[3][3];
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
board[i][j] = 0;}




// das aktuelle Spielfeld von TicTacToe wird angezeigt
public void showBoard(){
System.out.println("\n**a*b*c**");
for (int i=0; i < 3; i++){
System.out.print((i+1)+" ");
for (int j=0; j < 3; j++){ 
if (board[i][j]==-1) System.out.print("O ");
else if (board[i][j]==1) System.out.print("X ");
else System.out.print(". ");
}
System.out.println(i+1);
}
System.out.println("**a*b*c**\n");
}

// Spiel schon zu Ende, da Spielzüge genug
public boolean finishedGame(){ 
if ((evaluate(board)!=0) || (countSigns(board)==9))
return true;
else return false;
} 

// das Spielergebnis wird ausgegeben
public String resultGame(){ 
int wert = evaluate(board);
if (wert==0) return "Spiel endet unentschieden.";
else if (wert==1) return "Spieler X gewinnt.";
else return "Spieler O gewinnt.";
} 


// Spieler ist am Zug
public boolean meinZug(int x, int y, int move) {
if ((x>=0)&&(x<3)&&(y>=0)&&(y<3)&&(board[x][y]==0)&&(spielerAmZug==move)) {
board[x][y] = move;
spielerAmZug = -spielerAmZug;
spielTiefe++;
return true;
} else 
return false;
}

// Computer ist am Zug
public void compZug() {
if (spielerAmZug==-1) {

spielTiefe++;
spielerAmZug = -spielerAmZug;
} } 

// zählt die Anzahl der bereits besetzten Felder
private int countSigns(int[][] b){
int count=0;
for (int i=0; i < 3; i++)
for (int j=0; j < 3; j++)
if (b[i][j]!=0)
count++;
return count;
} 


// bewertet die aktuelle Stellung, -1 O-gewinnt, 1 X-gewinnt, sonst 0
private int evaluate(int[][] b){
// prüfe zeilen und spalten
int sum=0, sum2=0;
for (int i=0; i < 3; i++) {
sum = b[i][0] + b[i][1] + b[i][2]; 
sum2 = b[0][i] + b[1][i] + b[2][i];
if ((sum == -3)||(sum2 == -3)) return -1;
else if ((sum == 3)||(sum2 == 3)) return 1; 
} 

// prüfe die Diagonale links oben nach rechts unten
sum = b[0][0] + b[1][1] + b[2][2];
// prüfe die Diagonale links unten nach rechts oben
sum2 = b[0][2] + b[1][1] + b[2][0];

if ((sum == -3)||(sum2 == -3)) return -1;
else if ((sum == 3)||(sum2 == 3)) return 1; 

// ansonsten ist es (noch) unentschieden 
return 0; 
} 

public static void main(String[] args){
TicTacToe ttt = new TicTacToe();
;

// zur Kommunikation 
InputStreamReader stdin = new InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin); 

int x, y;
while (true) {
ttt.showBoard();
System.out.println("Ihr Zug, zuerst x-Koordinate, dann y-Koordinate eingeben : ");

try {
x = Integer.parseInt(console.readLine());
y = Integer.parseInt(console.readLine());
} catch(Exception e){
System.out.println("Eingabefehler!Bitte versuchen Sie es noch einmal.");
continue;
} 
// Zug außerhalb der Spielfeldkoordinaten
if (!ttt.meinZug(y-1, x-1, 1)) {
System.out.println("Ungültiger Zug, bitte versuchen Sie es noch einmal.");
continue;
}

if (ttt.finishedGame()) {
System.out.print("Das Spiel ist beendet! ");
System.out.println(ttt.resultGame());
ttt.showBoard();
break;
}

System.out.println("Der Computer hat gespielt: ");
ttt.compZug();

if (ttt.finishedGame()) {
System.out.print("Das Spiel ist beendet! ");
System.out.println(ttt.resultGame());
ttt.showBoard();
break;
}
}
}
}
```


----------



## hdi (26. Mrz 2011)

Also für das zufällige Auswürfeln des Spielers, der anfangen darf:


```
Random r = new Random();
spielerAmZug = r.nextInt(2); // liefert eine Zahl zwischen 0 (inklusiv) und 2 (exklusiv), also 0 oder 1
```

Das ist jetzt halt unter der Annahme dass du zwei Spieler mit 0 oder 1 unterscheidest. Wenn du andere Werte abfragst musst du das natürlich anpassen.

Was die andere Frage angeht.. Naja du kannst nicht einfach 150 Zeilen Code reinklatschen und Fragen "wo ist der Fehler"  _Welcher _spielzug wird nicht erlaubt?


----------



## Runtime (26. Mrz 2011)

Vor allem solltest du den Code erstmal richtige formatieren, dann wird er lesbarer und Fehler können einfacher gefunden werden.
Falls du keine IDE benutzt solltest du dir eine zulegen.

```
import java.io.*;

public class TicTacToe {

    private int[][] board;
    private int spielerAmZug;
    private int spielTiefe;

    public TicTacToe() {
// Spielfeld von TicTacToe wird ausgeben!
        System.out.println("Hier das Spielfeld :");
        board = new int[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = 0;
            }
        }
    }

// das aktuelle Spielfeld von TicTacToe wird angezeigt
    public void showBoard() {
        System.out.println("\n**a*b*c**");
        for (int i = 0; i < 3; i++) {
            System.out.print((i + 1) + " ");
            for (int j = 0; j < 3; j++) {
                if (board[i][j] == -1) {
                    System.out.print("O ");
                } else if (board[i][j] == 1) {
                    System.out.print("X ");
                } else {
                    System.out.print(". ");
                }
            }
            System.out.println(i + 1);
        }
        System.out.println("**a*b*c**\n");
    }

// Spiel schon zu Ende, da Spielzüge genug
    public boolean finishedGame() {
        if ((evaluate(board) != 0) || (countSigns(board) == 9)) {
            return true;
        } else {
            return false;
        }
    }

// das Spielergebnis wird ausgegeben
    public String resultGame() {
        int wert = evaluate(board);
        if (wert == 0) {
            return "Spiel endet unentschieden.";
        } else if (wert == 1) {
            return "Spieler X gewinnt.";
        } else {
            return "Spieler O gewinnt.";
        }
    }

// Spieler ist am Zug
    public boolean meinZug(int x, int y, int move) {
        if ((x >= 0) && (x < 3) && (y >= 0) && (y < 3) && (board[x][y] == 0) && (spielerAmZug == move)) {
            board[x][y] = move;
            spielerAmZug = -spielerAmZug;
            spielTiefe++;
            return true;
        } else {
            return false;
        }
    }

// Computer ist am Zug
    public void compZug() {
        if (spielerAmZug == -1) {

            spielTiefe++;
            spielerAmZug = -spielerAmZug;
        }
    }

// zählt die Anzahl der bereits besetzten Felder
    private int countSigns(int[][] b) {
        int count = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (b[i][j] != 0) {
                    count++;
                }
            }
        }
        return count;
    }

// bewertet die aktuelle Stellung, -1 O-gewinnt, 1 X-gewinnt, sonst 0
    private int evaluate(int[][] b) {
// prüfe zeilen und spalten
        int sum = 0, sum2 = 0;
        for (int i = 0; i < 3; i++) {
            sum = b[i][0] + b[i][1] + b[i][2];
            sum2 = b[0][i] + b[1][i] + b[2][i];
            if ((sum == -3) || (sum2 == -3)) {
                return -1;
            } else if ((sum == 3) || (sum2 == 3)) {
                return 1;
            }
        }

// prüfe die Diagonale links oben nach rechts unten
        sum = b[0][0] + b[1][1] + b[2][2];
// prüfe die Diagonale links unten nach rechts oben
        sum2 = b[0][2] + b[1][1] + b[2][0];

        if ((sum == -3) || (sum2 == -3)) {
            return -1;
        } else if ((sum == 3) || (sum2 == 3)) {
            return 1;
        }

// ansonsten ist es (noch) unentschieden 
        return 0;
    }

    public static void main(String[] args) {
        TicTacToe ttt = new TicTacToe();

// zur Kommunikation 
        InputStreamReader stdin = new InputStreamReader(System.in);
        BufferedReader console = new BufferedReader(stdin);

        int x, y;
        while (true) {
            ttt.showBoard();
            System.out.println("Ihr Zug, zuerst x-Koordinate, dann y-Koordinate eingeben : ");

            try {
                x = Integer.parseInt(console.readLine());
                y = Integer.parseInt(console.readLine());
            } catch (Exception e) {
                System.out.println("Eingabefehler!Bitte versuchen Sie es noch einmal.");
                continue;
            }
// Zug außerhalb der Spielfeldkoordinaten
            if (!ttt.meinZug(y - 1, x - 1, 1)) {
                System.out.println("Ungültiger Zug, bitte versuchen Sie es noch einmal.");
                continue;
            }

            if (ttt.finishedGame()) {
                System.out.print("Das Spiel ist beendet! ");
                System.out.println(ttt.resultGame());
                ttt.showBoard();
                break;
            }

            System.out.println("Der Computer hat gespielt: ");
            ttt.compZug();

            if (ttt.finishedGame()) {
                System.out.print("Das Spiel ist beendet! ");
                System.out.println(ttt.resultGame());
                ttt.showBoard();
                break;
            }
        }
    }
}
```
Hier hats den vollständingen Source Code für den Zug des Computers.


----------



## Sonnenschein (26. Mrz 2011)

Der Spielzug zum Setzen funktioniert nicht. Das Spielfeld wird ausgegeben und dann soll die x-/y-Koordinate eingegeben werden. z.B. a 3 . Da kommt dann aber die Fehlermeldung, dass der Zug ungültig ist..


----------



## hdi (26. Mrz 2011)

Naja dann heißt es wohl dass 
	
	
	
	





```
!ttt.meinZug(y - 1, x - 1, 1)
```
 true ergibt. Das wiederum heißt, dass der Aufruf der meinZug() Methode false ergibt. Und das heißt, dass 
	
	
	
	





```
(x >= 0) && (x < 3) && (y >= 0) && (y < 3) && (board[x][y] == 0) && (spielerAmZug == move)
```
 false ergibt. Und _das _heißt, dass mindestens ein Teilterm false ist. Hier wäre jetzt also der Punkt, an dem du ansetzen musst. Lass dir mal die einzelnen Werte ausgeben. Sind x und y zwischen 0 und 2? Ist board[x][y] == 0? Und ist spielerAmZug == move? Alles mal per sysout anzeigen lassen.


----------



## JAVAnnik (27. Apr 2011)

ich finde TicTacToe gegen den Computer ein wenig sinnlos, denn wenn du richtig programmierst wird der Mensch nie gewinnen, da TicTacToe nur durch Fehler entschieden werden kann und extra einen Fehler zu programmieren finde ich auch nicht sehr sinnvoll


----------



## Marco13 (27. Apr 2011)

Aber dem Spieler nach dem ersten oder zweiten Spielzug schon eine Meldung einzublenden: "Du wirst verlieren  " hat doch auch was


----------



## Tomate_Salat (27. Apr 2011)

@JAVAnnik: In dem Falle dürftest du kein Spiel programmieren. Egoshooter/autorennen/Simulationen... Egal was. Die KI muss einfach manchmal menschliche Fehler machen. Soetwas zu programmieren ist also keineswegs sinnfrei und wenn es über Zufallsgenerierung hinaus geht, wohl auch nicht mehr trivial.


----------



## Sanix (27. Apr 2011)

Tomate_Salat hat gesagt.:


> @JAVAnnik: In dem Falle dürftest du kein Spiel programmieren. Egoshooter/autorennen/Simulationen... Egal was. Die KI muss einfach manchmal menschliche Fehler machen. Soetwas zu programmieren ist also keineswegs sinnfrei und wenn es über Zufallsgenerierung hinaus geht, wohl auch nicht mehr trivial.



Es gibt auch Spiele, wo es sehr schwierig ist, eine starke KI zu programmieren. Beim Schach gewinnt die KI erst seit ein paar Jahren, vorhin war der Mensch immer besser. Bei Echtzeitstrategiespielen ist der Mensch meistens auch besser, weil es sehr schwierig ist, eine Aktion in jedem Fall korrekt zu gewichten.


----------



## Tomate_Salat (27. Apr 2011)

und bei Strategie-spielen fangen viele ab einem gewissen Schwierigkeitsgrad an zu cheaten. Ich weis, es gibt sogar Wettbewerbe um die besten Schach-KI's aber darum geht es nicht. Ich wollte nur auf einen Denkfehler hinweisen. Es geht darum: in Computerspielen soll eine KI menschliche Fehler machen (oder bei leichtern schwierigkeitsgraden eben einfach dumm sein). Was herauskommt, wenn die KI übermenschlich ist, sieht man bei aimbot-usern. Es trübt den Spielspaß.


----------



## Firephoenix (28. Apr 2011)

Das Hauptproblem bleibt dabei immer die Bewertung  je intuitiver sich ein Spiel spielt, umso eher schlägt ein Mensch nach einer Lernzeit eine K.I.
Und jemand der eine perfekte KI für ein Strategiespiel schreibt das trotzdem so komplex ist, wird seine Techniken wohl eher beim Pentagon vermarkten 
Gruß


----------

