Here are some defines to get started.
Code: Select all
typedef int8_t s08;
typedef uint8_t u08;
typedef int32_t s32;
typedef uint64_t u64;
constexpr u64 one = 1ull;
constexpr s32 valp = 100;
constexpr s32 valn = 290;
constexpr s32 valb = 320;
constexpr s32 valr = 500;
constexpr s32 valq = 960;
constexpr s32 na = 0;
constexpr u64 file_b2_b7 = 0x0002020202020200;
constexpr u64 file_a2_a7 = 0x0001010101010100;
constexpr u64 diag_c2_h7 = 0x0080402010080400;
constexpr u64 occ_w_s = 0x0000000000000060; // occupied white short castling squares
constexpr u64 occ_w_l = 0x000000000000000e;
constexpr u64 occ_b_s = 0x6000000000000000;
constexpr u64 occ_b_l = 0x0e00000000000000;
constexpr u64 atk_w_s = 0x0000000000000070; // attacked white short castling squares
constexpr u64 atk_w_l = 0x000000000000001c;
constexpr u64 atk_b_s = 0x7000000000000000;
constexpr u64 atk_b_l = 0x1c00000000000000;
typedef struct {
u08 fs; // from square
u08 ts; // to square
u08 ft; // from type
u08 tt; // to type
} Move;
typedef struct {
u64 epsq;
u64 sides[2];
u64 pawns[2];
u64 knights[2];
u64 bishops[2];
u64 rooks[2];
u64 queens[2];
u64 kings[2];
s32 board[64];
s32 stm; // side to move
s32 otm; // otherside to move
s32 ply;
} Thread;
// some defines so t-> does not have to be typed everywhere
#define epsq t->epsq
#define sides t->sides
#define pawns t->pawns
#define knights t->knights
#define bishops t->bishops
#define rooks t->rooks
#define queens t->queens
#define kings t->kings
#define board t->board
#define stm t->stm
#define otm t->otm
#define ply t->ply
enum { EXIT, GETCMD, SEARCH, MOVE, RESIGN };
enum { BLACK, WHITE };
enum {
WP2, WP3, WP4, WP5, WP6, WP7, WN, WB, WR, Wr, WQ, WK, Wk, // a WK is a king with castling rights, Wk can't castle
ES,
BP7, BP6, BP5, BP4, BP3, BP2, BN, BB, BR, Br, BQ, BK, Bk,
WPd, WPe, WPq, WPn, WPr, WPb, WS, WL, // special case labels to handle some rules more efficiently
BPd, BPe, BPq, BPn, BPr, BPb, BS, BL
};
enum {
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8
};
enum { RANK1, RANK2, RANK3, RANK4, RANK5, RANK6, RANK7, RANK8 };
enum { FILEa, FILEb, FILEc, FILEd, FILEe, FILEf, FILEg, FILEh };
Code: Select all
u64 wPawnAtks[64];
u64 bPawnAtks[64];
u64 knightMvs[64];
u64 kingMvs[64];
u64 aMask[64]; // anti diagonal mask
u64 dMask[64]; diagonal mask
u64 aSubset[64][64]; // anti diagonal subset of possible move bits
u64 dSubset[64][64]; // diagonal Subset of possible move bits
u64 vSubset[64][64]; // vertical Subset of possible move bits
u64 hSubset[64][64]; // horizontal Subset of possible move bits
s32 hShift[64]; // necessary shift for horizontal move gen
Code: Select all
static void Resign() {
}
static void GameMove() {
}
static void MakeMove(Thread* t, Move* m) {
}
static void TakeBack(Thread* t, Move* m) {
}
static bool AtkByWhite(Thread* t, u64 bb) {
u64 atk = 0;
u64 occ = sides[WHITE] | sides[BLACK];
while (bb) {
s32 sq = std::countr_zero(bb);
bb ^= 1ull << sq;
atk |= (bPawnAtks[sq] & pawns[WHITE]);
atk |= (knightMvs[sq] & knights[WHITE]);
atk |= (kingMvs[sq] & kings[WHITE]);
atk |= (dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE]));
atk |= (aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[WHITE] | queens[WHITE]));
atk |= (hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[WHITE] | queens[WHITE]));
atk |= (vSubset[sq][((((occ >> (sq & 7)) & file_a2_a7) * diag_c2_h7) >> 58)] & (rooks[WHITE] | queens[WHITE]));
}
return (atk != 0);
}
static bool AtkByBlack(Thread* t, u64 bb) {
u64 atk = 0;
u64 occ = sides[WHITE] | sides[BLACK];
while (bb) {
s32 sq = std::countr_zero(bb);
bb ^= 1ull << sq;
atk |= (wPawnAtks[sq] & pawns[BLACK]);
atk |= (knightMvs[sq] & knights[BLACK]);
atk |= (kingMvs[sq] & kings[BLACK]);
atk |= (dSubset[sq][(((occ & dMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK]));
atk |= (aSubset[sq][(((occ & aMask[sq]) * file_b2_b7) >> 58)] & (bishops[BLACK] | queens[BLACK]));
atk |= (hSubset[sq][(occ >> hShift[sq]) & 63] & (rooks[BLACK] | queens[BLACK]));
atk |= (vSubset[sq][((((occ >> (sq & 7)) & file_a2_a7) * diag_c2_h7) >> 58)] & (rooks[BLACK] | queens[BLACK]));
}
return (atk != 0);
}
static s32 GenAllMoves(Thread* t, u64* bb) {
u64 atk = 0;
u08 fs, ft;
u64 friends = sides[stm];
u64 enemies = sides[otm];
u64 occupied = friends | enemies;
u64 empty = ~occupied;
u64 notme = ~friends;
do {
fs = std::countr_zero(friends);
friends ^= 1ull << fs;
ft = board[fs];
switch (ft) {
case WP2:
atk |= bb[fs] = wPawnAtks[fs] & enemies;
bb[fs] |= (one << (fs + 8)) & empty;
bb[fs] |= (bb[fs] << 8) & (one << (fs + 16)) & empty;
break;
case WP3: case WP4: case WP6: case WP7:
atk |= bb[fs] = wPawnAtks[fs] & enemies;
bb[fs] |= (one << (fs + 8)) & empty;
break;
case WP5:
atk |= bb[fs] = wPawnAtks[fs] & (enemies | epsq);
bb[fs] |= (one << (fs + 8)) & empty;
break;
case WN: case BN:
atk |= bb[fs] = knightMvs[fs] & notme;
break;
case WB: case BB:
atk |= bb[fs] = (
dSubset[fs][(((occupied & dMask[fs]) * file_b2_b7) >> 58)] |
aSubset[fs][(((occupied & aMask[fs]) * file_b2_b7) >> 58)]
) & notme;
break;
case WR: case Wr: case BR: case Br:
atk |= bb[fs] = (
hSubset[fs][(occupied >> hShift[fs]) & 63] |
vSubset[fs][((((occupied >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
) & notme;
break;
case WQ: case BQ:
atk |= bb[fs] = (
dSubset[fs][(((occupied & dMask[fs]) * file_b2_b7) >> 58)] |
aSubset[fs][(((occupied & aMask[fs]) * file_b2_b7) >> 58)] |
hSubset[fs][(occupied >> hShift[fs]) & 63] |
vSubset[fs][((((occupied >> (fs & 7)) & file_a2_a7) * diag_c2_h7) >> 58)]
) & notme;
break;
case WK:
atk |= bb[fs] = kingMvs[fs] & notme;
bb[fs] |= ((u64)((board[h1] == WR) & !(occupied & occ_w_s) & !AtkByBlack(t, atk_w_s))) * g1;
bb[fs] |= ((u64)((board[a1] == WR) & !(occupied & occ_w_l) & !AtkByBlack(t, atk_w_l))) * c1;
break;
case Wk:
atk |= bb[fs] = kingMvs[fs] & notme;
break;
case BK:
atk |= bb[fs] = kingMvs[fs] & notme;
bb[fs] |= ((u64)((board[h8] == BR) & !(occupied & occ_b_s) & !AtkByWhite(t, atk_b_s))) * g8;
bb[fs] |= ((u64)((board[a8] == BR) & !(occupied & occ_b_l) & !AtkByWhite(t, atk_b_l))) * c8;
break;
case Bk:
atk |= bb[fs] = kingMvs[fs] & notme;
break;
}
} while (friends);
}
static void StartSearch() {
}
static void GetCommand() {
}
static void NewGame() {
mode = GETCMD;
}
static void InitBitboards() {
s08 sq, ts, x, y, dx, dy;
u64 occ;
for (sq = a1; sq <= h8; sq++) {
x = sq & 7;
y = sq >> 3;
// pawns
if (sq >= a2 && sq <= h7) {
wPawnAtks[sq] = ((u64)(x > FILEa) << (sq + 7)) | ((u64)(x < FILEh) << (sq + 9));
bPawnAtks[sq] = ((u64)(x > FILEa) << (sq - 9)) | ((u64)(x < FILEh) << (sq - 7));
}
// knights
knightMvs[sq] =
((u64)(x > FILEb && y < RANK8) << (sq + 06)) |
((u64)(x > FILEa && y < RANK7) << (sq + 15)) |
((u64)(x < FILEh && y < RANK7) << (sq + 17)) |
((u64)(x < FILEg && y < RANK8) << (sq + 10)) |
((u64)(x < FILEg && y > RANK1) << (sq - 06)) |
((u64)(x < FILEh && y > RANK2) << (sq - 15)) |
((u64)(x > FILEa && y > RANK2) << (sq - 17)) |
((u64)(x > FILEb && y > RANK1) << (sq - 10));
// kings
kingMvs[sq] =
((u64)(x > FILEa) << (sq - 1)) |
((u64)(x < FILEh) << (sq + 1)) |
((u64)(y < RANK8) << (sq + 8)) |
((u64)(y > RANK1) << (sq - 8)) |
((u64)(x > FILEa && y < RANK8) << (sq + 7)) |
((u64)(x < FILEh && y < RANK8) << (sq + 9)) |
((u64)(x < FILEh && y > RANK1) << (sq - 7)) |
((u64)(x > FILEa && y > RANK1) << (sq - 9));
// diagonals
for (ts = sq + 9, dx = x + 1, dy = y + 1; dx < FILEh && dy < RANK8; dMask[sq] |= 1ull << ts, ts += 9, dx++, dy++);
for (ts = sq - 9, dx = x - 1, dy = y - 1; dx > FILEa && dy > RANK1; dMask[sq] |= 1ull << ts, ts -= 9, dx--, dy--);
// anti diagonals
for (ts = sq + 7, dx = x - 1, dy = y + 1; dx > FILEa && dy < RANK8; aMask[sq] |= 1ull << ts, ts += 7, dx--, dy++);
for (ts = sq - 7, dx = x + 1, dy = y - 1; dx < FILEh && dy > RANK1; aMask[sq] |= 1ull << ts, ts -= 7, dx++, dy--);
// diagonal indexes
for (u64 index = 0; index < 64; index++) {
dSubset[sq][index] = 0;
occ = index << 1;
if ((sq & 7) != FILEh && (sq >> 3) != RANK8) {
for (ts = sq + 9; ; ts += 9) {
dSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEh || (ts >> 3) == RANK8) break;
}
}
if ((sq & 7) != FILEa && (sq >> 3) != RANK1) {
for (ts = sq - 9; ; ts -= 9) {
dSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEa || (ts >> 3) == RANK1) break;
}
}
}
// anti diagonal indexes
for (u64 index = 0; index < 64; index++) {
aSubset[sq][index] = 0;
occ = index << 1;
if ((sq & 7) != FILEa && (sq >> 3) != RANK8) {
for (ts = sq + 7; ; ts += 7) {
aSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEa || (ts >> 3) == RANK8) break;
}
}
if ((sq & 7) != FILEh && (sq >> 3) != RANK1) {
for (ts = sq - 7; ; ts -= 7) {
aSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEh || (ts >> 3) == RANK1) break;
}
}
}
// vertical indexes
for (u64 index = 0; index < 64; index++) {
vSubset[sq][index] = 0;
uint64_t blockers = 0;
for (int i = 0; i <= 5; i++) {
if (index & (1ull << i)) {
blockers |= (1ull << (((5 - i) << 3) + 8));
}
}
if ((sq >> 3) != RANK8) {
for (ts = sq + 8; ; ts += 8) {
vSubset[sq][index] |= (1ull << ts);
if (blockers & (1ull << (ts - (ts & 7)))) break;
if ((ts >> 3) == RANK8) break;
}
}
if ((sq >> 3) != RANK1) {
for (ts = sq - 8; ; ts -= 8) {
vSubset[sq][index] |= (1ull << ts);
if (blockers & (1ull << (ts - (ts & 7)))) break;
if ((ts >> 3) == RANK1) break;
}
}
}
// horizontal indexes
for (u64 index = 0; index < 64; index++) {
hSubset[sq][index] = 0;
occ = index << 1;
if ((sq & 7) != FILEh) {
for (ts = sq + 1; ; ts += 1) {
hSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEh) break;
}
}
if ((sq & 7) != FILEa) {
for (ts = sq - 1; ; ts -= 1) {
hSubset[sq][index] |= (1ull << ts);
if (occ & (1ull << (ts & 7))) break;
if ((ts & 7) == FILEa) break;
}
}
}
// horizontal shift
hShift[sq] = (sq & 56) + 1;
}
}
static void Initialize() {
InitBitboards();
NewGame();
}
s32 main() {
Initialize();
while (mode != EXIT) {
if (mode == GETCMD) GetCommand();
if (mode == SEARCH) StartSearch();
if (mode == MOVE) GameMove();
if (mode == RESIGN) Resign();
}
}