Tic Tac Toe: KI funktioniert nicht



  • Hi,
    gestern Abend habe ich einfach mal entschlossen Tic Tac Toe zu programmieren, aber bei der KI (Künstliche Intelligenz), hat es gescheitert.
    Vorerst: Ich bin damit noch nicht fertig. Ich will erst einmal verhindern, dass der Spieler gewinnt bzw. drei in der richtigen Reigenfolge schafft.

    import java.io.*;
    
    class TicTacToe {
      public static void main(String[] args) {
    
      int eingabe= -1;
      char matrix[][]={
                    {' ', ' ', ' ','#', ' ', ' ', '#', ' ', ' ',' '},
                    {' ', '1', ' ','#', ' ', '2', '#', ' ', '3', ' '},
                    {'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
                    {' ', '4', ' ', '#', ' ', '5', '#', ' ', '6', ' '},
                    {'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
                    {' ', '7', ' ', '#', ' ', '8', '#', ' ', '9', ' '},
                    {' ', ' ', ' ','#', ' ', ' ', '#', ' ', ' ', ' '}, };
    
      do{
        try{
          BufferedReader daten= new BufferedReader(new InputStreamReader(System.in));
    
          for(int j=0; j<matrix.length; j++){
            for (int i = 0; i < 10; i++) {
              System.out.print(String.valueOf(matrix[j][i]));
    
            }
            System.out.println();
          }
          System.out.println("Welches Feld soll angekreuzt werden? (0 eingeben, um abzubrechen)");
    
          eingabe = Integer.parseInt(daten.readLine());
    
          if(eingabe == 0)
            System.out.println("Beendet.");
    
          else
            switch(eingabe)
            {
            case 1:
            matrix[1][1]='X';
            break;
            case 2:
            matrix[1][5]='X';
            break;
            case 3:
            matrix[1][8]='X';
            break;
            case 4:
            matrix[3][1]='X';
            break;
            case 5:
            matrix[3][5]='X';
            break;
            case 6:
            matrix[3][8]='X';
            break;
            case 7:
            matrix[5][1]='X';
            break;
            case 8:
            matrix[5][5]='X';
            break;
            case 9:
            matrix[5][8]='X';
            break;
            default:
            System.out.println("Feld nicht vorhanden!");
            }
        // 1, 2
        if(matrix[1][1]=='X' && matrix[1][5]=='X' && matrix[1][8]!='X' || matrix[1][8]!='O')
          matrix[1][8]='O';
    
        //1, 4
        else if(matrix[1][1]=='X' && matrix[3][1]=='X' && matrix[5][1]!='X' || matrix[5][1]!='O')
          matrix[5][1]='O';
    
        //4, 7
        else if(matrix[3][1]=='X' && matrix[5][1]=='X' && matrix[1][1]!='X' || matrix[1][1]!='O')
          matrix[1][1]='O';
    
        //2, 5
        else if(matrix[1][5]=='X' && matrix[3][5]=='X' && matrix[5][5]!='X' || matrix[5][5]!='O')
          matrix[5][5]='O';
    
        //5, 8
        else if(matrix[3][5]=='X' && matrix[5][5]=='X' && matrix[1][5]!='X' || matrix[1][5]!='O')
          matrix[1][5]='O';
    
        //3, 6
        else if(matrix[1][8]=='X' && matrix[3][8]=='X' && matrix[5][8]!='X' || matrix[5][8]!='O')
          matrix[5][8]='O';
    
        //6, 9
        else if(matrix[3][8]=='X' && matrix[5][8]=='X' && matrix[1][8]!='X' || matrix[1][8]!='O')
          matrix[1][8]='O';
    
        //4, 5
        else if(matrix[3][1]=='X' && matrix[3][5]=='X' && matrix[3][8]!='X' || matrix[3][8]!='O')
          matrix[3][8]='O';
    
        //5, 6
        else if(matrix[3][5]=='X' && matrix[3][8]=='X' && matrix[3][1]!='X' || matrix[3][1]!='O')
          matrix[3][1]='O';
    
        //1, 5
        else if(matrix[1][1]=='X' && matrix[3][5]=='X' && matrix[5][8]!='X' || matrix[5][8]!='O')
          matrix[5][8]='O';
    
        //5, 9
        else if(matrix[3][5]=='X' && matrix[5][8]=='X' && matrix[1][1]!='X' || matrix[1][1]!='O')
          matrix[1][1]='O';
    
        } catch(IOException f){
          System.out.println("Fehler bei der Eingabe! Bitte nur Zahlen eingeben!");
        }
        }while(eingabe!=0);
      }
    }
    

    Kompiliert das bitte mal. Es kreuzt einfach nicht an den richtigen Stellen an.
    Zuvor war der Code bei mir so:

    // 1, 2
        if(matrix[1][1]=='X' && matrix[1][5]=='X')
          matrix[1][8]='O';
    
        //1, 4
        if(matrix[1][1]=='X' && matrix[3][1]=='X')
          matrix[5][1]='O';
    
        //4, 7
        if(matrix[3][1]=='X' && matrix[5][1]=='X')
          matrix[1][1]='O';
    
        //2, 5
        if(matrix[1][5]=='X' && matrix[3][5]=='X')
          matrix[5][5]='O';
    
        //5, 8
        if(matrix[3][5]=='X' && matrix[5][5]=='X')
          matrix[1][5]='O';
    
        //3, 6
        if(matrix[1][8]=='X' && matrix[3][8]=='X')
          matrix[5][8]='O';
    
        //6, 9
        if(matrix[3][8]=='X' && matrix[5][8]=='X')
          matrix[1][8]='O';
    
        //4, 5
        if(matrix[3][1]=='X' && matrix[3][5]=='X')
          matrix[3][8]='O';
    
        //5, 6
        if(matrix[3][5]=='X' && matrix[3][8]=='X')
          matrix[3][1]='O';
    
        //1, 5
        if(matrix[1][1]=='X' && matrix[3][5]=='X')
          matrix[5][8]='O';
    
        //5, 9
        if(matrix[3][5]=='X' && matrix[5][8]=='X')
          matrix[1][1]='O';
    

    Da war das Problem, dass an manchen Stellen der Computer zwei Stellen gleichzeitig angekreutzt hat.

    Wie kann ich das besser hinkriegen?!

    Liebe Grüße
    Real



  • Ich weis nich ob es besser ist, aber ich hab´s jedenfalls so gemacht:

    public class KI {
    
        boolean[][][] set = new boolean[3][3][2]; // 3 x 3 Feld x oder nicht
    
        // [x][y][0] = x
        // [x][y][1] = o
        boolean x = false;
    
        public final void setX(Point p) {
    
            set[p.x][p.y][0] = true;
        }
    
        public KI(String l) { // hat der Spieler X oder O?
    
            if (l.equals("x")) {
                x = true;
            }
            // weis nich ob alle felder des boolean arrays nun mit true oder false
            // initialisiert wurden, also:
            for (int x = 0; x < 3; ++x) {
                for (int y = 0; y < 3; ++y) {
                    for (int s = 0; s < 2; ++s) {
                        set[x][y][s] = false;
                    }
                }
            }
        }
    
        public final void setO(Point p) {
    
            set[p.x][p.y][1] = true;
        }
    
        public final Point getNextField() {
    
            //KI berechnungen
            //Spielfeld:
            /*
    
           x0 1 2
          y - - -
          0|1|2|3|
            - - -
          1|4|5|6|
            - - -
          2|7|8|9|
            - - -
    
            */
            if (setCount() <= 2) {
                Point p = new Point(-1, -1);
                while (true) {
                    p = getRandomPoint();
                    if (!pointMatch(p)) break;
                }
                return p;
            } else {
                if (!x) {
                    if (isEmpty(1) && isX(4) && isX(7)) return new Point(0, 0);
                    else if (isEmpty(1) && isX(2) && isX(3)) return new Point(0, 0);
                    else if (isEmpty(1) && isX(5) && isX(9)) return new Point(0, 0);
                    else if (isEmpty(2) && isX(5) && isX(8)) return new Point(1, 0);
                    else if (isEmpty(3) && isX(6) && isX(9)) return new Point(2, 0);
                    else if (isEmpty(3) && isX(5) && isX(7)) return new Point(2, 0);
                    else if (isEmpty(4) && isX(5) && isX(6)) return new Point(0, 1);
                    else if (isEmpty(7) && isX(8) && isX(9)) return new Point(0, 2);
    
                    else if (isX(1) && isEmpty(4) && isX(7)) return new Point(0, 1);
                    else if (isX(1) && isEmpty(2) && isX(3)) return new Point(1, 0);
                    else if (isX(1) && isEmpty(5) && isX(9)) return new Point(1, 1);
                    else if (isX(2) && isEmpty(5) && isX(8)) return new Point(1, 1);
                    else if (isX(3) && isEmpty(6) && isX(9)) return new Point(2, 1);
                    else if (isX(3) && isEmpty(5) && isX(7)) return new Point(1, 1);
                    else if (isX(4) && isEmpty(5) && isX(6)) return new Point(1, 1);
                    else if (isX(7) && isEmpty(8) && isX(9)) return new Point(1, 2);
    
                    else if (isX(1) && isX(4) && isEmpty(7)) return new Point(0, 2);
                    else if (isX(1) && isX(2) && isEmpty(3)) return new Point(2, 0);
                    else if (isX(1) && isX(5) && isEmpty(9)) return new Point(2, 2);
                    else if (isX(2) && isX(5) && isEmpty(8)) return new Point(1, 2);
                    else if (isX(3) && isX(6) && isEmpty(9)) return new Point(2, 2);
                    else if (isX(3) && isX(5) && isEmpty(7)) return new Point(0, 2);
                    else if (isX(4) && isX(5) && isEmpty(6)) return new Point(2, 1);
                    else if (isX(7) && isX(8) && isEmpty(9)) return new Point(2, 2);
    
                } else {
                    if (isEmpty(1) && isO(4) && isO(7)) return new Point(0, 0);
                    else if (isEmpty(1) && isO(2) && isO(3)) return new Point(0, 0);
                    else if (isEmpty(1) && isO(5) && isO(9)) return new Point(0, 0);
                    else if (isEmpty(2) && isO(5) && isO(8)) return new Point(1, 0);
                    else if (isEmpty(3) && isO(6) && isO(9)) return new Point(2, 0);
                    else if (isEmpty(3) && isO(5) && isO(7)) return new Point(2, 0);
                    else if (isEmpty(4) && isO(5) && isO(6)) return new Point(0, 1);
                    else if (isEmpty(7) && isO(8) && isO(9)) return new Point(0, 2);
    
                    else if (isO(1) && isEmpty(4) && isO(7)) return new Point(0, 1);
                    else if (isO(1) && isEmpty(2) && isO(3)) return new Point(1, 0);
                    else if (isO(1) && isEmpty(5) && isO(9)) return new Point(1, 1);
                    else if (isO(2) && isEmpty(5) && isO(8)) return new Point(1, 1);
                    else if (isO(3) && isEmpty(6) && isO(9)) return new Point(2, 1);
                    else if (isO(3) && isEmpty(5) && isO(7)) return new Point(1, 1);
                    else if (isO(4) && isEmpty(5) && isO(6)) return new Point(1, 1);
                    else if (isO(7) && isEmpty(8) && isO(9)) return new Point(1, 2);
    
                    else if (isO(1) && isO(4) && isEmpty(7)) return new Point(0, 2);
                    else if (isO(1) && isO(2) && isEmpty(3)) return new Point(2, 0);
                    else if (isO(1) && isO(5) && isEmpty(9)) return new Point(2, 2);
                    else if (isO(2) && isO(5) && isEmpty(8)) return new Point(1, 2);
                    else if (isO(3) && isO(6) && isEmpty(9)) return new Point(2, 2);
                    else if (isO(3) && isO(5) && isEmpty(7)) return new Point(0, 2);
                    else if (isO(4) && isO(5) && isEmpty(6)) return new Point(2, 1);
                    else if (isO(7) && isO(8) && isEmpty(9)) return new Point(2, 2);
    
                }    
            }
            Point p = null;
            while (true) {
                p = getRandomPoint();
                if (!pointMatch(p)) break;
            }
            return p;
        }
    
        public final boolean isEmpty(int field) {
    
            if (!isX(field) && !isO(field)) return true;
            return false;
        }
    
        public final boolean isTripleX() {
    
            if (isX(1) && isX(4) && isX(7)) return true;
            else if (isX(1) && isX(2) && isX(3)) return true;
            else if (isX(1) && isX(5) && isX(9)) return true;
            else if (isX(2) && isX(5) && isX(8)) return true;
            else if (isX(3) && isX(6) && isX(9)) return true;
            else if (isX(3) && isX(5) && isX(7)) return true;
            else if (isX(4) && isX(5) && isX(6)) return true;
            else if (isX(7) && isX(8) && isX(9)) return true;
            else return false;
        }
    
        public final boolean isTripleO() {
    
            if (isO(1) && isO(4) && isO(7)) return true;
            else if (isO(1) && isO(2) && isO(3)) return true;
            else if (isO(1) && isO(5) && isO(9)) return true;
            else if (isO(2) && isO(5) && isO(8)) return true;
            else if (isO(3) && isO(6) && isO(9)) return true;
            else if (isO(3) && isO(5) && isO(7)) return true;
            else if (isO(4) && isO(5) && isO(6)) return true;
            else if (isO(7) && isO(8) && isO(9)) return true;
            else return false;
        }
    
        private final boolean pointMatch(Point p) {
    
            for (int x = 0; x < 3; ++x) {
                for (int y = 0; y < 3; ++y) {
                    if (p.x == x && p.y == y) {
                        if (set[x][y][0] == true || set[x][y][1] == true) return true;
                    }
                }
            }
            return false;
        }
    
        public final boolean isX(int field) {
    
            if (field == 1) {
                if (set[0][0][0]) return true;
            } else if (field == 2) {
                if (set[1][0][0]) return true;
            } else if (field == 3) {
                if (set[2][0][0]) return true;
            } else if (field == 4) {
                if (set[0][1][0]) return true;
            } else if (field == 5) {
                if (set[1][1][0]) return true;
            } else if (field == 6) {
                if (set[2][1][0]) return true;
            } else if (field == 7) {
                if (set[0][2][0]) return true;
            } else if (field == 8) {
                if (set[1][2][0]) return true;
            } else if (field == 9) {
                if (set[2][2][0]) return true;
            } else {
                return false;
            }
            return false;
        }
    
        public final boolean isO(int field) {
    
            if (field == 1) {
                if (set[0][0][1]) return true;
            } else if (field == 2) {
                if (set[1][0][1]) return true;
            } else if (field == 3) {
                if (set[2][0][1]) return true;
            } else if (field == 4) {
                if (set[0][1][1]) return true;
            } else if (field == 5) {
                if (set[1][1][1]) return true;
            } else if (field == 6) {
                if (set[2][1][1]) return true;
            } else if (field == 7) {
                if (set[0][2][1]) return true;
            } else if (field == 8) {
                if (set[1][2][1]) return true;
            } else if (field == 9) {
                if (set[2][2][1]) return true;
            } else {
                return false;
            }
            return false;
        }
    
        public final int setCount() {
    
            int c = 0;
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    if (set[i][j][0] == true || set[i][j][1] == true) ++c;
                }
            }
            return c;
        }
    
        private final Point getRandomPoint() {
    
            double rc = Math.random();
            int xc = 0;
            int yc = 0;
            if (rc >= 0.0 && rc < 0.1) {
                xc = 0;
                yc = 0;
            } else if (rc >= 0.1 && rc < 0.2) {
                xc = 0;
                yc = 1;
            } else if (rc >= 0.2 && rc < 0.3) {
                xc = 0;
                yc = 2;
            } else if (rc >= 0.3 && rc < 0.4) {
                xc = 1;
                yc = 0;
            } else if (rc >= 0.4 && rc < 0.5) {
                xc = 1;
                yc = 1;
            } else if (rc >= 0.5 && rc < 0.6) {
                xc = 1;
                yc = 2;
            } else if (rc >= 0.6 && rc < 0.7) {
                xc = 2;
                yc = 0;
            } else if (rc >= 0.7 && rc < 0.8) {
                xc = 2;
                yc = 1;
            } else if (rc >= 0.8 && rc < 0.9) {
                xc = 2;
                yc = 2;
            } else {
                return getRandomPoint();
            }
            return new Point(xc, yc);
        }
    }
    

    Nagut, es ist jedenfalls umfangreicher, aber dafür einfach und es funktioniert! 😃



  • Oh!
    So viel Wissen habe ich noch nicht, dass ich Point und Random verstehe.
    Jedenfalls, wenn ich es kompilieren will, kommt folgende Fehlermeldung:

    java.lang.NoSuchMethodError: main

    Exception in thread "main"

    Liebe Grüße
    Reality



  • Nicht zu Java, sondern nur zur KI:

    Googlet mal nach "Minimax" (wird für Schach/Dame etc. verwendet), kann man ganz gut auch für Tic-Tac-Toe implementieren.



  • Bist du sicher, dass der Fehler beim Compilieren auftritt? Ich könnte es mir höchstens beim Start per java KI vorstellen. Da wäre es auch ganz logisch, da die Klasse keine main-Methode hat. Sie ist lediglich eine Hilfsklasse, die der Hauptklasse sagt, in welches Feld das Symbol der KI gesetzt werden soll(also x oder o).
    Also du musst das so machen, dass der Spieler ein Feld "ankreuzen" kann und das musst der KI per setX(new Point(x, y)) mitteilen. Daraufhin kannst du mit getNextField() herausfinden, welches Feld die KI mit einem O versehen will.
    Z.B. so: ki.setO(ki.getNextField())
    Das ist alles nur "Berechnung", die grafische Darstellung des Geschehens musst du hier übernehmen.

    Zu random() und Point:
    random auf deutsch: ziellos, zufällig

    Math.random() gibt dir einfach eine zufällige Zahl vom Typ double zwischen 0.0 und 1.0 zurück.
    Point ist eine Klasse die die 2 variablen x und y beinhaltet, die hier mit Zeile und Spalte des Spielfeldes gleichzusetzen sind.



  • Doktor Prokt schrieb:

    Nicht zu Java, sondern nur zur KI:

    Googlet mal nach "Minimax" (wird für Schach/Dame etc. verwendet), kann man ganz gut auch für Tic-Tac-Toe implementieren.

    Das ist sicher angebracht bei der vielzahl der Möglichen Brettkonstellationen in Schach und Dame. Aber bei Tic-Tac-Toe lassen sich alle möglichen Stellungen im voraus berechnen. Diese könnte man in einem Baum mit Bewertung der Stellung speichern. Wenn man das konsequent anwendet, kann der Menschliche Gegner höchstens unentschieden spielen aber nich gewinnen.

    [Edit] sry hab das i überlesen. Was ich da geschrieben hab ist ja der minimaxalgorithmus [/edit]



  • Hmm,leider habe ich zu MiniMax nur das Spiel selbst gefunden.

    Liebe Grüße
    Real


Anmelden zum Antworten