int minmax(Board game, int depth) { if (game.IsFinished() || depth < 0) return game.Score(game.Turn); int alpha = int.MinValue + 1; foreach (Point move in game.Generate_Moves()) { Board currentBoard = game; currentBoard.Do_Move(move); alpha = max(alpha, -minmax(currentBoard, depth-1)); currentBoard.Undo_Move(move); } return alpha; }
这个小函数可以告诉我游戏是赢、输还是平局,但如何得到能让我获胜的移动呢?我的Point类是一个包含两个坐标X和Y的简单类,我希望得到的答案是一个点,这样我就可以后续使用game.Do_Move(myPoint)
来执行移动。
如果有些函数不是很明显:
game.IsFinished()
– 如果是赢/输/平局则返回true,否则返回false
game.Score(turn)
– 如果下一个移动的玩家是输/平/赢,则返回-1/0/1
game.Generate_Moves()
– 返回一个包含可用移动的列表
game.Do_Move()
– 一个应用移动到游戏中的void函数
game.Undo_Move()
– 顾名思义,撤销移动
回答:
如果minimax函数在游戏树的根节点上被调用时能够返回选择的移动和分数,对于游戏树的其他节点,函数只需要返回分数就足够了。因此,通常的做法是实现两个略有不同的minimax函数 – 参见此NegaMax框架描述中的注释#2。
应用到你的minimax接口上,你将会有以下额外的函数:
int minimaxWithMove(Board game, int depth, Point& choosen){ assert (!game.IsFinished() && depth > 0); // 在根节点上不可能 int alpha = int.MinValue + 1; foreach (Point move in game.Generate_Moves()) { Board currentBoard = game; currentBoard.Do_Move(move); int score = -minmax(currentBoard, depth-1); if (score > alpha) { alpha = score; choosen = move; } } return alpha;}
请注意,我已经移除了对Undo_Move
的调用,因为在每次迭代中你都创建了game
的副本,所以不需要它。