【发布时间】:2018-02-22 19:19:01
【问题描述】:
我为井字游戏制作了一个带有 alpha beta 修剪的 minimax 算法。人工智能对于 3x3 板按预期工作,但它不适用于 4x4 板。我设法修复了算法,以便它在 4x4 棋盘上选择最佳移动,但现在它不适用于 3x3,而且我无法让 minimax 方法同时适用于 3x3 和 4x4 棋盘。我想要一些帮助来理解为什么我必须根据电路板大小改变评估方法的处理方式。问题似乎源于从评估方法评估分数时。当使用 3x3 评估分数时,它必须运行评估方法,然后返回 10,如果 A.I.获胜,如果对手获胜,则为 -10,或者在 minimax 方法顶部的完整棋盘中为 0。然后,如有必要,它会继续算法的其余部分。这是代码:
int score = evaluate(board);
if (score == 10) {
return score;
}
if (score == -10) {
return score;
}
if (hasCellsLeft(board) == false) {
return 0;
}
为了让算法在 4x4 板上正常工作,评估方法嵌套在 if 语句中。如果深度等于 3,则返回分数:
if (depth == 3) {
return evaluate(board);
}
下面是 minimax 方法的其余部分:
if (isMax) {
int best = MIN;
ArrayList<Integer> cells = new ArrayList<>();
for (int j=0; j<board.length; j++) {
if (board[j].getToken() == Token.EMPTY) {
cells.add(j);
}
}
//cells is a list of empty cells in the board array
for (int i=0; i<cells.size(); i++) {
if (board[cells.get(i)].getToken() == Token.EMPTY) {
board[cells.get(i)].setToken(playerToken);
int val = alphaBeta(board, depth+1, nodeIndex*2+i,false, alpha, beta);
best = Math.max(best, val);
alpha = Math.max(alpha, best);
board[cells.get(i)].resetMarker();
}
if (beta <= alpha) {
break;
}
}
return best;
}
else {
int best = MAX;
for (int i=0; i<board.length; i++) {
if (board[i].getToken() == Token.EMPTY) {
board[i].setToken(opponentToken);
int val = alphaBeta(board,depth+1, nodeIndex*2+i, true, alpha, beta);
best = Math.min(best, val);
beta = Math.min(beta, best);
board[i].resetMarker();
}
if (beta <= alpha) {
break;
}
}
return best;
}
此方法调用极小极大算法并检索最佳可能移动的索引:
public int findBestMove(Cell[] board) {
int bestValue = -1000;
int bestMove = -1;
for (int i=0; i<board.length; i++) {
if (board[i].getToken() == Token.EMPTY) {
board[i].setToken(playerToken);
int moveValue = alphaBeta(board, 0, 0, false, -1000, 1000);
board[i].resetMarker();
if (moveValue > bestValue) {
bestMove = i;
bestValue = moveValue;
}
}
}
return bestMove;
}
这是评估方法:
public int evaluate(Cell[] board) {
if (endStates.checkWinByRow(board, playerToken) || endStates.checkWinByColumn(board, playerToken) || endStates.checkWinByDiagonal(board, playerToken)) {
return 10;
}
else if (endStates.checkWinByRow(board, opponentToken) || endStates.checkWinByColumn(board, opponentToken) || endStates.checkWinByDiagonal(board, opponentToken)) {
return -10;
}
return 0;
}
如果板数组中有未占用的单元格,则返回真/假的方法:
public boolean hasCellsLeft(Cell[] board) {
for (int i=0; i<9; i++) {
if(board[i].getToken() == Token.EMPTY) {
return true;
}
}
return false;
}
【问题讨论】:
-
您的问题到底是什么?你提出了需求、代码和一些调试见解(顺便说一句:一件好事,大多数人不这样做)——但现在呢?您到底希望我们做什么?
-
和无关的:我建议大幅打破最小最大方法。将每个部分放入自己的方法中 - 很难掌握一个有这么多行并做了这么多不同事情的方法!
-
感谢您的建议。我无法弄清楚它为什么会这样。无论电路板大小如何,我都希望它能够工作。相反,我必须在它们之间进行选择,并且无法理解为什么我需要重写算法如何处理评估方法的输出。我认为另一双眼睛会有更好的洞察力。
标签: java algorithm tic-tac-toe minimax alpha-beta-pruning