C++ 在Zobrist散列中存储玩家回合
我目前正在中国Checkers minimax算法中实现一个换位表。在中国跳棋中,没有棋子被捕获,棋盘在功能上有81个空格。玩家轮流在棋盘上移动棋子 该过程的一部分涉及为board状态创建哈希。到目前为止,我已经有了一个有效的方法,可以为每个板状态创建(希望是)唯一的散列:C++ 在Zobrist散列中存储玩家回合,c++,algorithm,hash,hash-function,game-ai,C++,Algorithm,Hash,Hash Function,Game Ai,我目前正在中国Checkers minimax算法中实现一个换位表。在中国跳棋中,没有棋子被捕获,棋盘在功能上有81个空格。玩家轮流在棋盘上移动棋子 该过程的一部分涉及为board状态创建哈希。到目前为止,我已经有了一个有效的方法,可以为每个板状态创建(希望是)唯一的散列: myHash = 0; //randoms[81][3] is an array filled completely with pseudorandom values for (int x = 0; x < 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)
}
这是因为XOR函数具有可逆性
我现在遇到的问题是,哈希函数不存储轮到谁了。也就是说,您可以有两个相同的游戏板,但它们在minimax算法中会返回不同的值,因为一个尝试最大化分数,另一个尝试最小化分数
基本上,我的问题是:如何在增量生成的散列函数中存储玩家的回合,同时保持完美(最好是便宜)反转的能力?假设玩家的回合是整数而不是布尔值,因为游戏最终将有6名玩家而不是两名玩家。您可以使用填充伪随机值的
回合[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]];
std::uint64_t randoms[81][2];//两名球员
for(无符号x(0);x<81;++x)
如果(电路板[x])
myHash^=randoms[x][board[x]];
无论如何,您可以在散列的开头将回合状态存储为一个位
inline bool GetTurn(int hash){
return (bool)(hash & 1);
}
并且让数组中的Zobrist散列键的最低有效位都是0,例如,
[[0x2348dec2,0x93857e34,…]
谢谢,这应该可以很好地工作!此外,我没有考虑到事实上,我只需要散列填充方格,这肯定会节省一些空间。
inline bool GetTurn(int hash){
return (bool)(hash & 1);
}