我目前正在中国Checkers minimax算法中实现Transposition表。在中国跳棋中,没有任何棋子被捕获,并且棋盘在功能上是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函数的可逆性属性。
我现在遇到的问题是哈希函数不存储它的转向。也就是说,你可以有两个相同的游戏板,但它们会在minimax算法中返回不同的值,因为一个人试图最大化得分,而另一个试图最小化它。
基本上,我的问题是:如何在增量生成的哈希函数中存储玩家的回合,同时保持完美反转它的能力(并且最好是便宜)?假设玩家的回合是整数而不是布尔值,因为游戏最终将有6名玩家而不是2名玩家。
答案 0 :(得分:1)
您可以使用填充了伪随机值的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散列,排除空方块。空方块的位置未明确散列。
所以你可以使用更小(更多缓存友好)的数组。类似的东西:
std::uint64_t randoms[81][2]; // two players
for (unsigned x(0); x < 81; ++x)
if (board[x])
myHash ^= randoms[x][board[x]];
答案 1 :(得分:0)
对于它的价值,你可以将转弯状态存储在哈希的开头......
inline bool GetTurn(int hash){
return (bool)(hash & 1);
}
并且数组中的Zobrist散列键的最低有效位都为0,例如。 [[0x2348dec2, 0x93857e34, ....] ...]