更新:
受clwhisk的建议启发,我有了以下想法:
将所有棋盘位置散列为 30 位 - 前 15 位作为计算机的位置,接下来的 15 位作为玩家的位置(每个棋子 5 位)。对于每 25 个选择 3 (=2300) 个计算机位置,生成 22 个选择 3 (=1540) 个匹配玩家位置,并将哈希设置为指向下一个棋盘位置(前 15 位是计算机的棋子)这可能是由于其中一台计算机棋子的移动造成的。
这种方式不需要生成任何动作,也不需要测试获胜位置。散列大小似乎是 2300 * 1540 = 3,542,000,但会同时包括所有三个棋子的预先计算的下一个棋盘状态,包括散列的获胜位置。此外,棋盘可以表示为一个数字,而不是有两个位棋盘代表每个玩家的位置(这在其他一些棋盘游戏中很常见)。
嗯,这个想法在我的 Firefox 浏览器上崩溃了,即使是网络工作者也是如此。所以我的替代想法是使用 2300 项哈希作为二维数组 (2300x2300; player_1_position x player_2_position) 的键,其值是可以跟随 player_1 可用动作的棋盘状态。此外,可以尝试对一半的位置进行散列 - 如果它不在散列中,则它在镜像位置。
结束更新。
这是一个尝试对所有棋盘位置、棋盘和移动进行哈希处理的 JavaScript 示例——在我看来,棋盘有 25 个选择 5 = 53130 种可能的状态(不包括我们想要移动的棋子) );每个棋盘状态为我们的棋子提供了 20 个可能的位置。
我不确定在这个相当大的哈希中查找的速度与动态生成可用移动的速度相比如何。正如预期的那样,预先计算哈希值需要几秒钟才能加载到浏览器上。
要查找可用的移动,请输入:hash[board<<5|position],
例如:
console.log(hash[31<<5|6])
[1048576,512,8388608]
console.log(hash[31<<5|7])
[2097152,512,32,16777216,1024]
JavaScript 代码(函数 comb 和 main 改编自 C 中的 Rosetta Code):
var hash = {}
function comb(m, n, c)
{
var i;
for (i = 0; i < n; i++) c[i] = n - i;
while (1) {
var s = 0
for (i = n; i--;)
s|=1<<c[i]-1;
//hash boards, positions, and moves
for (var j=1; j<=25; j++){
var pos = 1 << (j - 1)
if (pos & s)
continue
hash[(s<<5)|j] = moves(pos,s)
}
/* this check is not strictly necessary, but if m is not close to n,
it makes the whole thing quite a bit faster */
if (c[i]++ < m) continue;
for (i = 0; c[i] >= m - i;) if (++i >= n) return;
for (c[i]++; i; i--) c[i-1] = c[i] + 1;
}
}
function moves(position,board){
var leftBorder = 17318416,
rightBorder = 1082401,
moves = [],
positionTemp = position
//up
while (positionTemp < 1<<20 && !((positionTemp<<5) & board))
positionTemp <<= 5
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//down
while (positionTemp > 1<<4 && !((positionTemp>>5) & board))
positionTemp >>= 5
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//left
while (!((positionTemp<<1) & board)){
if (positionTemp & leftBorder || positionTemp == 1<<24)
break
positionTemp <<= 1
}
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//right
while (!((positionTemp>>1) & board)){
if (positionTemp & rightBorder || positionTemp == 1)
break
positionTemp >>= 1
}
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//NW
while (!((positionTemp<<6) & board)){
if (positionTemp & leftBorder || positionTemp >= 1<<20)
break
positionTemp <<= 6
}
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//NE
while (!((positionTemp<<4) & board)){
if (positionTemp & rightBorder || positionTemp >= 1<<20)
break
positionTemp <<= 4
}
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//SW
while (!((positionTemp>>4) & board)){
if (positionTemp & leftBorder || positionTemp <= 1<<4)
break
positionTemp >>= 4
}
if (positionTemp != position)
moves.push(positionTemp)
positionTemp = position
//SE
while (!((positionTemp>>6) & board)){
if (positionTemp & rightBorder || positionTemp <= 1<<4)
break
positionTemp >>= 6
}
if (positionTemp != position)
moves.push(positionTemp)
return moves
}
function main()
{
var buf = new Array(100);
comb(25, 5, buf);
console.log("done")
}
main()