【问题标题】:MiniMax algorithm Tic Tac Toe. Something's wrong?MiniMax 算法井字游戏。有什么问题吗?
【发布时间】:2014-08-27 13:28:56
【问题描述】:

我已经为实现 MiniMax 算法的井字游戏 AI 编写了这段代码。 AI 每次都获胜(全深度搜索)。但可能有问题。这是让我怀疑实现正确性的输出:

0 0 0

0 0 0

0 0 0

Who's gonna move first? (1) You : (2) Me?

1

Your move: 

2 2

0 0 0 

0 0 0 

0 0 2 

Score: -1 Point: 0 0

Score: -1 Point: 0 1

Score: -1 Point: 0 2

Score: -1 Point: 1 0

Score: 0 Point: 1 1

Score: 0 Point: 1 2

Score: 0 Point: 2 0

Score: 0 Point: 2 1

0 0 0 

0 1 0 

0 0 2 

Your move: 

0 0

2 0 0 

0 1 0 

0 0 2 

Score: 0 Point: 0 1

Score: 0 Point: 0 2

Score: 0 Point: 1 0

Score: 0 Point: 1 2

Score: 0 Point: 2 0

Score: 0 Point: 2 1

2 1 0 

0 1 0 

0 0 2 

现在这些点上的所有 0 表示如果 AI 轮流并将这些点标记为 1,则 AI 可以在最坏的情况下平局并将这些点标记为 1。(AI 为 1,Player 为 2)。那绝对是错误的。有两点肯定会失败(点 0 2 和点 2 0),所以在这些点上的得分肯定是 -1。但是 AI 采取了第一步并获胜(为什么?)。即使经过数千次随机测试,我也无法击败 AI。

这是完整的代码。如果你能告诉我哪里出了问题,那将非常有帮助。

import java.util.*;

class Point {

int x, y;

public Point(int x, int y) {
    this.x = x;
    this.y = y;
}
}

public class Board {

//Copy constructor
public Board(Board b) {
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            this.board[i][j] = b.board[i][j];
        }
    }
}

public Board() {
}

int[][] board = new int[3][3];

List<Point> availablePoints;

//Get the playable locations available on the board
public List<Point> getAvailableStates() {
    availablePoints = new ArrayList<>();
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (board[i][j] == 0) {
                availablePoints.add(new Point(i, j));
            }
        }
    }
    return availablePoints;
}

public boolean isGameOver() {
    //Game is over is someone has won, or board is full (draw)
    return (hasXWon() || hasOWon() || getAvailableStates().isEmpty());
}

public boolean hasXWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1)
            || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) {
        //System.out.println("X Diagonal Win");
        return true;
    }
    for (int i = 0; i < 3; ++i) {
        if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
                || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
            //System.out.println("X Row or Column win");
            return true;
        }
    }
    return false;
}

public boolean hasOWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2)
            || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) {
        //System.out.println("O Diagonal Win");
        return true;
    }
    for (int i = 0; i < 3; ++i) {
        if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
                || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2)) {
            //System.out.println("O Row or Column win");
            return true;
        }
    }
    return false;
}

public void placeAMove(Point point, int player) {
    board[point.x][point.y] = player;   //player = 1 for X, 2 for O
}

class PointsAndScores {

    int score;
    Point point;

    PointsAndScores(int score, Point point) {
        this.score = score;
        this.point = point;
    }
}

List<PointsAndScores> pointsAndScores = new ArrayList<>();

//The actual MinMax Logic is in this function
public int evaluateBoardPositions(int RecursionTurn) {

    List<Point> availablePoints = getAvailableStates();

    if (hasXWon()) {
        return +1;
    } else if (hasOWon()) {
        return -1;
    } else if (availablePoints.isEmpty()) {
        return 0;
    } else {
        int minOrMax = -999;

        List<Integer> scores = new ArrayList<>();

        for (Point point : availablePoints) {

            Board newBoard = new Board(this);
            if (RecursionTurn == 1) {
                newBoard.placeAMove(point, 1);
                scores.add(newBoard.evaluateBoardPositions(2));
                Collections.sort(scores, Collections.reverseOrder());
                minOrMax = scores.get(0);
            }
            if (RecursionTurn == 2) {
                newBoard.placeAMove(point, 2);
                scores.add(newBoard.evaluateBoardPositions(1));
                Collections.sort(scores);
                minOrMax = scores.get(0);
            }
            pointsAndScores.add(new PointsAndScores(minOrMax, point));
        }
        return minOrMax;
    }
}

//Return the move with the highest score i.e. +1 for our Bot.
public Point returnBestMove() {
    int MAX = -100000;
    int best = -1;

    for (int i = 0; i < pointsAndScores.size(); ++i) {
        if (MAX < pointsAndScores.get(i).score) {
            MAX = pointsAndScores.get(i).score;
            best = i;
        }
    }

    return pointsAndScores.get(best).point;
}
Scanner scan = new Scanner(System.in);

void takeHumanInput() {
    System.out.println("Your move: ");
    int x = scan.nextInt();
    int y = scan.nextInt();
    Point point = new Point(x, y);
    placeAMove(point, 2);
}

public void displayBoard() {
    System.out.println();

    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            System.out.print(board[i][j] + " ");
        }
        System.out.println();

    }
}

void placeFirstMove() {
    Random rand = new Random();
    Point p = new Point(rand.nextInt(3), rand.nextInt(3));
    placeAMove(p, 1);
}

public static void main(String[] args) {

    Board b = new Board();
    b.displayBoard();

    System.out.println("Who's gonna move first? (1) You : (2) Me?");
    Scanner scan = new Scanner(System.in);
    int choice = scan.nextInt();

    if (choice == 2) {
        b.placeFirstMove();
        b.displayBoard();
    }
    while (!b.isGameOver()) {
        b.takeHumanInput();
        if (b.isGameOver()) {
            break;
        }
        b.displayBoard();

        b.pointsAndScores.clear();
        b.evaluateBoardPositions(1);
        Point p = b.returnBestMove();

        for (PointsAndScores pas : b.pointsAndScores) {
            System.out.println("Score: " + pas.score + " Point: " + pas.point.x + " " + pas.point.y);
        }
        b.placeAMove(p, 1);
        b.displayBoard();
    }
    if (b.hasXWon()) {
        System.out.println("Unfortunately, you lost!");
    } else if (b.hasOWon()) {
        System.out.println("Never gets displayed. Computer Always wins or draws");
    } else {
        System.out.println("It's a draw!");
    }
}
}

【问题讨论】:

  • 我已经这样做了:else if (hasOWon()) { return -1; }
  • 对不起,你是对的。调试纠结的代码不是很容易>.pointsAndScores.add(new PointsAndScores(minOrMax, point)); 你确定你应该在这里添加到目前为止可用的最小/最大移动,而不是特定移动的分数吗?
  • 我将此列表仅用于 MAX 必须采取的最后一步。此列表将所有分数和计算的分数相加。其他递归列表(此列表在递归期间重建)及其元素被忽略(我知道这是一个非常糟糕的设计)。这就是为什么我需要在计算机每次采取下一步行动之前清除它。
  • 是的,这不应该影响程序做出的decision,但它确实会导致debug output不正确。从而使调试更加困难。

标签: java minimax


【解决方案1】:
public int evaluateBoardPositions(int RecursionTurn, int bestPoint) {

    List<Point> availablePoints = getAvailableStates();

    int minOrMax = -999;
    if (hasXWon()) {
        return +1;
    } else if (hasOWon()) {
        return -1;
    } else if (availablePoints.isEmpty()) {
        return 0;
    }
    else {
        for (Point point : availablePoints) {

            Board newBoard = new Board(this);
            if (RecursionTurn == 1) {
                newBoard.placeAMove(point, 1);
                bestPoint = newBoard.evaluateBoardPositions(2,bestPoint);
                pointsAndScores.add(new PointsAndScores(bestPoint, point));
                Collections.sort(pointsAndScores);
                minOrMax = pointsAndScores.get(pointsAndScores.size()-1).score;
            }
            else {
                newBoard.placeAMove(point, 2);
                bestPoint = newBoard.evaluateBoardPositions(1,bestPoint);
                pointsAndScores.add(new PointsAndScores(bestPoint, point));
                Collections.sort(pointsAndScores);
                minOrMax = pointsAndScores.get(0).score;
            }
        }
        return minOrMax;
    }
}

【讨论】:

  • 请同时添加解释,不要只是粘贴一些代码,因为它并不总是清楚你在做什么
猜你喜欢
  • 2015-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多