我正在用Java针对AI电脑玩家构建tic_tac_toe(棋盘)游戏,我为电脑编写了MiniMax算法。 木板的宽度可以像 3 * 3 或 4 * 4。 和
当我在 3 * 3 上运行游戏时,计算机播放器将开始工作 很好,但是当我尝试 4 * 4板子时,计算机播放器没有 工作只需要花费很多时间,然后什么都没有 等到我停止游戏。 这是发生的屏幕截图。
这是我编写的MiniMax算法:
private Pair<Integer, State> maxMove(State b) {
if(b.isWin('X') || b.isFinished())
return new Pair<>(b.eval('X'), b);
else{
int max = -222, temp;
Pair<Integer, State> p = null;
for (State s : b.allNextMoves('O')){
temp = minMove(s).getKey();
if (temp > max){
max = temp;
p = new Pair<>(s.eval('X'), s);
}
}
return p;
}
}
private Pair<Integer, State> minMove(State b) {
if(b.isWin('O') || b.isFinished())
return new Pair<>(b.eval('O'), b);
else{
int min = 222, temp;
Pair<Integer, State> p = null;
for (State s : b.allNextMoves('X')){
temp = maxMove(s).getKey();
if (temp < min){
min = temp;
p = new Pair<>(s.eval('O'), s);
}
}
return p;
}
}
eval函数用于评估网格,我只是将其作为样本,这是func:
public int eval(char player) {
if (isWin(player))
return -1;
else
return 0;
}
有人知道为什么会这样吗?
allNextMoves(char c)
函数将拿起这个棋盘,并尝试通过找到棋盘中的第一个空字符并根据玩家的回合放置“ X”或“ O”来查找该棋盘的所有可能动作,并返回新板列表,这是代码。
public List<State> allNextMoves(char player) {
List<State> nextBoards = new LinkedList<>();
for (int i = 0; i < width; i++) {
for (int j = 0; j < width; j++) {
if (board[i][j] == ' ') {
State nextBoard = new State(this);
nextBoard.play(i, j, player);
nextBoards.add(nextBoard);
}
}
}
return nextBoards;
}
答案 0 :(得分:3)
minimax算法不响应的原因是,使用4x4网格时,要访问的板数要大得多。
首先,我看到您的算法将继续搜索,直到赢得或平局,这意味着很多搜索路径将完全填满整个棋盘。第一步后,左转15圈,每转分别有15、14、13 ... 1个可供选择的替代动作。所以有接近15个!董事会要访问的国家。少了一点,因为会发现(非强制)获胜,但是仍然是15!是对大小的一个很好的粗略估计。
在一个3x3的板上,这个数字只有8个!
比较两个数字:
8! = 40 230
15! = 1 307 674 368 000
因此,在4x4面板中进行搜索所需的时间比在3x3面板中进行搜索的时间长3000万倍。
可以采取多种措施,并且可以将它们组合在一起。这不是完整的列表,而是按此顺序列出的我将要处理的事情的列表:
当搜索深度太大时,您需要停止搜索。有几种方法可以决定何时停止:
当您限制搜索时,您需要一个评估函数,该函数将给出状态值而无需进行更深入的搜索。这将是一些启发式的价值。例如,它可以计算玩家仍然可以赢得的线数(如果对手不能很好地打),并从对手的角度将其抵消为相同的数字。
可以通过不同的移动路径来达到相同的板状态。例如,如果两个玩家将第一步和第二步交换,您将进入相同的棋盘状态。
此外,几个状态通过沿X,Y或对角线轴进行镜像而彼此映射。
通过维护以前评估状态的哈希表(该哈希表还管理镜像方面),可以避免进行本质上是重复的搜索。
由alpha-beta算法完成的修剪不会影响结果。其结果与minimax算法相同。
在极端情况下,当前的局面可能距离获胜者只有一步之遥,但是如果考虑到最后一步,则浪费大量时间寻找其他步伐。因此,如果您可以按照先完成最有前途的举动的方式对这些举动进行排序,则可以节省时间:alpha beta修剪将更加有效。
您可以根据移动是否在被“很多”对手棋子占据的线上进行排名,或者在没有区别的情况下,首先处理中心和角点移动,因为它们可以提供比边界移动更多的解决方案
如果经过一定举动后您发现回复是挽救生命,或是迈向强制胜利的关键一步,那么当替代初始举动而不是最初举动时,首先尝试相同的回复可能会有所回报玩过。