c++ - 将玩家回合存储在 Zobrist 哈希值中

标签 c++ algorithm hash hash-function game-ai

我目前正在中国跳棋极小极大算法中实现换位表。在中国跳棋中,不会吃掉任何棋子,棋盘的功能大小为 81 个格。玩家轮流在棋盘上移动棋子。

该过程的一部分涉及为棋盘状态创建哈希。到目前为止,我已经有了一个可以为每个棋盘状态创建(希望)唯一的哈希值的有效方法:

 myHash = 0;
 //randoms[81][3] is an array filled completely with pseudorandom values
 for (int x = 0; x < 81; x++) {
      myHash ^= randoms[x][board[x]]; 
      //board[x] is the piece at space x (1=player1 piece, 2=player2 piece, 0=empty)
 }

更重要的是,我在 applyMove 函数(和 undoMove 函数)中逐步执行此操作:

applyMove(int to, int from) {

   //Undo the 'from' piece in the hash
   myHash ^= randoms[from][board[from]];
   // Apply the move
   std::swap(board[from], board[to]);
   //Add the 'to' piece to the hash
   myHash ^= randoms[to][board[to]];

   // Update whose turn it is
   swapTurn();
 }

这是由于 XOR 函数的可逆性而起作用的。

我现在遇到的问题是,哈希函数不存储轮到谁了。也就是说,您可以有两个相同的游戏板,但它们会在极小极大算法中返回不同的值,因为一个试图最大化分数,另一个试图最小化分数。

基本上,我的问题是:如何将玩家的回合存储在增量生成的哈希函数中,同时保持完美反转的能力(最好是便宜的)?假设玩家的回合是整数而不是 bool 值,因为游戏最终将有 6 名玩家而不是 2 名玩家。

最佳答案

您可以使用填充伪随机值的 turns[6] 数组:

unsigned n = 6;  // number of players;

myHash ^= turns[active_player];           // 'undo' the old active player
active_player = (active_player + 1) % n;  // new active player's index
myHash ^= turns[active_player];           // 'add' new active player

这与棋子位置增量更新类似,适用于 n ∈ [2, 6]。


作为旁注...

通常,Zobrist 哈希是通过扫描棋子的位置来完成的,排除空方 block 。空方 block 的位置未显式散列。

因此您可以使用更小的(更适合缓存)数组。像这样的东西:

std::uint64_t randoms[81][2];  // two players

for (unsigned x(0); x < 81; ++x)
  if (board[x])
    myHash ^= randoms[x][board[x]]; 

关于c++ - 将玩家回合存储在 Zobrist 哈希值中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29666995/

相关文章:

c++ - 如何将 GLES 包含在旧 GL 中

MySQL SHA-256 双重哈希截断数据失败

c++ - 如何修剪 std::string?

python - 在Pygame中绘制五边形、六边形

c++ - Kosaraju 的 spoj 底部算法

c++ - 输入 "cobra"输出 "dpcsb"将 1 个字符转换为下一个 C++

c# - 征求意见 : fast hashed base class for dictonary keys

php - 与盐渍 SHA512 相比,盐渍 SHA1 有多不安全

c++ - llvm 可以发出跳转到函数内给定地址的代码吗?

c++ - 如何从派生类访问基类中的 protected 方法?