我对Negamax算法以及如何在实际案例中应用它感到有点困惑。在网上我找到了以下C / C ++代码(参考:https://chessprogramming.wikispaces.com/Unmake+Move)
int negaMax( int depth ) {
if ( depth == 0 ) return evaluate();
int max = -oo;
generateMoves(...);
while ( m = getNextMove(...) ) {
makeMove(m);
score = -negaMax( depth - 1 );
unmakeMove(m);
if( score > max )
max = score;
}
return max;
}
据我所知,每次调用makeMove(m)
和unmakeMove(m)
时,“board”实例都会更改,但似乎没有创建任何板的副本。
[1]
我对这个概念是对的还是我错过了什么?
现在,我发现了一个Negamax python实现(参考:http://blogs.skicelab.com/maurizio/connect-four.html)
def negamax(board, depth):
if check_end(board) is not None:
return endscore(board)
if depth <= 0:
return [], evaluate(board)
bestmove = []
bestscore = -INF
for m in board.moves():
nextmoves, score = negamax(board.move(m), depth-1)
score = -score
if not bestmove or score >= bestscore:
bestscore = score
bestmove = [m] + nextmoves
return bestmove, bestscore
在第二种情况下,我认为board.move(m)
调用返回副本(因此是一个新的板对象实例)。这就是为什么Negamax函数需要2个参数而不是1个参数。
[2]
我又回来了吗?
[3]
如果[1]
和[2]
都正确,哪种方式通常更快?如果董事会表示非常简单(我假设Board
类作为数组包装器)我想首选副本,但我会选择make / unmake。
提前致谢!
***************编辑***************
[4]
在make / unmake解决方案中
makeMove(m);
score = -negaMax( depth - 1 );
unmakeLastMove();
的行为与
不同makeMove(m);
score = -negaMax( depth - 1 );
unmakeMove(m);
码?
由于我的棋盘类存储了移动列表,我认为unmakeLastMove()
和unmakeMove(m)
一样有用。但这不是一个好主意,对吗?
答案 0 :(得分:1)
这取决于游戏,你在棋盘上存储的细节等等。
基本上,真正的答案是:实施两者并分析解决方案。
如果您的电路板附加了额外的信息,如果您的评分不是微不足道的,并且您携带一些预先计算的值,如果移动具有复杂的规则并且您的撤消信息与您的撤消信息大致相同,那么Make / Unmake可能会变得复杂董事会本身等。
如果某种语言鼓励不可变数据共享,克隆该板也可能更简单,因为您不会复制所有内容。克隆不会保留您的移动历史记录,但如果您感兴趣,则必须将其保留在一边。
对于不同的情况,两种方式都有不同的作用只需考虑每种方式所暗示的实施方式和/或比较两种结果。