refactor: (bb64)occupied -> ~(Bb64)PIECE_EMPTY
This commit is contained in:
@@ -197,10 +197,6 @@ static void board_print(struct pos const* pos, struct move* move, FILE* out, boo
|
||||
bg = (i+j) % 2 ? 45 : 43;
|
||||
}
|
||||
|
||||
if ((pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK]) & MASK_FROM_SQ(n)) {
|
||||
bg += 60; /* make bright */
|
||||
}
|
||||
|
||||
fprintf(out, "\033[%d;%dm", fg, bg);
|
||||
|
||||
if (buf[i][j]) {
|
||||
|
||||
@@ -2,25 +2,24 @@ let exports;
|
||||
|
||||
async function init() {
|
||||
const resp = await fetch("./chess.wasm");
|
||||
if (!resp.ok) {
|
||||
throw new Error("fetch wasm failed ${resp.status} ${resp.statusText}");
|
||||
}
|
||||
|
||||
const { instance } =
|
||||
await WebAssembly.instantiateStreaming(resp, {});
|
||||
if (!resp.ok) throw new Error(`fetch wasm failed ${resp.status} ${resp.statusText}`);
|
||||
|
||||
const { instance } = await WebAssembly.instantiateStreaming(resp, {});
|
||||
exports = instance.exports;
|
||||
}
|
||||
|
||||
await init();
|
||||
self.postMessage({ type: "ready" });
|
||||
|
||||
self.onmessage = (e) => {
|
||||
const { id, method, args = [] } = e.data;
|
||||
try {
|
||||
const value = exports[method](...args);
|
||||
let value;
|
||||
value = exports[method](...args);
|
||||
self.postMessage({ id, ok: true, value });
|
||||
} catch (err) {
|
||||
self.postMessage({ id, ok: false, error: String(err?.message ?? err) });
|
||||
self.postMessage({
|
||||
id, ok: false, error: String(err?.message ?? err)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ static Bb64 diagonals(Bb64 p)
|
||||
* ==================
|
||||
*
|
||||
* All piece attack functions rely on the caller masking their own pieces.
|
||||
* e.g. `knight_attacks(knights) & ~our_occupied`
|
||||
* e.g. `knight_attacks(knights) & empty`
|
||||
* */
|
||||
|
||||
static Bb64 knight_attacks(Bb64 p)
|
||||
@@ -522,7 +522,7 @@ static Bb64 attacks_to(struct pos const* pos,
|
||||
Bb64 pretend_occupied,
|
||||
Bb64 pretend_empty)
|
||||
{
|
||||
Bb64 const occ_orig = pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK];
|
||||
Bb64 const occ_orig = ~(pos->pieces[SIDE_WHITE][PIECE_EMPTY] & pos->pieces[SIDE_BLACK][PIECE_EMPTY]);
|
||||
Bb64 const occ = (occ_orig & ~pretend_empty) | pretend_occupied;
|
||||
|
||||
Bb64 const* pw = pos->pieces[SIDE_WHITE];
|
||||
@@ -563,15 +563,15 @@ static
|
||||
Bb64 checkers(struct pos const* pos, Side8 us)
|
||||
{
|
||||
/* TODO: specialize */
|
||||
return attacks_to(pos, pos->pieces[us][PIECE_KING], 0ULL, 0ULL) & ~pos->occupied[us];
|
||||
return attacks_to(pos, pos->pieces[us][PIECE_KING], 0ULL, 0ULL) & pos->pieces[us][PIECE_EMPTY];
|
||||
}
|
||||
|
||||
static
|
||||
Bb64 pinning_lines_to_target(struct pos const* pos, Side8 us, Sq8 tsq)
|
||||
{
|
||||
Side8 const them = other_side(us);
|
||||
Bb64 const our_occ = pos->occupied[us];
|
||||
Bb64 const their_occ = pos->occupied[them];
|
||||
Bb64 const our_occ = ~pos->pieces[us][PIECE_EMPTY];
|
||||
Bb64 const their_occ = ~pos->pieces[them][PIECE_EMPTY];
|
||||
|
||||
Bb64 const* p = pos->pieces[them];
|
||||
Bb64 const bqs = p[PIECE_QUEEN] | p[PIECE_BISHOP];
|
||||
@@ -595,7 +595,7 @@ Bb64 pinning_lines_to_target(struct pos const* pos, Side8 us, Sq8 tsq)
|
||||
static
|
||||
Bb64 all_threats_from_side(struct pos const * pos, Side8 who)
|
||||
{
|
||||
Bb64 const occ = pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK];
|
||||
Bb64 const occ = ~(pos->pieces[SIDE_WHITE][PIECE_EMPTY] & pos->pieces[SIDE_BLACK][PIECE_EMPTY]);
|
||||
|
||||
Bb64 const* p = pos->pieces[who];
|
||||
Bb64 t = 0ULL;
|
||||
|
||||
@@ -12,7 +12,6 @@ struct board {
|
||||
Side8 moving_side;
|
||||
bool castling_illegal[SIDE_COUNT][CASTLE_COUNT];
|
||||
Bb64 ep_targets;
|
||||
Bb64 occupied[SIDE_COUNT];
|
||||
|
||||
int halfmoves; /* FIXME: this duplicates the hist.length value */
|
||||
int fullmoves;
|
||||
@@ -44,6 +43,7 @@ struct board {
|
||||
.fullmoves = 1, \
|
||||
.pieces = { \
|
||||
[SIDE_WHITE] = { \
|
||||
[PIECE_EMPTY] = RANK_MASK_3 | RANK_MASK_4 | RANK_MASK_5 | RANK_MASK_6 | RANK_MASK_7 | RANK_MASK_8, \
|
||||
[PIECE_PAWN] = RANK_MASK_2, \
|
||||
[PIECE_ROOK] = SQMASK_A1 | SQMASK_H1, \
|
||||
[PIECE_KNIGHT] = SQMASK_B1 | SQMASK_G1, \
|
||||
@@ -52,6 +52,7 @@ struct board {
|
||||
[PIECE_KING] = SQMASK_E1, \
|
||||
}, \
|
||||
[SIDE_BLACK] = { \
|
||||
[PIECE_EMPTY] = RANK_MASK_1 | RANK_MASK_2 | RANK_MASK_3 | RANK_MASK_4 | RANK_MASK_5 | RANK_MASK_6, \
|
||||
[PIECE_PAWN] = RANK_MASK_7, \
|
||||
[PIECE_ROOK] = SQMASK_A8 | SQMASK_H8, \
|
||||
[PIECE_KNIGHT] = SQMASK_B8 | SQMASK_G8, \
|
||||
@@ -60,16 +61,6 @@ struct board {
|
||||
[PIECE_KING] = SQMASK_E8, \
|
||||
} \
|
||||
}, \
|
||||
.occupied = { \
|
||||
[SIDE_WHITE] = \
|
||||
RANK_MASK_2 | SQMASK_A1 | SQMASK_H1 | \
|
||||
SQMASK_B1 | SQMASK_G1 | SQMASK_C1 | \
|
||||
SQMASK_F1 | SQMASK_D1 | SQMASK_E1, \
|
||||
[SIDE_BLACK] = \
|
||||
RANK_MASK_7 | SQMASK_A8 | SQMASK_H8 | \
|
||||
SQMASK_B8 | SQMASK_G8| SQMASK_C8 | \
|
||||
SQMASK_F8| SQMASK_D8| SQMASK_E8, \
|
||||
}, \
|
||||
.hash = ~0ULL, \
|
||||
}, \
|
||||
.mailbox = { \
|
||||
@@ -156,13 +147,20 @@ static bool board_load_fen_unsafe(struct board* b, char const* fen_str)
|
||||
struct piece_side const p = piece_and_side_from_char[(uint8_t)ch];
|
||||
Bb64 const sq_mask = MASK_FROM_RF(ri, fi);
|
||||
b->pos.pieces[p.side][p.piece] |= sq_mask;
|
||||
b->pos.occupied[p.side] |= sq_mask;
|
||||
b->pos.pieces[p.side][PIECE_EMPTY] &= ~sq_mask;
|
||||
b->mailbox[SQ_FROM_RF(ri, fi)] = p.piece;
|
||||
}
|
||||
}
|
||||
(void)BUF_GETCHAR(fen); /* discard '/' or ' ' */
|
||||
}
|
||||
|
||||
b->pos.pieces[SIDE_WHITE][PIECE_EMPTY] = ~0ULL;
|
||||
b->pos.pieces[SIDE_BLACK][PIECE_EMPTY] = ~0ULL;
|
||||
for (Piece8 p = PIECE_BEGIN; p < PIECE_COUNT; ++p) {
|
||||
b->pos.pieces[SIDE_WHITE][PIECE_EMPTY] &= ~b->pos.pieces[SIDE_WHITE][p];
|
||||
b->pos.pieces[SIDE_BLACK][PIECE_EMPTY] &= ~b->pos.pieces[SIDE_BLACK][p];
|
||||
}
|
||||
|
||||
{ /* active color */
|
||||
char const ch = BUF_GETCHAR(fen);
|
||||
if (ch == 'w') {
|
||||
@@ -238,13 +236,6 @@ enum move_result {
|
||||
MR_CHECKMATE,
|
||||
};
|
||||
|
||||
struct move_undo {
|
||||
Piece8 captured_piece;
|
||||
Piece8 moved_piece;
|
||||
Sq8 captured_square;
|
||||
Sq8 moved_square;
|
||||
};
|
||||
|
||||
/* does not check validity */
|
||||
static enum move_result move_piece(struct pos* restrict pos,
|
||||
Side8 us,
|
||||
@@ -252,8 +243,6 @@ static enum move_result move_piece(struct pos* restrict pos,
|
||||
Piece8 mailbox[restrict static SQ_COUNT],
|
||||
struct move move)
|
||||
{
|
||||
struct move_undo undo;
|
||||
|
||||
//Side8 const us = pos->moving_side;
|
||||
Side8 const them = other_side(us);
|
||||
|
||||
@@ -277,7 +266,7 @@ static enum move_result move_piece(struct pos* restrict pos,
|
||||
do { \
|
||||
Bb64 const x = MASK_FROM_SQ(from) | MASK_FROM_SQ(to); \
|
||||
pos->pieces[side][piece] ^= x; \
|
||||
pos->occupied[side] ^= x; \
|
||||
pos->pieces[side][PIECE_EMPTY] ^= x; \
|
||||
pos->hash = tt_hash_update(pos->hash, from, side, piece); \
|
||||
pos->hash = tt_hash_update(pos->hash, to, side, piece); \
|
||||
mailbox[to] = piece; \
|
||||
@@ -288,7 +277,7 @@ static enum move_result move_piece(struct pos* restrict pos,
|
||||
do { \
|
||||
Bb64 const x = MASK_FROM_SQ(at); \
|
||||
pos->pieces[owner][piece] &= ~x; \
|
||||
pos->occupied[owner] &= ~x; \
|
||||
pos->pieces[owner][PIECE_EMPTY] |= x; \
|
||||
pos->hash = tt_hash_update(pos->hash, at, owner, piece); \
|
||||
hist->length = 0; \
|
||||
pos->halfmoves = 0; \
|
||||
@@ -298,7 +287,7 @@ static enum move_result move_piece(struct pos* restrict pos,
|
||||
do { \
|
||||
Bb64 const x = MASK_FROM_SQ(at); \
|
||||
pos->pieces[owner][piece] |= x; \
|
||||
pos->occupied[owner] |= x; \
|
||||
pos->pieces[owner][PIECE_EMPTY] &= ~x; \
|
||||
pos->hash = tt_hash_update(pos->hash, at, owner, piece); \
|
||||
mailbox[at] = piece; \
|
||||
pos->halfmoves = 0; \
|
||||
@@ -325,7 +314,7 @@ static enum move_result move_piece(struct pos* restrict pos,
|
||||
else {
|
||||
POS_MOVE(us, from_piece, move.from, move.to);
|
||||
/* capture */
|
||||
if (to_mask & pos->occupied[them]) {
|
||||
if (to_mask & ~pos->pieces[them][PIECE_EMPTY]) {
|
||||
POS_REMOVE(them, to_piece, move.to);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,23 +22,7 @@ struct move move_make(struct pos const* restrict pos,
|
||||
(void)piece;
|
||||
(void)pos;
|
||||
(void)add_attr;
|
||||
#if 0
|
||||
Side8 const us = pos->moving_side;
|
||||
Side8 const them = other_side(us);
|
||||
Bb64 const their_occ = pos->occupied[them];
|
||||
Bb64 const tomask = MASK_FROM_SQ(to);
|
||||
Bb64 const finishline = (us == SIDE_WHITE ? RANK_MASK_8 : RANK_MASK_1);
|
||||
|
||||
uint8_t attr = 0ULL;
|
||||
#define MASK_IF8(x) ((~(uint8_t)0U) + (uint8_t)!(x))
|
||||
attr |= MATTR_CAPTURE & MASK_IF8(tomask & their_occ);
|
||||
attr |= MATTR_CAPTURE & MASK_IF8((piece == PIECE_PAWN) && tomask & pos->ep_targets);
|
||||
attr |= MATTR_PROMOTE & MASK_IF8((piece == PIECE_PAWN) && (tomask & finishline));
|
||||
attr |= add_attr;
|
||||
#undef MASK_IF8
|
||||
|
||||
return (struct move){.from = from, .to = to, .attr = attr};
|
||||
#endif
|
||||
return (struct move){.from = from, .to = to, .attr = add_attr};
|
||||
}
|
||||
#define MOVE_MAX 128
|
||||
@@ -63,8 +47,8 @@ static void all_pseudolegal_from_piece(struct pos const* restrict pos,
|
||||
|
||||
Side8 them = other_side(us);
|
||||
|
||||
Bb64 const our_occ = pos->occupied[us];
|
||||
Bb64 const all_occ = pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK];
|
||||
Bb64 const our_occ = ~pos->pieces[us][PIECE_EMPTY];
|
||||
Bb64 const all_occ = ~(pos->pieces[SIDE_WHITE][PIECE_EMPTY] & pos->pieces[SIDE_BLACK][PIECE_EMPTY]);
|
||||
|
||||
if (type == MG_CHECKS) {
|
||||
allowed &= non_pawn_piece_attacks(piece, pos->pieces[them][PIECE_KING], all_occ);
|
||||
@@ -93,7 +77,7 @@ static void all_pseudolegal_pawn_moves_##side(struct pos const* restrict pos,\
|
||||
size_t* restrict out_count,\
|
||||
struct move out[restrict static MOVE_MAX])\
|
||||
{\
|
||||
Bb64 const all_occ = pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK];\
|
||||
Bb64 const all_occ = ~(pos->pieces[SIDE_WHITE][PIECE_EMPTY] & pos->pieces[SIDE_BLACK][PIECE_EMPTY]);\
|
||||
\
|
||||
if (type == MG_CHECKS) {\
|
||||
allowed &= pawn_attacks_##opp_side(pos->pieces[other_side(side_enum)][PIECE_KING]);\
|
||||
@@ -127,7 +111,7 @@ static void all_pseudolegal_pawn_attacks_##side(struct pos const* restrict pos,\
|
||||
size_t* restrict out_count,\
|
||||
struct move out[restrict static MOVE_MAX])\
|
||||
{\
|
||||
Bb64 const their_occ = pos->occupied[other_side(side_enum)];\
|
||||
Bb64 const their_occ = ~pos->pieces[other_side(side_enum)][PIECE_EMPTY];\
|
||||
\
|
||||
if (type == MG_CHECKS) {\
|
||||
allowed &= pawn_attacks_##opp_side(pos->pieces[other_side(side_enum)][PIECE_KING]);\
|
||||
@@ -177,7 +161,7 @@ static void all_pseudolegal_moves(struct pos const* restrict pos,
|
||||
|
||||
Bb64 const their_threats = all_threats_from_side(pos, them);
|
||||
|
||||
Bb64 const their_occ = pos->occupied[them];
|
||||
Bb64 const their_occ = ~pos->pieces[them][PIECE_EMPTY];
|
||||
|
||||
Bb64 allowed;
|
||||
if (type == MG_CAPTURES) {
|
||||
@@ -243,7 +227,7 @@ static void all_pseudolegal_moves(struct pos const* restrict pos,
|
||||
/* castling */
|
||||
if (!chk && type != MG_CAPTURES) {
|
||||
bool can_castle_kingside, can_castle_queenside;
|
||||
Bb64 const blocked = pos->occupied[SIDE_WHITE] | pos->occupied[SIDE_BLACK] | their_threats;
|
||||
Bb64 const blocked = ~(pos->pieces[SIDE_WHITE][PIECE_EMPTY] & pos->pieces[SIDE_BLACK][PIECE_EMPTY]) | their_threats;
|
||||
if (us == SIDE_WHITE) {
|
||||
can_castle_kingside = !(blocked & (SQMASK_F1 | SQMASK_G1))
|
||||
&& (pos->pieces[us][PIECE_ROOK] & SQMASK_H1)
|
||||
|
||||
@@ -195,6 +195,7 @@ static char const* side_str[SIDE_COUNT] = {
|
||||
/* https://en.wikipedia.org/wiki/X_macro */
|
||||
/* enum value white char white unicode black char black unicode */
|
||||
#define PIECES \
|
||||
X(PIECE_EMPTY, 0.0f, ' ', ' ', ' ', ' ') \
|
||||
X(PIECE_PAWN, 1.0f, 'P', 0x2659, 'p', 0x265F) \
|
||||
X(PIECE_KNIGHT, 3.1f, 'N', 0x2658, 'n', 0x265E) \
|
||||
X(PIECE_BISHOP, 3.2f, 'B', 0x2657, 'b', 0x265D) \
|
||||
@@ -207,8 +208,8 @@ typedef enum piece : uint8_t {
|
||||
#define X(e, v, wc, wu, bc, bu) e,
|
||||
PIECES
|
||||
PIECE_COUNT,
|
||||
PIECE_BEGIN = 0,
|
||||
PIECE_POISONED, /* used as default undefined value in debug builds */
|
||||
PIECE_BEGIN = PIECE_PAWN,
|
||||
PIECE_POISONED, /* used as undefined value in debug builds */
|
||||
#undef X
|
||||
} Piece8;
|
||||
|
||||
@@ -273,6 +274,25 @@ struct move {
|
||||
#define APPEAL_MAX UINT8_MAX
|
||||
uint8_t appeal;
|
||||
};
|
||||
|
||||
/*
|
||||
* Move32 layout:
|
||||
* f (from piece): 3 bits
|
||||
* F (from square): 6 bits
|
||||
* t (to piece): 3 bits
|
||||
* T (to square): 6 bits
|
||||
* p (promotion): ? bits (likely 3)
|
||||
* [x,x,x,x,x,x,x,x,x,x,x,p,p,p,T,T,T,T,T,T,t,t,t,F,F,F,F,F,F,f,f,f]
|
||||
* */
|
||||
|
||||
typedef uint32_t Move32;
|
||||
|
||||
#define MOVE_FROM_PIECE(m) (m & 0b000000000000000000111)
|
||||
#define MOVE_FROM_SQUARE(m) (m & 0b000000000000111111000)
|
||||
#define MOVE_TO_PIECE(m) (m & 0b000000000111000000000)
|
||||
#define MOVE_TO_SQUARE(m) (m & 0b000111111000000000000)
|
||||
#define MOVE_PROMOTION(m) (m & 0b111000000000000000000)
|
||||
|
||||
_Static_assert(sizeof(struct move) == 4,
|
||||
"this static assuming is here to check when sizeof(move) changes");
|
||||
|
||||
|
||||
23
engine.h
23
engine.h
@@ -36,14 +36,17 @@ static void move_compute_appeal(struct move* restrict m,
|
||||
Side8 them = other_side(us);
|
||||
Piece8 const atk = mailbox[m->from];
|
||||
|
||||
uint8_t n = 1;
|
||||
if (MASK_FROM_SQ(m->to) & pos->occupied[them]) {
|
||||
uint8_t n = 0;
|
||||
if ((MASK_FROM_SQ(m->to) & pos->pieces[them][PIECE_EMPTY]) == 0) {
|
||||
n += (uint8_t)piece_value[mailbox[m->to]];
|
||||
}
|
||||
|
||||
uint8_t mmv_lva_bonus = (uint8_t)(16.0f*(float)n - piece_value[atk]);
|
||||
|
||||
m->appeal = mmv_lva_bonus;
|
||||
/* TODO: remove branch */
|
||||
if (n) {
|
||||
m->appeal = (uint8_t)(16.0f*(float)n - piece_value[atk]);
|
||||
} else {
|
||||
m->appeal = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static float board_score_heuristic(struct pos const* pos)
|
||||
@@ -52,9 +55,8 @@ static float board_score_heuristic(struct pos const* pos)
|
||||
eventually flipping the sign based on `pos` */
|
||||
float score = 0.0f;
|
||||
|
||||
Bb64 const occw = pos->occupied[SIDE_WHITE];
|
||||
Bb64 const occb = pos->occupied[SIDE_BLACK];
|
||||
Bb64 const occall = occw | occb;
|
||||
Bb64 const occw = ~pos->pieces[SIDE_WHITE][PIECE_EMPTY];
|
||||
Bb64 const occb = ~pos->pieces[SIDE_BLACK][PIECE_EMPTY];
|
||||
|
||||
enum game_progress const gp = endgameness(pos);
|
||||
|
||||
@@ -172,8 +174,9 @@ float quiesce(struct pos const* pos,
|
||||
|
||||
all_pseudolegal_moves(pos, MG_CAPTURES, us, &move_count, moves);
|
||||
if (move_count == 0) {
|
||||
return -(SCORE_CHECKMATE + (float)depth);
|
||||
return score;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < move_count; ++i) {
|
||||
move_compute_appeal(&moves[i], pos, us, mailbox);
|
||||
}
|
||||
@@ -181,7 +184,7 @@ float quiesce(struct pos const* pos,
|
||||
while (move_count) {
|
||||
struct move m = moves_linear_search(moves, &move_count);
|
||||
|
||||
assuming((pos->occupied[them] | pos->ep_targets) & MASK_FROM_SQ(m.to));
|
||||
assuming((~pos->pieces[them][PIECE_EMPTY] | pos->ep_targets) & MASK_FROM_SQ(m.to));
|
||||
|
||||
struct pos poscpy = *pos;
|
||||
|
||||
|
||||
4
sys.h
4
sys.h
@@ -20,8 +20,8 @@ static size_t g_buf_len = 0;
|
||||
|
||||
static void* sys_mmap_anon_shared(size_t size, int, int)
|
||||
{
|
||||
/* FIXME: this program relies on very few memory allocations, a simple bump
|
||||
* allocator works for now, but will cause memory leaks in the future */
|
||||
/* FIXME: this program relies on very few memory allocations, a simple bump
|
||||
* allocator works for now, but will cause memory leaks in the future */
|
||||
size = (size + 7ULL) & ~7ULL;
|
||||
|
||||
if (g_buf_len + size > sizeof g_buf) {
|
||||
|
||||
Reference in New Issue
Block a user