我尝试将minimax算法实现到我的连接四游戏中。 我完成了评估功能,并完成了算法功能。
我无法找到“最后”问题的解决方案。这是我的职能:
void minimax(field f){
int i;
field c;
convert_1D_to_2D(f, c);
for(i=0;i<COLS;i++) {
if(can_throw(c, i) == 0) {
throw(f, i);
convert_1D_to_2D(f, c);
if((is_winner(c) == 0) && (is_board_full(f) == 0)) { //no winner, board not full
minimax(f);
}
else if(is_winner(c) == 1) { //there is a winner
evaluate_turn(f);
//compare evaluation
undo_turn(f);
}
else if(is_winner(c) == 0 && (is_board_full(f) == 1)) { //no winner, board full
evaluate_turn(f);
//compare evaluation
undo_turn(f);
}
}
}
该字段是一个f [COLS * ROWS + 1]的数组,其中f [0]是深度,其他元素保存在哪些列中抛出。 “c”-board代表“图形”棋盘,免费为0,玩家1为1,玩家2为2。
static int evaluate_turn(field f) {
field c;
convert_1D_to_2D(f, c);
if (((f[0] % 2) == 1) && (current_player == 1) && (is_winner(c) == 1) ) { //player 1 won, max for him || +1
return 1;
}
else if (((f[0] % 2) == 2) && (current_player == 2) && (is_winner(c) == 1) ) { //player 2 won, max for him || +1
return 1;
}
if (((f[0] % 2) == 1) && (current_player == 2) && (is_winner(c) == 1) ) { //player 2 won, counting for 1 || -1
return -1;
}
else if (((f[0] % 2) == 2) && (current_player == 1) && (is_winner(c) == 1) ) { //player 1 won, counting for 2 || -1
return -1;
}
else if ((is_board_full(f) == 1) && (is_winner(c) == 0)) { //draw || 0
return 0;
}
所以我的问题是,我无法想到一个干净的解决方案来比较评估的自下而上。我真的认为,我不需要引入新的数据结构(这会变得太大)。这就像解决方案就在我面前,但我无法抓住它。
是否可以仅仅比较递归的“返回”的评估?如果是,怎么样?
或者我真的需要介绍一些更复杂的新东西吗?或许我完全错过了什么?
谢谢!
答案 0 :(得分:0)
或者我真的需要介绍一些更复杂的新东西吗?或者可能 我完全错过了什么?
不幸的是答案是后者。 Minimax不是空函数。它返回它表示的节点的值。这就是比较评估的方式。你也错过了另一个基本概念。您的功能仅将终端节点视为赢得游戏或电路板已满的终端节点。虽然这在技术上是正确的,但没有真正的极小极大功能以这种方式工作。节点的数量大约是7 ^ 48,所以你的功能在现代电脑上终止需要十年以上。现实世界的minimax函数所做的是为搜索设置最大深度(除非你添加树修剪,期望这是5或6),并认为该深度的所有节点都是终端并使用启发式评估它们(不精确的猜测) )evalation功能。在连接四中,这可以基于诸如行中三个的数字。你犯的另一个错误是如果你知道有胜利者就调用你的eval函数。如果您知道哪个玩家赢了而不是直接返回正确的值,则无需调用昂贵的eval函数。你也无法像你一样对最小值和最大值的函数进行流线化。您必须为min和max创建单独的函数,或使用negamax变体。
我建议:您似乎并不真正了解算法应该如何实施。阅读minimax和negamax伪代码。