3

我正在用 Java 编写九人莫里斯游戏,并且已经使用 negamax 实现了游戏规则和 AI。然而,游戏是基于数组的,当 AI 思考时(从 6 层开始),移动生成需要相当长的时间。

我的位置数组基于下图:

// 0        1        2
//    3     4     5
//       6  7  8
// 9  10 11    12 13 14
//       15 16 17
//    18    19    20
// 21       22       23

我有更多的阵列充满了可能的工厂和相邻的位置。

我决定将游戏从阵列更改为使用位板,以便移动生成和当前使用阵列的其他区域更快。

我的第一步是为每个玩家准备一个位板,用于跟踪玩家在棋盘上的棋子。

第二步是确定空闲位置的位置。我知道我可以这样做:

freepositions = ~(player1bb | player2bb);

所以我的问题是,我如何设置/更新玩家的位板以跟踪他们的作品?

4

4 回答 4

1

考虑到玩家的棋盘长度为 24 位,棋盘的位置 0 为第一位,因此在玩家下棋时设置棋盘非常简单,只需执行以下操作:

player1bb |= (1 << pos);
于 2013-03-15T10:17:16.793 回答
0

位板很有趣:-)

我正在为这个问题编写一些代码,但这里有一些可以让你开始的东西:

public class BitBoard {
    public static final int White = 0;
    public static final int Black = 1;

    public long[] board = { 0, 0 };
    public int Player = 0;
    public int[] left = { 9, 9 };

    public int Opponent()
    {
        return Player == White ? Black : White;
    }

    public void makemove(int from, int to, int capture)
    {
        if (from == 0) { 
            assert left[Player] > 0 : "makemove: no left";
            left[Player]--;
        }       
        if (from != 0)
        {
            assert (board[Player] & from) != 0 : "makemove: source empty";
            board[Player] &= ~from;
        }
        assert (board[Player] & to) == 0 : "makemove: target must be empty";
        board[Player] |= to;
        if (capture != 0)
        {
            assert (board[Opponent()] & capture) != 0 : "makemove: capture empty";
            board[Opponent()] &= ~capture;
        }
    }

    public void unmakemove(int from, int to, int capture)
    {
        if (capture != 0)
        {
            assert (board[Opponent()] & capture) == 0 : "unmakemove: capture empty";
            board[Opponent()] |= capture;
        }
        assert (board[Player] & to) != 0 : "unmakemove: target empty";
        board[Player] &= ~to;
        if (from != 0)
        {
            assert (board[Opponent()] & capture) != 0 : "unmakemove: source must be empty empty";
            board[Player] |= from;
        }
        if (from == 0) { 
            assert left[Player] < 9 : "unmakemove: too many left";
            left[Player]++;
        }           
    }

    public void generatemoves()
    {
        // determine phase

        // 

    }
}

没有对此进行全面测试,但以下代码显示了如何使用:

import java.math.*;

public class NineMenBitboard {
    static int tst;

    //   A  B  C  D  E  F  G
    // 1 0        1        2
    // 2    3     4     5
    // 3       6  7  8
    // 4 9 10 11    12 13 14
    // 5      15 16 17
    // 6   18    19    20
    // 7 21       22       23

    // positions

    static int A1 = 1 << 0;
    static int D1 = 1 << 1;
    static int G1 = 1 << 2;
    static int B2 = 1 << 3;
    static int D2 = 1 << 4;
    static int F2 = 1 << 5;
    static int C3 = 1 << 6;
    static int D3 = 1 << 7;
    static int E3 = 1 << 8;
    static int A4 = 1 << 9;
    static int B4 = 1 << 10;
    static int C4 = 1 << 11;
    static int E4 = 1 << 12;
    static int F4 = 1 << 13;
    static int G4 = 1 << 14;
    static int C5 = 1 << 15;
    static int D5 = 1 << 16;
    static int E5 = 1 << 17;
    static int B6 = 1 << 18;
    static int D6 = 1 << 19;
    static int F6 = 1 << 20;
    static int A7 = 1 << 21;
    static int D7 = 1 << 22;
    static int G7 = 1 << 23;

    // mills

    static int hor1 = A1 | D1 | G1;
    static int hor2 = B2 | D2 | F2;
    static int hor3 = C3 | D3 | E3;
    static int hor4_1 = A4 | B4 | C4;
    static int hor4_2 = E4 | F4 | G4;
    static int hor5 = C5 | D5 | E5;
    static int hor6 = B6 | D6 | F6;
    static int hor7 = A7 | D7 | G7;

    static int ver1 = A1 | A4 | A7;
    static int ver2 = B2 | B4 | B6;
    static int ver3 = C3 | C4 | C5;
    static int ver4_1 = D1 | D2 | D3;
    static int ver4_2 = D5 | D6 | D7;
    static int ver5 = E3 | E4 | E5;
    static int ver6 = F2 | F4 | F6;
    static int ver7 = G1 | G4 | G7; 

    public static void main(String[] args) {
        // sample on how to loop bits

        BitBoard game = new BitBoard();
        game.makemove(0, A1, 0);
        game.makemove(A1, A4, 0);


        System.out.println();

        tst = 255;

        for(int looper = tst, i = Integer.highestOneBit(looper); looper != 0; looper &= ~i, i = Integer.highestOneBit(looper))
        {
            System.out.println(i);
        }       

        System.out.println(tst);
      }
}

还添加了一个循环来显示如何循环遍历位置。

玩得开心。我也将编写这个游戏,因为我想刷新我的 AB 修剪 :-)

于 2013-03-16T22:22:59.643 回答
0

这是 Perft 代码。我也在做所有的第一步,但在未来的版本中,我可能只会做 6 个独特的(其他只会导致评估镜像)。

public long Perft(int depth)
{
    long nodes = 0;

    ArrayList<Integer> moves = generateMoves();

    if (depth == 1) 
    {
        //for(int move : moves)
        //  System.out.println(moveStr(move));
        return moves.size();
    }

    for (int move : moves) {
        int capture = 1 << (move >> 10) >> 1; 
        int to = 1 << ((move >> 5) & 31) >> 1;
        int from = 1 << (move & 31) >> 1;           
        makemove(from, to, capture);
        //System.out.print(this);
        nodes += Perft(depth - 1);
        unmakemove(from, to, capture);
    }
    return nodes;       
}

如您所见,我将动作打包成整数。

对于健全性检查,这是我的第一个 perft 结果:

  • 1 24
  • 2 552
  • 3 12144
  • 4 255024
  • 5 5140800
  • 6 99274176 (3.107ms)
  • 7 1873562112(53 秒)
  • 8 耗时太长
于 2013-03-17T21:37:04.907 回答
0

我知道你已经实现了它,但你应该这样实现它

//  0        1           2
//     8     9       10
//        16  17  18
//  7 15  23      19 11  3
//        22   21 20
//    14    13       12
//  6       5            4

这样你就可以移动投掷位置 pos >> 1 for privious pos << 1 for next , pos << 8 for next byte 相同位置 pos >> 8 previous 用于字节相同位置

于 2013-03-24T16:26:02.207 回答