使用评估函数返回的值从 minimax 中找到合适的移动
Finding a suitable move from minimax using the values returned from evaluation function
所以,我正在尝试为一个简单的游戏实现 minimax
算法,该游戏有 2 个玩家,每个玩家有 2 个皇后。所以在 7X7 的棋盘上总共有 4 个皇后。所以在每一轮,玩家将他的两个皇后移动到一个新位置。
我尝试通过递归找到 min
和 max
,minimax
函数如下所示。基本情况应该是 return 一个整数,它是评估函数 return 的分数。但是遍历到叶节点后,如何找到min
和max
呢?
这个函数应该可以return queen1 和queen2 的最佳着法。但我不明白,至于如何从叶节点值中找到最小值和最大值。我如何传播价值观。我只是不能 understand/visualize 这个。
我从你的问题中得到的印象是,你的大部分困惑在于,函数 return 应该是什么?它应该 return 得分还是移动?一般来说,你实际上应该把这个东西分成两个独立的功能;
一个minimax()
函数,应该和你现在看到的差不多至少接近罚款)。这应该只有 return 一个 integer/float/whatever,一个节点的值(如果你已经足够深,它被定义为评估函数,或者所有 [=74] 的 max/min =]ren(最大值或最小值取决于要移动的玩家)。
类似于 choose_move()
函数,应该 return 走棋。它应该通过为所有 children 调用 minimax()
,然后 returning 导致具有最大值的 child 的移动来做到这一点(建议打破平局随机)。
注意: 您的代码中似乎也有一些错误,似乎 return 太频繁了。例如,在最大化玩家的情况下,当您第一次看到 score > best_val
时,您已经 return,而您也应该继续遍历所有其他动作以找出是否有任何动作可能会有更高的分数。
最小化播放器的代码应该更多''symmetric''和最大化播放器的代码,现在看起来太不一样了。
编辑:要解决分数 return 编得太快的问题,这一行:
return best_move_q_1, best_move_q_2, score
应该简单地移到执行所有可能操作的循环之外。这个想法是,遍历所有动作,评估它们(通过递归 minimax
调用),然后 return 动作和与最佳动作相关的分数。这意味着它必须在动作循环之外,你不能已经 return 而仍然在这些循环内,因为那样你还没有完成所有动作的循环并且可能错过了更好的选择。
在这种情况下,执行此操作的方法是简单地将特定代码行向左移动 4 个选项卡。它应该直接在 for move_q_1 in moves_1:
行下方(在相同的缩进级别),因为这是所有移动循环的开始。
然后,该行应该另外更改为return best_val
(所有children中最好的分数),而不是score
(评价最后 child).
之后,not maximizing_player
案例的代码应更改为与上述其他案例的代码更加相似。
然后,我又注意到一件事;靠近顶部,您决定评估是否 depth == 0
(或者游戏状态是否为终端)。但是,在递归调用中,您总是会增加传递的深度级别。这看起来很奇怪(除非你在第一次调用时传入负深度?)。您可能想要执行以下操作之一:
在第一次调用 minimax 时,传入您要搜索的最大深度(例如,3 或 5 或其他)。然后,当您再次递归调用 minimax 时,总是 递减 它,而不是递增(以确保它最终到达它将计算的 depth=0
点)。
不要在 depth == 0
时进行评估,而是在 depth == max_depth
时进行评估,其中 max_depth
又是一个常量,如 3 或 5 或其他。然后,您对 minimax 的初始调用应该有 depth=0
.
我没有详细检查是否还有其他错误,所以如果这还不是全部,请随时告诉我(或者尝试将您的代码与其他地方的算法伪代码进行比较,看看在哪里区别是,如果你能理解的话)。
所以,我正在尝试为一个简单的游戏实现 minimax
算法,该游戏有 2 个玩家,每个玩家有 2 个皇后。所以在 7X7 的棋盘上总共有 4 个皇后。所以在每一轮,玩家将他的两个皇后移动到一个新位置。
我尝试通过递归找到 min
和 max
,minimax
函数如下所示。基本情况应该是 return 一个整数,它是评估函数 return 的分数。但是遍历到叶节点后,如何找到min
和max
呢?
这个函数应该可以return queen1 和queen2 的最佳着法。但我不明白,至于如何从叶节点值中找到最小值和最大值。我如何传播价值观。我只是不能 understand/visualize 这个。
我从你的问题中得到的印象是,你的大部分困惑在于,函数 return 应该是什么?它应该 return 得分还是移动?一般来说,你实际上应该把这个东西分成两个独立的功能;
一个
minimax()
函数,应该和你现在看到的差不多至少接近罚款)。这应该只有 return 一个 integer/float/whatever,一个节点的值(如果你已经足够深,它被定义为评估函数,或者所有 [=74] 的 max/min =]ren(最大值或最小值取决于要移动的玩家)。类似于
choose_move()
函数,应该 return 走棋。它应该通过为所有 children 调用minimax()
,然后 returning 导致具有最大值的 child 的移动来做到这一点(建议打破平局随机)。
注意: 您的代码中似乎也有一些错误,似乎 return 太频繁了。例如,在最大化玩家的情况下,当您第一次看到 score > best_val
时,您已经 return,而您也应该继续遍历所有其他动作以找出是否有任何动作可能会有更高的分数。
最小化播放器的代码应该更多''symmetric''和最大化播放器的代码,现在看起来太不一样了。
编辑:要解决分数 return 编得太快的问题,这一行:
return best_move_q_1, best_move_q_2, score
应该简单地移到执行所有可能操作的循环之外。这个想法是,遍历所有动作,评估它们(通过递归 minimax
调用),然后 return 动作和与最佳动作相关的分数。这意味着它必须在动作循环之外,你不能已经 return 而仍然在这些循环内,因为那样你还没有完成所有动作的循环并且可能错过了更好的选择。
在这种情况下,执行此操作的方法是简单地将特定代码行向左移动 4 个选项卡。它应该直接在 for move_q_1 in moves_1:
行下方(在相同的缩进级别),因为这是所有移动循环的开始。
然后,该行应该另外更改为return best_val
(所有children中最好的分数),而不是score
(评价最后 child).
之后,not maximizing_player
案例的代码应更改为与上述其他案例的代码更加相似。
然后,我又注意到一件事;靠近顶部,您决定评估是否 depth == 0
(或者游戏状态是否为终端)。但是,在递归调用中,您总是会增加传递的深度级别。这看起来很奇怪(除非你在第一次调用时传入负深度?)。您可能想要执行以下操作之一:
在第一次调用 minimax 时,传入您要搜索的最大深度(例如,3 或 5 或其他)。然后,当您再次递归调用 minimax 时,总是 递减 它,而不是递增(以确保它最终到达它将计算的
depth=0
点)。不要在
depth == 0
时进行评估,而是在depth == max_depth
时进行评估,其中max_depth
又是一个常量,如 3 或 5 或其他。然后,您对 minimax 的初始调用应该有depth=0
.
我没有详细检查是否还有其他错误,所以如果这还不是全部,请随时告诉我(或者尝试将您的代码与其他地方的算法伪代码进行比较,看看在哪里区别是,如果你能理解的话)。