我正在尝试编写一个程序来对井字棋进行强化学习。我希望引擎认识到,如果您反射棋盘或旋转它,您会得到完全相同的游戏,因此这些棋盘应该被视为彼此相同。
目前我有一本字典,代表我当前对每个棋盘的估计估值游戏中的棋盘,每次游戏结束时,该游戏期间发生的所有棋盘位置的估值都会根据它们是否导致胜利或导致失败进行更新。
我想要一种方法来实现这一点所有的旋转和反射都会组合在一起,这样一个更新也会更新所有其他的。
我当前的策略是生成一块板的所有可能的旋转和反射,将它们放在一组中,然后把这个集合变成一个冻结集合,这样我就可以用它作为字典中的键。我认为这应该可行,但是使用冻结集感觉非常危险。
我很好奇还有什么其他方法可以解决这个问题。而且,如果我对冰冻套装的感觉是“狡猾的”,有任何优点,或者只是一些愚蠢的心理障碍,我应该克服。每当我使用某种不为人所知的 python 结构时,我经常有这种感觉。
在 Python 中表示井字棋的等价类的想法不错,冻结集合是一个合理的选择。以下是对的方法的改进以及一些替代方案:
1. 使用冻结集合(推荐)
的直觉是正确的,冻结集合非常适合这个任务。它们是不可变的,这意味着一旦创建就不能更改,这使得它们可以安全地用作字典键。以下是它的工作原理:
import numpy as np
from functools import reduce
def generate_equivalences(board):
"""生成棋盘的所有旋转和反射。"""
base_board = np.array(board)
equivalences = [base_board]
for _ in range(3):
base_board = np.rot90(base_board)
equivalences.append(base_board)
equivalences.append(np.fliplr(base_board)) # 水平翻转
equivalences.append(np.flipud(base_board)) # 垂直翻转
return [frozenset(board.flatten()) for board in equivalences]
# 示例用法
board = [
['X', 'O', ' '],
[' ', 'X', ' '],
[' ', ' ', 'O']
]
equivalence_class = generate_equivalences(board)
# 使用冻结集合作为字典键
value_function = {}
value_function[equivalence_class[0]] = 0.5 # 示例值
# 检查等价类是否在字典中
if equivalence_class[1] in value_function:
print("找到等价棋盘!")
为什么冻结集合适合此任务?
- 不可变性: 冻结集合是不可变的,因此可以作为字典键使用。
- 散列: 冻结集合是可散列的,因此可以有效地在字典中查找。
- 清晰度: 冻结集合清楚地表明,将一组唯一元素视为一个组,并且该组的顺序无关紧要。
2. 整数表示
另一种方法是将每个棋盘表示为一个唯一的整数,该整数考虑了其对称性。这可以通过为每个单元格分配一个三进制(0、1、2)值并将棋盘视为三进制数来实现。然后,可以计算所有等价棋盘的整数表示形式,并使用最小的整数作为规范表示形式。这种方法效率很高,但不如冻结集合直观。
3. 自定义类
可以创建一个自定义类来表示棋盘等价类。此类可以存储棋盘的规范表示形式(例如,规范方向的二维数组)并覆盖
__hash__
和
__eq__
方法以确保正确处理等价性。这种方法更加灵活,但需要更多代码。
结论
对于大多数情况,使用冻结集合是表示井字棋的等价类的一个好的解决方案。它既高效又易于理解。如果担心性能或需要更复杂的表示,可以考虑使用整数表示或自定义类。
请记住,理解数据结构背后的概念比坚持“正确”答案更重要。如果对冻结集合感到满意并且它们适合的需求,那么请放心地使用它们!
标签:python,reinforcement-learning From: 78710425