Minimax问题 - 连接四个。

时间:2016-08-17 23:47:58

标签: java algorithm minimax

我正在努力进行极小极大运动,我只是试图用它连接四个ai。当我只深入探索一个节点时,我的工作正常,但我无法弄清楚为什么它一旦深入就会混乱。

private int minimax(Gameboard gameBoard, int alpha, int depth, char color) {
    Gameboard gb = new Gameboard(gameBoard);
    int value = 0;
    int bestChoice = 0;
    int bestValue = alpha;
    // determine which use the value is for
    if (gb.computerColor == color) {
        value = 1;
    } else {
        value = -1;
    }
    if (gb.CheckForWinner(gb.lastSpacePlayed)) {
        if(gb.winner == gb.computerColor){
            bestValue = (1000000000 - depth);
        }else{
            bestValue = (-1000000000 - depth);
        }

    }

    // get the bestValue at our maximum recrusion depth
    else if (depth == maxDepth) {
        int moveWeight = (threatLevel(gb, color));
        if (moveWeight != 0) {
            bestValue = value * (moveWeight - depth);
        } else {
            bestValue = moveWeight;
        }
    } else {
        // Generate moves for each col and find the best score from each of
        // the generated moves.
        for (int c = 0; c < 7; c++) {
            Gameboard game = new Gameboard(gb);
            int selectedPlace = game.PlacePiece(c, color);

            // Recursive call the generated game grid and compare the
            // current value to move value
            // If move is higher, make it the new current value.

            if (selectedPlace != -1) {
                char tempColor;
                // change the user for the child node after a piece is played
                if (color == 'Y') {
                    tempColor = 'R';
                } else {
                    tempColor = 'Y';
                }
                // call the function so we can explore to maximum depth
                if (depth < maxDepth) {
                    int v = minimax(new Gameboard(game), -1000000, depth + 1, tempColor);
                    if (v > bestValue) {
                        bestChoice = c;
                        bestValue = v;
                    }
                    System.out.println(v);
                }
            }
        }
    }
    if (depth == 0) {
        if (threatLevel(gb, gb.lastSpacePlayed.getColor()) == 0) {
            return gb.spaces.get(0).get(3).getColor() == gb.playerColor ? 2
                    : 3;
        } else {
            return bestChoice;
        }
    } else {
        return bestValue;
    }

}

我是以return minimax(gameBoard, -1000000, 0, gameBoard.computerColor);

开始的

我的理解是循环遍历所有子节点,如果节点与父节点相同则返回值为最大值,如果节点不相同则返回最小值。任何方向将不胜感激。

2 个答案:

答案 0 :(得分:1)

private int minimax(Gameboard gameBoard, int depth, char color) {
    Gameboard gb = new Gameboard(gameBoard);
    int bestChoice = 0;
    int bestValue = 0;

    //If we've won, return highest possible value. If we've lost, return lowest.
    if (gb.CheckForWinner(gb.lastSpacePlayed)) {
        if(gb.winner == color){
            return Integer.MAX_VALUE
        }else{
            return Integer.MIN_VALUE
        }

    }
    //if we hit maximum depth, resort to our heuristic method.
    else if (depth == maxDepth) {
        return threatLevel(gb, color);
    } else {
        // Generate moves for each col and find the best score from each of
        // the generated moves. Keep track of the worst one.
        int worstBestResponse = Integer.MAX_INT
        boolean tie = true;
        for (int c = 0; c < 7; c++) {
            Gameboard game = new Gameboard(gb);
            int selectedPlace = game.PlacePiece(c, color);

            // Recursive call the generated game grid and compare the
            // current value to move value
            // If move is higher, make it the new current value.

            if (selectedPlace != -1) {
                tie = false;
                char tempColor;
                // change the user for the child node after a piece is played
                if (color == 'Y') {
                    tempColor = 'R';
                } else {
                    tempColor = 'Y';
                }
                // call the function so we can explore to maximum depth
                if (depth < maxDepth) {
                    int v = minimax(new Gameboard(game), depth + 1, tempColor);
                    if (v < worstBestResponse) {
                        worstBestResponse = v;
                    }
                }
            }
        }

        if(tie) {
            //if game is a tie, we return 0, to show no favour.
            return 0;
        } else {
            //After determining the value of the opponents best response, we return the negative value of it. That is, what's bad for them is good for us and visa versa.
            return -worstBestResponse;
        }
    }
}

我相信这样的事情更像是你正在寻找的东西。这假设威胁等级是一种启发式方法,用于确定在给定游戏中大约谁赢了。

我已经掌握了该方法可能具有的关于它的根源的任何知识。它应该只适用于任何人和#34;颜色&#34;是。我还清理了你的任意大整数以显示输赢。 MAX_VALUE和MIN_VALUE更加优雅。

无论如何,尝试一下,并以深度为0调用它。如果您有疑问,请告诉我

答案 1 :(得分:0)

如果您的方法不起作用,您可以尝试模仿wikihere上的伪代码的基本结构。在java中我有:

    /**
     * initialize MiniMax(0, player1) where player1 is computer
     * @param deg depth
     * @param player either MAX or MIN
     * @return int {score,column}
     */
    int[] MiniMax(int deg, char player) {

        // list of possible columns to place a checker
        List<int[]> moves = nextMoves();
        int v;
        char prev;

        if (player==player1) prev = player2;
        else prev = player1;

        // IF depth = 0 OR there is a connect 4 OR the board is full (draw) THEN
        //      return your static evaluation (heuristic)
        // if the current position has a connect 4, return -inf or inf
        // depending on if player is MIN or MAX respectively
        if (checkPos(prev) || (deg == this.deg) || moves.isEmpty())
            return new int[] {eval(),bestMove};

        //MAX
        else if (player==player1) {
            v = -inf;
            for (int[] move : moves) {  // move = {row,column}

                board[move[0]][move[1]] = player1; // make move
                int score = MiniMax(deg+1,player2)[0];
                board[move[0]][move[1]] = ' '; // undo move

                if (score>v) {
                    v = score;
                    bestMove = move[1];
                }

            }
            return new int[] {v,bestMove};
        }

        //MIN
        else {
            v = inf;
            for (int[] move : moves) {  // move = {row,column}

                board[move[0]][move[1]] = player2; // make move
                int score = MiniMax(deg+1,player1)[0];
                board[move[0]][move[1]] = ' '; // undo move

                if (v>score) {
                    v = score;
                    bestMove = move[1];
                }
            }
            return new int[] {v,bestMove};
        }
    }

使用字符数组或其他东西而不是class来表示电路板可能很有用。最有效的方法是将电路板表示为long,因为您可以检查是否存在使用4位移位的连接四。这是一些草率的Java,显示上面的东西工作:

import java.util.ArrayList;
import java.util.List;

public class Connect4 {
    static final int WIDTH = 7;
    static final int HEIGHT = 6;
    private static final int inf = 9999999;
    private static final char player1 = 'X';
    private static final char player2 = 'O';
    char[][] board = new char[WIDTH][HEIGHT];
    private int deg;
    int bestMove;


    static char[][] copy(char[][] aArray) {
        char[][] copy = new char[aArray.length][aArray[0].length];
        for (int idy = 0; idy < aArray.length; ++idy) {
            for (int idx = 0; idx < aArray[0].length; ++idx) {
                copy[idy][idx] = aArray[idy][idx];
            }
        }
        return copy;
    }
    void prints() {
        System.out.println();
        for (int i = 0; i < 6; i++) {
            System.out.println("=============================");
            for (int j = 0; j < 7; j++) {
                if (j == (WIDTH - 1)) {
                    if (board[i][j]==' ') {
                        System.out.println("|   |");
                    }
                    else {
                        if(board[i][j]==player1 ) System.out.println("| " +"\u001B[32m"+board[i][j]+"\u001B[0m" + " |");

                        else System.out.println("| " +"\u001B[34m"+board[i][j]+"\u001B[0m" +  " |");
                    }
                }
                else {

                    if (board[i][j]==' ') {
                        System.out.print("|   ");
                    }
                    else {
                        if(board[i][j]==player1 ) System.out.print("| " +"\u001B[32m"+board[i][j]+"\u001B[0m" + " ");

                        else System.out.print("| " +"\u001B[34m"+board[i][j]+"\u001B[0m" + " ");
                    }
                }

            }
        }
        System.out.println("=============================");
    }


    //STATIC EVALUATION
    int eval3(char player) {
        if (checkPos(player)) {
            return inf;
        }

        int count;
        int open;
        int evaluation = 0;

        //evaluation = number of open 3 in rows
        //go through all possible 4in rows and check

        //horz
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < 4; j++) {
                count = 0;
                open = 0;
                if (board[i][j]==player) count++;
                else if(board[i][j]==' ') open++;

                if (board[i][j + 1]==player) count++;
                else if(board[i][j + 1]==' ') open++;

                if (board[i][j + 2]==player) count++;
                else if(board[i][j + 2]==' ') open++;

                if (board[i][j + 3]==player) count++;
                else if(board[i][j + 3]==' ') open++;

                if ((count == 3) && (open == 1)) evaluation++;
            }
        }

        //vert
        for (int j = 0; j < WIDTH; j++) {
            for (int i = 0; i < 3; i++) {
                count = 0;
                open = 0;
                if (board[i][j]==player) count++;
                else if (board[i][j]==' ') open++;

                if (board[i + 1][j]==player) count++;
                else if (board[i+1][j]==' ') open++;

                if (board[i + 2][j]==player) count++;
                else if (board[i + 2][j]==' ') open++;

                if (board[i + 3][j]==player) count++;
                else if (board[i + 3][j]==' ') open++;

                if ((count == 3) && (open == 1)) evaluation++;
            }
        }


        // pos slope diag
        for (int j = 0; j < 4; j++) {
            for (int i = 3; i < HEIGHT; i++) {
                count = 0;
                open = 0;
                if (board[i][j]==player) count++;
                else if (board[i][j]==' ') open++;

                if (board[i - 1][j + 1]==player) count++;
                else if (board[i - 1][j + 1]==' ') open++;

                if (board[i - 2][j + 2]==player) count++;
                else if (board[i - 2][j + 2]==' ') open++;

                if (board[i - 3][j + 3]==player) count++;
                else if (board[i - 3][j + 3]==' ') open++;

                if ((count == 3) && (open == 1)) evaluation++;
            }
        }

        // neg slope diag
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < (3); i++) {
                count = 0;
                open = 0;
                if (board[i][j]==player) count++;
                else if (board[i][j]==' ') open++;

                if (board[i + 1][j + 1]==player) count++;
                else if (board[i + 1][j + 1]==' ') open++;

                if (board[i + 2][j + 2]==player) count++;
                else if (board[i + 2][j + 2]==' ') open++;

                if (board[i + 3][j + 3]==player) count++;
                else if (board[i + 3][j + 3]==' ') open++;

                if ((count == 3) && (open == 1)) evaluation++;

            }
        }
        return evaluation;
    }
    int eval() {return eval3(player1) - eval3(player2);}
    boolean checkPos(char cur) {
        //horz
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < 4; j++) {
                if (    board[i][j]==cur &&
                        board[i][j + 1]==cur &&
                        board[i][j + 2]==cur &&
                        board[i][j + 3]==cur) {
                    return true;
                }
            }
        }


        //vert
        for (int j = 0; j < WIDTH; j++) {
            for (int i = 0; i < 3; i++) {
                if (    board[i][j]==cur &&
                        board[i + 1][j]==cur &&
                        board[i + 2][j]==cur &&
                        board[i + 3][j]==cur) {
                    return true;
                }
            }
        }


        // pos slope diag
        for (int j = 0; j < 4; j++) {
            for (int i = 3; i < HEIGHT; i++) {
                if (    board[i][j]==cur &&
                        board[i - 1][j + 1]==cur &&
                        board[i - 2][j + 2]==cur &&
                        board[i - 3][j + 3]==cur) {
                    return true;
                }

            }
        }


        // neg slope diag
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 3; i++) {
                if (    board[i][j]==cur &&
                        board[i + 1][j + 1]==cur &&
                        board[i + 2][j + 2]==cur &&
                        board[i + 3][j + 3]==cur) {
                    return true;
                }
            }
        }

        return false;
    }
    List<int[]> nextMoves() {
        List<int[]> result = new ArrayList<>();
        for (int j = 0; j < WIDTH; j++) {
            //if column j isnt full then add
            if (board[0][j]==' ') result.add(new int[] {findY(j),j});
        }
        return result;
    }
    int findY(int col) {
        int i = board.length - 1;
        while (i > -1) {
            if (board[i][col]==' ') break;
            i--;
        }
        return i;
    }


    /**
     * @param deg depth
     * @param player either MAX or MIN
     * @return int {score,column}
     */
    int[] MiniMax(int deg, char player) {

        // list of possible columns to place a checker
        List<int[]> moves = nextMoves();
        int v;
        char prev;

        if (player==player1) prev = player2;
        else prev = player1;

        // IF depth = 0 OR there is a connect 4 OR the board is full (draw) THEN
        //      return your static evaluation (heuristic)
        // if the current position has a connect 4, return -inf or inf
        // depending on if player is MIN or MAX respectively
        if (checkPos(prev) || (deg == this.deg) || moves.isEmpty())
            return new int[] {eval(),bestMove};



        //MAX
        else if (player==player1) {
            v = -inf;
            for (int[] move : moves) {  // move = {row,column}

                board[move[0]][move[1]] = player1; // make move
                int score = MiniMax(deg+1,player2)[0];
                board[move[0]][move[1]] = ' '; // undo move

                if (score>v) {
                    v = score;
                    bestMove = move[1];
                }

            }
            return new int[] {v,bestMove};
        }

        //MIN
        else {
            v = inf;
            for (int[] move : moves) {  // move = {row,column}

                board[move[0]][move[1]] = player2; // make move
                int score = MiniMax(deg+1,player1)[0];
                board[move[0]][move[1]] = ' '; // undo move

                if (v>score) {
                    v = score;
                    bestMove = move[1];
                }

            }
            return new int[] {v,bestMove};
        }

    }

    public static void main(String[] args) {
        Connect4 c = new Connect4();
        c.deg = 5;

        char[][] b = {
                {' ',' ',' ',' ',' ',' ',' '},
                {' ',' ',' ',' ',' ',' ',' '},
                {' ',' ',' ',' ',' ',' ',' '},
                {' ',' ',' ',' ',' ',' ',' '},
                {' ','X','X','X',' ',' ',' '},
                {' ','O','X','X','X',' ',' '}
        };

        c.board = copy(b);
        c.prints();
        System.out.println("best value = " + c.MiniMax(0, player1)[1]);

    }
}