2013-02-11 84 views
4

我正在研究国际象棋引擎,目前我正在实施转位表(一组已经评估过的棋盘位置)。总的想法是,当做出移动时,我检查换位表的匹配位置。如果存在,我跳过昂贵的评估过程,只需从转置表中提取以前计算的结果。如果它不存在,我会进行所需的计算,然后将其添加到转位表中以备将来参考。如何引用引用类型字典键的属性?

对我来说,这听起来像一个哈希集或字典的工作。我决定了字典。我希望关键是成为代表我的董事会的班级,并且该值应该是遇到位置次数的整数。计数的原因是能够检测到三次重复绘制。如果同一位置已经遇到过三次或更多次,玩家可以选择打平。使用字典而不是哈希集合,通过将它与转置表相结合,可以大大简化对三次重复绘制的检测。

为了做到这一点,我已经让表示电路板状态的类覆盖了Equals()和GetHashCode()。它工作得很好,现在我能够跟踪以前遇到的所有历史状态。

我的问题是我需要能够访问字典中的键对象的属性。我可以通过使用.ContainsKey(...)方法和我的Equals()/ GetHashCode()逻辑)查看是否存在匹配,但现在我需要提取前面提到的计算值(作为我的板的公共属性存储状态对象)。

我能想出:

BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.GetHashCode() == this.GetHashCode()); 

这工作,但感觉笨重给我。换位表的全部内容是加速对数百万连续棋盘状态的递归搜索。查询每场比赛的字典听起来都是违反直觉的。有一个更好的方法吗?

编辑:

由于它已经指出的那样,我的哈希不能是完美的,由于有效的板状态的数量巨大。 My Equals()覆盖会检查第二个备选生成的散列,以减少冲突的可能性。我上面的'解决方案'是有缺陷的,因为它依赖于不完美的哈希。我应该使用:

BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.Equals(this)); 

我的一个愚蠢的疏忽。不过,我不是一个查询字典的粉丝。

+0

字典中的关键字究竟是什么?可以使'GetHashCode()'的结果成为关键吗?如果是这样,那么这变得更加“自然”来处理...... – Yahia 2013-02-11 17:52:18

+0

@Yahia哈希代码,由于其本质,不是唯一的,所以你需要支持一个对象列表作为值并使用'Equals'用该散列码查找*真*相等的对象。 – Servy 2013-02-11 17:53:10

+0

@Servy,这是真的......但OP似乎很满意匹配散列码的任何结果(根据显示的代码)... – Yahia 2013-02-11 17:54:33

回答

2

一种选择是牵住参考词典中的值的键,以及字典的实际值,就像这样:

Dictionary<BoardState, Tuple<BoardState, int>> 

然后,每当你添加一个对象添加相同对象的值作为重点:

Dictionary<BoardState, Tuple<BoardState, int>> boards = 
    new Dictionary<BoardState,Tuple<BoardState,int>>(); 
BoardState board = new BoardState(); 
boards.Add(board, Tuple.Create(board, 1)); 

另一种选择(这可能是更好的设计)就是要打破你的董事会状态对象分为两个不同的类型。有一个确实代表董事会的状态(这应该是不可变的),另一个保存关于该状态的其他信息,包括发生的时间以及可能适用于您的特定应用程序的任何其他可用的属性。这将防止您需要访问字典密钥。

+0

我喜欢分离状态的想法...这不是简单的解决方案,但这感觉就像是正确的方向。 – Chronicide 2013-02-11 20:09:53

+0

我还应该注意到,我选择了你的答案,因为你的第一个解决方案不仅能回答我的问题,而且也意味着没有简单的方法直接访问密钥的属性(这正是我所行动的,在我自己的啰嗦中四处转转)。就像旁边一样,针对特定情况的另一种解决方案是为换位表运行哈希集,为三重重复规则运行单独的字典。这有消除歧义的额外好处,其中每个人都负责一件事,而没有其他任何东西。 – Chronicide 2013-02-11 20:19:54