1

私はクラスを作る練習のためにtictactoeボードに取り組んでいますが、アルゴリズムに問題が発生しました。攻めのベストムーブを返しているように見えますが、守備はしていません。私はどこを台無しにしたのかわからず、それを見つけることができないようです。私はそれについてここで多くのことを調べ、それをsimularプロジェクトと比較しましたが、まだそれを理解できないようです. これが私のコードです。

package TicTacToe;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;


public class Solution {

private static GameBoard currentBoard; 
private static Player botPlayer; 

public static void main(String[] args) {

    Scanner in = new Scanner(System.in);
    String player;
    System.out.println("ENTER bot: ");
    player = in.next();

    if(player.equalsIgnoreCase("X")) {
        botPlayer = Player.X;}
    else {botPlayer = Player.O;}

    String board[] = new String[3];
    for(int i = 0; i < 3; i++) {
        System.out.println("ENTER board: ");
        board[i] = in.next();
    }

        currentBoard = new GameBoard(3,3, board);
        List<Space> OpenSpaces = getOpenSquares(currentBoard);
        MakeMove(OpenSpaces);

    System.exit(-1);
}

public static List<Space> getOpenSquares(GameBoard GB) {
    List<Space> OpenSpaces = new ArrayList<Space>();
    for(int r = 0; r < 3; r++) {
        for(int c = 0; c < 3; c++) {
            if(GB.squares[r][c] == Player.Open) {
                OpenSpaces.add(new Space(r,c));
            }
        }
    }
    return OpenSpaces;
}

private static Space bestMove;
private static Space currentMove;
private static Space previousMove;


private static void MakeMove(List<Space> OpenSpaces) {
    if(OpenSpaces.size() == currentBoard.Size) {
        Random random = new Random();
        bestMove = new Space(random.nextInt(2),2);
    } else {
        for(Space child: OpenSpaces) {
            currentMove = GetBestMove(currentBoard,botPlayer);
            if (currentMove != null){

            }else{
                continue;}
            if(previousMove != null && previousMove.Rank < currentMove.Rank ||
                    previousMove == null && currentMove != null) {
                bestMove = currentMove;
            }
            previousMove = currentMove;
        }   
    }
    if (bestMove != null) {
        currentBoard.squares[bestMove.X][bestMove.Y] = botPlayer;
        System.out.println("the best move is: " + currentMove.X + " " + currentMove.Y);
    } 
}

private static Space GetBestMove(GameBoard gb, Player p) {
    Space bestSpace = null;
    List<Space> cloneOpenSpaces = getOpenSquares(gb);
    GameBoard cloneBoard = null;
    cloneBoard = gb.Clone();
        for(Space Open: cloneOpenSpaces) {
            cloneBoard = gb.Clone();
            Space newSpace = Open;
            cloneBoard.squares[newSpace.X][newSpace.Y] = p;
            if(cloneBoard.Winner == Player.Open && cloneOpenSpaces.size() > 0) {
                Player InP;
                if(p == Player.X) {
                    InP = Player.O;
                }else {
                    InP = Player.X;
                    }

                Space tempMove = GetBestMove(cloneBoard, InP);
                if(tempMove != null){
                    newSpace.Rank = tempMove.Rank;
                }


            } else {
                if(cloneBoard.Winner == Player.Open) {
                    newSpace.Rank = 0;
                }else if(cloneBoard.Winner == Player.O) {
                    newSpace.Rank = -1;
                }else if(cloneBoard.Winner == Player.X) {
                    newSpace.Rank = 1;
                }

            }
            System.out.println(newSpace.Rank);
            if(bestSpace == null || 
                    (p == Player.X && newSpace.Rank < ((Space)bestSpace).Rank)||
                    (p == Player.O && newSpace.Rank > ((Space)bestSpace).Rank)) {
                bestSpace = newSpace;
            }               
        }
    return (Space)bestSpace;
}

public static enum Player {
    X (1),
    O (-1),
    Open (0);

    private final double value;
    Player(double value){
        this.value = value;
    }
}

public static class Space {
    public int X;
    public int Y;
    public double Rank;

    public Space(int x, int y) {
        this.X = x;
        this.Y = y;
        Rank = 0;
    }


    public Space() {
    }
}

public static class GameBoard {

    public int Rows;
    public int getRows() {
        return this.Rows;
    }
    public void setRows(int rows) {
        Rows = rows;
    }

    public int Columns;
    public int getColumns() {
        return this.Columns;
    }
    public void setColumns(int columns) {
        Columns = columns;
    }

    public Player[][] squares;

    //public Player[x][y] 
    public Player getPlayer(int x, int y) {
        return this.squares[x][y];
    }

    public void setPlayer(int x, int y, Player player) {
        squares[x][y] = player;
    }

    public boolean Full;

    public boolean isFull() {
        for(int r = 0; r < 2; r++) {
            for(int c = 0; c < 2; c++) {
                if (squares[r][c] != Player.Open) {return false;}
            }
        }
        return true;
    }

    public int Size;
    public int getSize() {
        return this.Size;
    }
    public void setSize(int size) {
        Size = size;
    }

    public List<Space> OpenSquares;
    public List<Space> getOpenSquares() {
        List<Space> OpenSquares = new ArrayList<Space>();
        for(int r = 0; r < Rows; r++) {
            for(int c = 0; c < Columns; c++) {
                if(squares[r][c] == Player.Open) {
                    OpenSquares.add(new Space(r,c));
                }
            }
        }
        return this.OpenSquares;
    }

    public Player Winner;
    public Player getWinner() {
        int count = 0; 

        //columns 
        for (int x = 0; x < Rows; x++) 
        { 
            count = 0;
            for (int y = 0; y < Columns; y++) {
                count += squares[x][y].value;
            }
            if (count == 3) {
                return Player.X; 
            }else if (count == -3) {
                return Player.O; 
            }
        } 

        //rows 
        for (int x = 0; x < Rows; x++) { 
            count = 0; 
            for (int y = 0; y < Columns; y++) {
                count += squares[y][x].value; 
            }
            if (count == 3) {
                return Player.X; 
            }else if (count == -3) {
                return Player.O; 
            }
        } 

        // Diagonals right to left 
        count = 0; 
        count += squares[0][0].value; 
        count += squares[1][1].value; 
        count += squares[2][2].value; 
        if (count == 3) {
            return Player.X; 
        }else if (count == -3) {
            return Player.O; 
        } 


        // Diagonals left to right 
        count = 0; 
        count += squares[0][2].value; 
        count += squares[1][1].value; 
        count += squares[2][0].value; 
        if (count == 3) {
            return Player.X; 
        }else if (count == -3) {
            return Player.O; 
        }
        return Player.Open; 
    }

    public GameBoard Clone() {
        GameBoard b = new GameBoard(Rows,Columns);
        b.squares = (Player[][])this.squares.clone();
        b.Winner = getWinner();
        return b;
    }

    // Class initializer 
    public GameBoard(int boardRows, int boardColumns, String[] board) {

        // Set the dimensions 
        Rows = boardRows;
        Columns = boardColumns;

        // Create game spaces 
        squares = new Player[Rows][Columns];
        for(int r = 0; r < Rows; r++) {
            for(int c = 0; c < Columns; c++) {
                //squares[i][n] = Player.Open;
                if(board[r].charAt(c) == 'X') {
                    squares[r][c] = Player.X;
                }
                if(board[r].charAt(c) == 'O') {
                    squares[r][c] = Player.O;
                }
                if(board[r].charAt(c) == '_') {
                    squares[r][c] = Player.Open;
                }
            }
        }
        this.Winner = getWinner();
        this.OpenSquares = getOpenSquares();
        //Size of the board
        this.Size = Rows * Columns;
    }

    // clone Class initializer
    public GameBoard(int boardRows, int boardColumns) {
        // Set the dimensions 
        Rows = boardRows;
        Columns = boardColumns;

        // Create game spaces 
        squares = new Player[Rows][Columns];
        for(int r = 0; r < Rows; r++) {
            for(int c = 0; c < Columns; c++) {
                squares[r][c] = Player.Open;
            }   
        }
        this.Winner = getWinner();
        this.OpenSquares = getOpenSquares();
        //Size of the board
        Size = Rows * Columns;
    }
}
}

すべてのクラスが一番下にあります。ヘルプと修正をお寄せいただきありがとうございます。:)

次のコードで再帰的にしましたが、スコアリングはまだわかりません..値が1、0、または-1の場合、同じ値の複数の移動がある場合、最初の移動が行われる可能性があります最善の手ではない「ブロッキング。

private static Space GetBestMove(GameBoard gb, Player p) {
Space bestSpace = null;
List<Space> cloneOpenSpaces = getOpenSquares(gb);
GameBoard cloneBoard = null;
cloneBoard = gb.Clone();
    for(Space Open: cloneOpenSpaces) {
        cloneBoard = gb.Clone();
        Space newSpace = Open;
        cloneBoard.squares[newSpace.X][newSpace.Y] = p;
        if(cloneBoard.Winner == Player.Open && cloneOpenSpaces.size() > 0) {
            Player InP;
            if(p == Player.X) {
                InP = Player.O;
            }else {
                InP = Player.X;
                }

            ***Space tempMove = GetBestMove(cloneBoard, InP);***
            if(tempMove != null){
                newSpace.Rank = tempMove.Rank;
            }

テストの結果は次のとおりです

テスト1

ENTER bot: 
O

ENTER board: 
[ ][O][ ]

ENTER board: 
[ ][ ][ ]

ENTER board: 
[ ][X][X]

-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0

the best move is: 0 2

テスト 2

ENTER bot: 
O

ENTER board: 
[ ][X][X]

ENTER board: 
[ ][ ][ ]

ENTER board: 
[ ][O][ ]


1.0
1.0
1.0
1.0
1.0
-1.0
1.0
-1.0
-1.0
1.0
-1.0
1.0
1.0
-1.0
-1.0
the best move is: 1 1
4

1 に答える 1

2

私はあなたのコードを実行していませんが、なぜあなたが問題を抱えているのか知っているかもしれません。ミニマックスアルゴリズムは本質的に再帰的です。あなたはそれぞれのオープンスペースを見て、それぞれのある種のスコアを決定します。これはあなたのコードに見られます。ただし、「ここに移動した場合、対戦相手は次のターンにどのようなオプションを使用できるか」という論理に相当する再帰が表示されません。同じスコアリング関数を呼び出し続けることができますが、両方のプレーヤーのオプションをスコアリングすることに注意してください。これは、計算が集中的になる可能性がある場所であり、剪定のようなものが関係する場所です。3つ先を見たいとしましょう。最初は5つのオープンスペースがあるとします。5つのオープンスペースのそれぞれについて、私は自分の選択肢を調べ、それぞれにスコアを付けます。次に、そこに移動するふりをして、スコアリング関数を介して新しいボードを送信します。そして、私の対戦相手が残りの4つの可能な動きの中で最高得点の動きをとると仮定します。それから私は彼がそこに移動したふりをし、そして私は再びスコアリング関数を介してボードを実行します。あなたはこれを設定された「深さ」、または潜在的な動きの数の間続け、対戦相手があなたが計算したことをするだろうと仮定して、最も高い値をもたらす動きを選びます。

これは長蛇の列だったと思いますが、どこかに少し価値が埋もれていたと思います。あなたのコードを見て、あなたが動きを記録している場所を見つけてください(あなたが勝利を見たらそれを取りなさい;あなたが勝利をブロックすることができるならそれを取りなさい;など)。次に、この関数を呼び出し続けて、偽の/潜在的な動き(スコアリング関数から最も高い値を持つもの)を追加し続けます。深さに達したら、最も価値のある結果をもたらす可能性のある動きを選択するだけです。

基本的に、コードでは、GetBestMove(...)から1回呼び出す必要がありますMakeMove(...)。ただし、GetBestMove(...)毎回変更されたボードを使用して、繰り返し自分自身を呼び出す必要があります。そして毎回、仮想の(または実際の)ボードが与えられた場合に最良の動きを返します。私があなたのコードに見ないのは、への再帰的な呼び出しとGetBestMove(...)、それに伴う必要な維持です。これは、攻撃的な行動しか得られない理由を説明しています。それは、あなたがその動きをした場合に対戦相手が何をすることができるかに関わらず、最良の即時の動きが何であるかを見るためだけに見えます!

私の仮定が間違っている場合は、何らかの動作を期待しているが、何か違うものが得られているテストケースを提供してください。

于 2012-08-21T04:31:34.267 に答える