【问题标题】:Correctly Implementing Zobrist Hashing正确实现 Zobrist 散列
【发布时间】:2012-04-09 08:21:10
【问题描述】:

我目前正在我的国际象棋引擎中添加转置表,但我在增量更新 Zobrist 键时遇到了问题。我did some research 并实现了基本思想,但它的行为不像我预期的那样。我遇到的问题是等效的棋盘位置并不总是具有相同的键。例如,在起始位置,如果两个玩家都移动了一个马然后将其移回,那么关键将与起始位置的不同。但是,再次执行此操作(移动骑士)并返回到起始位置产生原始键。因此,这种序列的周期似乎是每个玩家 4 步,而实际上应该是 2 步。

有没有人遇到过这样的问题或者想出解决办法?我已经包含了我的制作/取消制作方法的相关部分。我不包括边移动、易位权等;它们不应该影响我提出的具体案例。 HashValue 存储随机值,第一个索引是棋子类型,第二个索引是正方形。

void Make(Move m) {
    ZobristKey ^= HashValue[Piece[m.From].Type][m.From];
    ZobristKey ^= HashValue[Piece[m.From].Type][m.To];
    ZobristKey ^= HashValue[Piece[m.To].Type][m.To];
    //rest of make move
}

void Unmake(Move m) {
    ZobristKey ^= HashValue[m.Captured.Type][m.To];
    ZobristKey ^= HashValue[Element[m.To].Type][m.To];
    ZobristKey ^= HashValue[Element[m.To].Type][m.From];
    //rest of unmake
}

【问题讨论】:

  • 通常make和unmake应该是一样的。 (XOR 是对称的)散列不应该反映移动,而是板上的棋子。捕获一块 := 从散列中删除它的值。移动一块:=从哈希中删除上一个位置+将新位置添加到哈希中。 (castling 和 en-passant 状态有点不同)
  • 是的,我相信我的代码就是这样做的。还必须考虑其余的 make/unmake 代码,这就是“to”和“from”方块改变的原因;在 make 方法中位于“from”的部分显然不再存在于 unmake 方法中。
  • 不,Make() 代码应该只有两个组件:一个用于从旧位置删除该片段,另一个将其添加到新位置。 (可能还有一个额外的组件来移除捕获的部分)
  • 我有一个“空”的片段类型,所以我认为我不需要检查捕获的片段。我认为这不会造成任何问题,但最好检查一下。
  • 好吧,我错了。包括“空”的部分把事情搞砸了。谢谢您的帮助;如果你做一个,我会接受你的回答:)。

标签: hash chess


【解决方案1】:
Make_a_move() {
    hashval ^= Zobrist_array[oldpos][piece];
    hashval ^= Zobrist_array[newpos][piece];
    /* if there is a capture */
    hashval ^= Zobrist_array[otherpos][otherpiece];
    }

Undo_a_move() {
    hashval ^= Zobrist_array[oldpos][piece];
    hashval ^= Zobrist_array[newpos][piece];
    /* if there was a capture */
    hashval ^= Zobrist_array[otherpos][otherpiece];
    }

攻城可以看作是两个动作的总和(显然没有捕获)

升级可以被视为从棋盘上移除一个棋子(从 2 或 7 位置)并添加新棋子(在 1 或 8 位置)

【讨论】:

    猜你喜欢
    • 2014-09-08
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 2016-05-09
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多