Tic Tac Toe

S

Sonnenschein

Gast
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 :

Java:
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

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

Java:
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

Top Contributor
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.
Java:
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.
 
Zuletzt bearbeitet:
S

Sonnenschein

Gast
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

Top Contributor
Naja dann heißt es wohl dass
Code:
!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
Code:
(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

Bekanntes Mitglied
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

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

Tomate_Salat

Gast
@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

Top Contributor
@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.
 
T

Tomate_Salat

Gast
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ß.
 
F

Firephoenix

Gast
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ß
 

Neue Themen


Oben