Java 九人莫里斯游戏的比特板表示
我正在用Java编写一个应用程序,已经用negamax实现了游戏规则和AI。然而,游戏是基于阵列的,当AI思考时(从6层开始),移动生成需要相当长的时间 我的位置数组基于下图:Java 九人莫里斯游戏的比特板表示,java,artificial-intelligence,bitboard,Java,Artificial Intelligence,Bitboard,我正在用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 我有更多的阵列,可能有磨坊
// 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);
所以我的问题是,我如何设置/更新玩家的比特板来跟踪他们的棋子?考虑到玩家的比特板有24位长,棋盘的位置0是第一位,当玩家移动时设置比特板非常简单,方法如下:
player1bb |= (1 << pos);
player1bb |=(1比特板很有趣:-)
我正在为这个问题编写一些代码,但这里有一些东西可以帮助您开始:
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
//
}
}
公共类位板{
公共静态最终整数白色=0;
公共静态最终整数黑色=1;
公共长[]板={0,0};
公共整数播放器=0;
公共int[]左={9,9};
公共int对手()
{
返回玩家==白色?黑色:白色;
}
公共void makemove(int-from、int-to、int-capture)
{
如果(from==0){
断言左[玩家]>0:“makemove:无左”;
左[玩家]——;
}
如果(从!=0)
{
断言(棋盘[玩家]&来自)!=0:“makemove:源空”;
棋盘[玩家]&=~来自;
}
断言(棋盘[Player]&to)==0:“makemove:目标必须为空”;
棋盘[牌手]|=到;
如果(捕获!=0)
{
断言(棋盘[对手()]和捕获)!=0:“makemove:捕获为空”;
棋盘[对手()]&=~捕获;
}
}
公共无效取消移动(int-from、int-to、int-capture)
{
如果(捕获!=0)
{
断言(棋盘[对手()]和捕获)=0:“取消移动:捕获为空”;
棋盘[对手()]|=捕获;
}
断言(棋盘[玩家]&目标)!=0:“取消移动:目标为空”;
棋盘[玩家]&=~to;
如果(从!=0)
{
assert(board[hatcher()]和capture)!=0:“取消移动:源必须为空”;
棋盘[玩家]|=来自;
}
如果(from==0){
断言左[玩家]<9:“取消移动:左过多”;
左[玩家]+;
}
}
公共void generatemoves()
{
//定相
//
}
}
未对此进行全面测试,但以下代码显示了如何使用:
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);
}
}
import java.math.*;
公共类九位板{
静态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
//职位
静态int A1=1这是性能代码。我也会做所有的第一步,但在未来的版本中,我可能只会做6个唯一的(其他的只会导致镜像的评估)
public long Perft(整数深度)
{
长节点=0;
ArrayList moves=generateMoves();
如果(深度==1)
{
//for(整数移动:移动)
//System.out.println(moveStr(move));
返回移动。size();
}
for(整数移动:移动){
int capture=1>10)>>1;
int to=1>5)和31>1;
int from=1>1;
makemove(从、到、捕获);
//系统输出打印(本);
节点+=性能(深度-1);
取消移动(从、到、捕获);
}
返回节点;
}
如你所见,我将移动打包成整数
对于健全性检查,以下是我的第一个性能结果:
- 124
- 2552
- 312144
- 4255024
- 55140800
- 699274176(3.107ms)
- 7 1873562112(53秒)
- 8需要太长时间
我知道你是阿莱德里要求的,但你应该这样实施
// 0 1 2
// 8 9 10
// 16 17 18
// 7 15 23 19 11 3
// 22 21 20
// 14 13 12
// 6 5 4
通过这种方式,你可以移动私密位置8的投掷位置>>1之前的字节相同位置比特板的真正优势是在生成makemove和unmakemove时保留一些额外的数据。我的第一个新增功能是跟踪每个玩家的成形磨数和铣削位置。这将大大改进移动生成(以及稍后的电路板评估)。我有类似的比特板代码。我正在与TT合作Negascout。如果您想共享更多代码,请告诉我。我们可以共享代码。我考虑在稍后阶段将其放在github上。我通过跟踪磨石完成了makemove/unmakemove。似乎可行,但需要进行健全性检查。我运行了性能测试(7)is在53秒内给出了1.873.562.112步。我要发布性能代码以便您检查吗?请发电子邮件到blastedw(at)hotmail(dot)com或add me on FBMy perft on ply 6在5.79秒内返回2164535个节点。但是我的perft复制电路板,生成移动,移动并撤销。嗯,pitty nodecounts不一致:好吧,我将深入调试:-)
// 0 1 2
// 8 9 10
// 16 17 18
// 7 15 23 19 11 3
// 22 21 20
// 14 13 12
// 6 5 4