在Neutreeko中,比发动机更好地移动发电机

时间:2014-01-25 16:51:29

标签: algorithm

我正在实施一款名为Neutreeko的游戏(5x5棋盘,两个玩家各占3个棋子),对于我正在实施的蒙特卡罗树搜索,我需要一种快速的方法来为所有的棋子生成所有可能的动作由玩家。我将板状态存储在一维数组中,其中每个单元格等于'player','cpu'或0。

关于规则,如果棋子沿水平线,垂直线或对角线移动到最远点而不击中墙壁或其他棋子,则移动是有效的(这意味着如果你假设站在中心位置一个空板,只允许你在每个角落和靠近这些边的每一边的中间单元中,总共8次移动。)

找到动作的更好方法是在8个方向中的每一个方向上进行蛮力行动,直到我撞到墙壁或其他棋子为止?这也需要许多条件来确保 - 当检查对角线时 - 我们在使用升序索引等旅行时不会意外地转到另一条线路。当然可以做到,但我敢打赌,有一些博弈论实践可以更优雅,更有效地处理它。

2 个答案:

答案 0 :(得分:0)

希望这不完全不清楚......

通过阻挡线,每件都会在允许的移动中导致某些排除。有24条线(10 + 14对角线)和我的计数320可能的滑动。最好在每个方向上使用5个“环绕式”对角线,总共20行,每行最多20次。每件作品都放在3(角)或4行上,当一件作品移动时,你会更新它移动的线,以及4-6个受影响的线。

特定方格的排除,即该方块上的棋子的移动是不变的。您需要做的就是从每一行添加或减去一个常量二进制字符串。要生成一个新位置,请从玩家的三个方块的方块中检查每个移动的一些位标记,以查看该移动的排除数量是否为零。

每次移动的最大排除次数各不相同(例如,如果整行已满,则有5个原因导致您无法从A滑动到E)。法线的总表示需要23位。

ABCDE AB,BC,CD,DE,AC,BD,CE每个只需要2位(< = 3个排除) AD,BE,AE 3位

答案 1 :(得分:0)

更新

受到clwhisk的建议的启发,我有了以下想法:

将所有棋盘位置散列为30位 - 前15位作为计算机的位置,接下来15位作为玩家的位置(每个棋子5位)。对于每25个选择3(= 2300)的计算机位置,生成22选择3(= 1540)个匹配的玩家位置,并设置散列指向下一个板位置(前15位是计算机&#39) ;其中一个计算机棋子移动会导致其产生。

这样就不需要生成任何动作,也不需要测试获胜位置。看起来哈希大小将是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代码(函数combmain)改编自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()