我已经尝试修改我的算法以更好地工作,但我还没有取得任何结果。我的问题是,在第一次移动后,如果我有,例如:
XX.
OO.
...
计算机,而不是选择0 2,选择例如1 2,有时候会尝试去寻找能够做到的位置。
我的代码:
#include "game.hpp"
pair<int,int> winner;
int m = INT_MAX;
pair<int,int> game::minimax(State ini) {
int v = maxValue(ini);
cout << v << endl;
return winner;
}
int game::maxValue(State u){
int check = u.getUtility();
if( check % 700 == 0 ) {
if( u.moves < m ) {
winner = u.move;
m = u.moves;
}
return check;
}
int v = INT_MIN;
u.makeDescendents();
while( !u.ls.empty() ) {
v = max(v,minValue(u.ls.front()));
u.ls.pop_front();
}
return v;
}
int game::minValue(State u) {
int check = u.getUtility();
if( check % 700 == 0 )
return check;
int v = INT_MAX;
u.makeDescendents();
while( !u.ls.empty() ) {
v = min(v,maxValue(u.ls.front()));
u.ls.pop_front();
}
return v;
}
因为你可以帮助我更好地表达一些变量的含义:
获胜者:是计算机将移动的位置
u.moves:是搜索树上的深度,对于root是0
m:应该保存较少深度的状态解决方案,因此过滤器解决方案和计算机必须更加接近解决方案。
检查:此时保存实用程序值,知道是否为终端状态
胜利的效用为700,领带为0,失败为-700
u.ls:儿童状态列表
其他一些事情,我认为使用m和胜利者全球并在极小极大情况下返回全局是一个糟糕的解决方案,你能看到一些方法来改善这个吗?
非常感谢。
答案 0 :(得分:1)
首先,如果状态不是终端,u.getUtility()
会返回什么?如果它返回0,那么0 % 700 == 0
为真,那么它只是找到它展开的第一步并选择它。由于我无法看到u.makeDescendents()
算法,因此我无法排除这一点。
如果情况并非如此,那么几乎可以肯定你的u.getUtility()
函数假设它只是被称为同一个最大玩家。即如果X获胜则返回700,如果X输了则返回-700。如果您通过相同的极小极大值运行双方,那么当您将O评估为最大值时,它仍在尝试为X找到胜利,因为这是唯一一次将评估视为一场胜利。
如果是这种情况,那么修复很简单,确定哪个玩家从状态转向并返回赢/输评估,就好像是那个玩家一样(这通常是TicTacToe的损失,因为你不能做出一个让你失去游戏的举动,你只能通过采取行动而获胜并且前一位玩家做出最后的动作。)
如果这些建议都没有解决问题,那么调试minimax问题的典型方法是一次一步地深入游戏树,探索返回已知无效评估的路径,直到找到关键点为止生成不正确的值。然后你必须检查它以找出原因。这对于像tic tac toe这样的小游戏来说是微不足道的,因为它只有9级深度并且你可以获得完美的极小极大值,但对于任何非平凡的游戏,你通常必须查看你的评估函数来确定差异发生的位置