2013-02-11 90 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