【发布时间】:2013-01-26 21:23:48
【问题描述】:
我正在开发一个国际象棋引擎,我目前正在实施换位表(一组已经评估过的棋盘位置从过去的移动)。一般的想法是,当进行移动时,我会检查换位表中的匹配位置。如果存在,我会跳过代价高昂的评估过程,只从转置表中提取先前计算的结果。如果它不存在,我会进行所需的计算,然后将其添加到转置表中以供将来参考。
对我来说,这听起来像是哈希集或字典的工作。我决定用字典。我希望 key 是代表我的董事会的类,而 value 是遇到该位置的次数的 int 计数。计数的原因是能够检测到三次重复平局。如果相同的位置出现了 3 次或更多次,玩家可以选择平局。使用字典而不是哈希集,我可以通过将它与我的转置表结合起来,大大简化对三重重复绘制的检测。
为了做到这一点,我创建了代表棋盘状态的类覆盖 Equals() 和 GetHashCode()。它工作得很好,我现在能够跟踪游戏之前遇到的所有历史状态。
我的问题是我需要能够访问字典中键对象的属性。我可以查看是否存在匹配项(通过使用 .ContainsKey(...) 方法和我的 Equals()/GetHashCode() 逻辑),但现在我需要提取前面提到的计算值(存储为我的板的公共属性状态对象)来自键。
我想出了:
BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.GetHashCode() == this.GetHashCode());
这行得通,但对我来说感觉很笨拙。转置表的重点是加速数百万个连续棋盘状态的递归搜索。为每个匹配查询字典听起来很违反直觉。有没有更好的方法来做到这一点?
编辑:
正如已经指出的那样,由于有效的棋盘状态数量巨大,我的哈希值并不完美。我的 Equals() 覆盖检查第二个交替生成的哈希以减少冲突的可能性。我上面的“解决方案”是有缺陷的,因为它依赖于不完美的哈希。我应该使用:
BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.Equals(this));
我的一个愚蠢的疏忽。不过,我不喜欢查询字典。
【问题讨论】:
-
您的字典中的关键字究竟是什么?可以使
GetHashCode()的结果成为关键吗?如果是这样,那么处理起来就更“自然”了…… -
@Yahia 哈希码,就其本质而言,并不是唯一的,因此您需要支持对象列表作为值并使用
Equals来查找 true i> 与该哈希码相等的对象。 -
@Servy 是真的......但 OP 似乎对匹配哈希码的任何结果感到满意(根据显示的代码)......
-
他已经实现了自己的Hashcode,所以也许它现在是独一无二的? OP,是这样的吗?如果是这样......
-
@Yahia 哈希并不完美,这就是 Equals() 的用武之地。除了校验和之外,Equals() 还检查了一个校验和(第二种哈希算法)。确实,我的 lambda 没有考虑主哈希的潜在冲突。我没有考虑到这一点。我应该改用 Equals。
标签: c# dictionary key