所以,我正在尝试为一个简单的游戏实现minimax
算法,该游戏有2个玩家,每个玩家有2个皇后。所以在7X7板上共有4个皇后。因此,在每个回合中,玩家都将他的两个王后移动到一个新的位置。
我尝试通过递归min
函数找到max
和minimax
,如下所示。基本情况应该返回一个整数,这是评估函数返回的分数。但是,在遍历叶节点后,如何找到min
和max
?
这个函数应该能够为queen1和queen2返回最佳移动。但我不明白,如何从叶节点值中找到最小值和最大值。如何传播值。我无法理解/想象这一点。
答案 0 :(得分:1)
我从你的问题中得到的印象是,你的大部分困惑都在于,该函数应该返回什么?它应该返回分数还是移动?通常,您应该将这个东西拆分为两个独立的函数;
一个minimax()
函数,它应该看起来像你到目前为止看起来一样(我没有详细检查正确性,也许没有什么错误,但总的来说它似乎接近于罚款最小)。这应该只返回一个整数/ float / whatever,一个节点的值(如果你已经足够深,则定义为评估函数,或者所有子节点的最大值/最小值(最大值或最小值取决于哪个球员要移动。)
像choose_move()
这样的函数,它应该返回一个游戏。它应该通过为所有孩子调用minimax()
,然后返回导致具有最大价值的孩子的移动(建议随机打破关系)来做到这一点。
注意:您的代码中似乎也有一些错误,似乎经常返回。例如,在最大化玩家的情况下,当你第一次看到score > best_val
时你已经返回,而你应该继续循环所有其他动作,以弄清楚他们中的任何一个是否有一个偶数得分越高。
最小化播放器的情况代码应该更加“对称”''使用最大化播放器的代码,它现在看起来太不同了。
编辑:要解决分数过快返回的问题,请注意以下几行:
return best_move_q_1, best_move_q_2, score
应该简单地移动到循环之外,通过所有可能的操作。这个想法是,遍历所有操作,评估所有操作(通过递归minimax
调用),然后返回与最佳移动相关联的移动和分数。这意味着它必须在循环之外通过动作,你仍然不能在这些循环中返回,因为那时你还没有完成所有动作的循环,可能错过了更好的替代方案。
在这种情况下执行此操作的方法是简单地将特定的代码行4个选项卡移动到左侧。它应该与for move_q_1 in moves_1:
行直接在(在相同的缩进级别下),因为它是所有移动循环的开始。
然后,该行应另外更改为返回best_val
(所有孩子中的最佳分数),而不是score
(对最后一个孩子的评价)。
之后,not maximizing_player
案例的代码应该更改为与上面其他案例的代码更相似。
然后,我注意到了另一件事;接近顶部,您决定评估depth == 0
(或游戏状态是否为终端)。但是,在递归调用中,您始终会增加传递的深度级别。这看起来很奇怪(除非你在第一次通话中传递负面深度?)。您可能希望改为执行以下操作之一:
在第一次调用minimax时,传入您要搜索的最大深度(例如,3或5或其他)。然后,当你再次递归调用minimax时,总是递减,而不是递增(以确保它最终到达它将评估的depth=0
点。
不是评估depth == 0
的时间,而是在depth == max_depth
时进行评估,其中max_depth
再次为常数,如3或5或其他。然后,您对minimax的初始调用应为depth=0
。
我没有详细检查是否有其他错误,所以如果不是全部(或者尝试将您的代码与其他地方的算法的伪代码进行比较,请随时告诉我),并查看差异是,如果你能理解它们。)