Merge branch 'hash'

This commit is contained in:
2024-05-21 07:53:55 +02:00
14 changed files with 558 additions and 53 deletions

View File

@@ -55,8 +55,9 @@ CPPFILES := $(SRC:.c=.i) $(TSTSRC:.c=.i)
##################################### pre-processor flags
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
CPPFLAGS += -DNDEBUG # assert
CPPFLAGS += -DNDEBUG # assert (unused)
CPPFLAGS += -DWARN_ON # brlib bug.h
CPPFLAGS += -DBUG_ON # brlib bug.h
#CPPFLAGS += -DDEBUG # global - unused
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
@@ -68,6 +69,9 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
# fen.c
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
# hash.c
#CPPFLAGS += -HASH_VERIFY # chk zobrist consistency
# attack.c
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
#CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
@@ -78,9 +82,6 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams
# Never comment this one !
CPPFLAGS += -DBUG_ON # brlib bug.h
# remove extraneous spaces (due to spaces before comments)
CPPFLAGS := $(strip $(CPPFLAGS))
@@ -342,12 +343,12 @@ TEST += movedo-test perft-test
PIECE_OBJS := piece.o
FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \
hyperbola-quintessence.o attack.o
hyperbola-quintessence.o attack.o hash.o init.o
BB_OBJS := $(FEN_OBJS)
MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o
ATTACK_OBJS := $(MOVEGEN_OBJS)
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o
PERFT_OBJS := $(MOVEDO_OBJS) search.o misc.o
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o misc.o
PERFT_OBJS := $(MOVEDO_OBJS) search.o
TEST := $(addprefix $(BINDIR)/,$(TEST))

2
brlib

Submodule brlib updated: 8ff163dcf5...7bedfddfba

46
scripts/fetch-all.sh Executable file
View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
origin=origin
declare -a remotes local
readarray -t remotes < <(git remote)
declare -A aremotes alocal_b
# fetch all remotes
for remote in "${remotes[@]}"; do
aremotes["$remote"]=1
echo doing git fetch -a "$remote"
done
# get local branches
readarray -t local_b < <(git for-each-ref --format='%(refname:short)' refs/heads/)
# build local ref array
for ref in "${local_b[@]}"; do
alocal_b[$ref]=1
done
readarray -t orig_b < <(git for-each-ref --format='%(refname:short)' \
refs/remotes/"$origin"/)
declare -p remotes
#declare -p aremotes
declare -p local_b orig_b
# find-out missing local branches
for remote_b in "${orig_b[@]}"; do
short=${remote_b#"$origin"/};
echo "$remote_b -> $short ${alocal_b[$short]}"
if ! [[ -v alocal_b[$short] ]]; then
echo git switch -t "$remote_b"
fi
done
#git remote | xargs -n 1 git fetch -a

View File

@@ -178,4 +178,6 @@ double clock_elapsed_sec(mclock_t *clock);
void rand_init(u64 seed);
u64 rand64(void);
void init_all(void);
#endif /* _CHESSDEFS_H */

View File

@@ -184,6 +184,8 @@ pos_t *fen2pos(pos_t *pos, const char *fen)
piece, PIECE(piece), COLOR(piece));
# endif
pos_set_sq(&tmppos, sq_make(file, rank), piece);
if (PIECE(piece) == KING)
tmppos.king[COLOR(piece)] = sq_make(file, rank);
file++;
} else { /* error */
err_line = __LINE__, err_char = *cur, err_pos = cur - fen;
@@ -250,8 +252,10 @@ end:
}
if (fen_check(&tmppos) < 0)
return NULL;
tmppos.key = zobrist_calc(&tmppos);
if (!pos)
pos = pos_dup(&tmppos);
pos = pos_new();
pos_copy(&tmppos, pos);
//puts("prout 1");
//pos_print_raw(&tmppos, 1);
//puts("prout 2");

240
src/hash.c Normal file
View File

@@ -0,0 +1,240 @@
/* hash.c - hash management.
*
* Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#include <string.h>
#include <brlib.h>
#include <bitops.h>
#include "chessdefs.h"
#include "util.h"
#include "position.h"
#include "piece.h"
#include "hash.h"
u64 zobrist_pieces[16][64];
u64 zobrist_castling[4 * 4 + 1];
u64 zobrist_turn; /* for black, XOR each ply */
u64 zobrist_ep[9]; /* 0-7: ep file, 8: SQUARE_NONE */
hasht_t hash_tt; /* main transposition table */
/**
* zobrist_init() - initialize zobrist tables.
*
* Initialize all zobrist random bitmasks. Must be called before any other
* zobrist function, and can be called once only (further calls will be ignored).
*/
void zobrist_init(void)
{
static bool called = false;
if (!called) {
called = true;
for (color_t c = WHITE; c <= BLACK; ++c) {
for (piece_type_t p = PAWN; p <= KING; ++p)
for (square_t sq = A1; sq <= H8; ++sq)
zobrist_pieces[MAKE_PIECE(p, c)][sq] = rand64();
}
for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c)
zobrist_castling[c] = rand64();
for (file_t f = FILE_A; f <= FILE_H; ++f)
zobrist_ep[f] = rand64();
zobrist_ep[8] = 0; /* see EP_ZOBRIST_IDX macro */
zobrist_turn = rand64();
}
}
/**
* zobrist_calc() - calculate a position zobrist hash.
* @pos: &position
*
* Normally, Zobrist keys are incrementally calculated when doing or
* undoing a move.
* This function should normally only be called:
* - When starting a new position
* - To verify incremental Zobrist calculation is correct
*
* @return: @pos Zobrist key
*/
key_t zobrist_calc(pos_t *pos)
{
key_t key = 0;
if (pos->turn == BLACK)
key ^= zobrist_turn;
for (color_t c = WHITE; c <= BLACK; ++c) {
for (piece_type_t pt = PAWN; pt <= KING; ++pt) {
piece_t piece = MAKE_PIECE(pt, c);
bitboard_t bb = pos->bb[c][pt];
while (bb) {
square_t sq = bb_next(&bb);
key ^= zobrist_pieces[piece][sq];
}
}
}
key ^= zobrist_castling[pos->castle];
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
return key;
}
/**
* zobrist_verify() - verify current position Zobrist key.
* @pos: &position
*
* Verify that position Zobrist key matches a full Zobrist calculation.
* This function cannot be called if ZOBRIST_VERIFY is not set.
*
* @return: True if Zobrist key is OK.
*/
#ifdef ZOBRIST_VERIFY
bool zobrist_verify(pos_t *pos)
{
key_t diff, key = zobrist_calc(pos);
if (pos->key == key)
return true;
printf("key verify: cur=%#lx != %#lx\n", pos->key, key);
/* try to find-out the key in different zobrist tables */
diff = pos->key ^ key;
for (color_t c = WHITE; c <= BLACK; ++c) {
for (piece_type_t p = PAWN; p <= KING; ++p)
for (square_t sq = A1; sq <= H8; ++sq)
if (diff == zobrist_pieces[MAKE_PIECE(p, c)][sq]) {
warn(true, "zobrist difference is piece:[%s][%s]\n",
piece_to_fen(MAKE_PIECE(p, c)), sq_to_string(sq));
goto end;
}
}
for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c)
if (diff == zobrist_castling[c]) {
warn(true, "zobrist difference is castling:[%d]\n", c);
goto end;
}
for (file_t f = FILE_A; f <= FILE_H; ++f)
if (diff == zobrist_ep[f]) {
warn(true, "zobrist difference is ep:[%d]\n", f);
goto end;
}
if (diff == zobrist_turn) {
warn(true, "zobrist difference is turn\n");
goto end;
}
warn(true, "zobrist diff %lx is unknown\n", diff);
end:
bug_on(false);
}
#endif
/**
* hash_create() - hashtable creation.
* @sizemb: s32 size of hash table in Mb
*
* Create a hash table of max @sizemb (or HASH_SIZE_MBif @sizemb <= 0) Mb size.
* This function must be called at startup.
*
* The number of bucket_t entries fitting in @sizemb is calculated, and rounded
* (down) to a power of 2.
* This means the actual size could be lower than @sizemb (nearly halved in
* worst case).
*
* If transposition hashtable already exists and new size would not change,
* the old one is cleared.
* If transposition hashtable already exists and new size is different,
* the old one is destroyed first (old data is not preserved).
*
* TODO:
* - Rebuild old hashtable data ?
*
* @return: hash table size in Mb. If memory allocation fails, the function does
* not return.
*/
int hash_create(s32 sizemb)
{
size_t bytes, target_nbuckets;
u32 nbits;
static_assert(sizeof(hentry_t) == 16, "fatal: hentry_t size != 16");
//printf("mb = %'7u ", sizemb);
/* adjust tt size */
if (sizemb <= 0)
sizemb = HASH_SIZE_DEFAULT;
sizemb = clamp(sizemb, HASH_SIZE_MIN, HASH_SIZE_MAX);
//printf("-> %'6d ", sizemb);
bytes = sizemb * 1024ull * 1024ull; /* bytes wanted */
target_nbuckets = bytes / sizeof(bucket_t); /* target buckets */
nbits = msb64(target_nbuckets); /* adjust to power of 2 */
if (hash_tt.nbits != nbits) {
if (hash_tt.nbits)
hash_delete();
hash_tt.nbits = nbits;
hash_tt.nbuckets = BIT(hash_tt.nbits);
hash_tt.nkeys = hash_tt.nbuckets * NBUCKETS;
hash_tt.bytes = hash_tt.nbuckets * sizeof(bucket_t);
hash_tt.mb = hash_tt.bytes / 1024 / 1024;
hash_tt.mask = -1ull >> (64 - nbits);
hash_tt.keys = safe_malloc(hash_tt.bytes);
//printf("bits=%2d size=%'15lu/%'6d Mb/%'14lu buckets ",
// hash_tt.nbits, hash_tt.bytes, hash_tt.mb, hash_tt.nbuckets);
//printf("mask=%9x\n", hash_tt.mask);
}
//else {
// printf("unchanged (cleared)\n");
//}
/* attention - may fail ! */
hash_clear();
return hash_tt.nbits;
}
/**
* hash_clear() - clear hashtable data.
*
* Reset hashtable entries (if available) and statistic information.
*/
void hash_clear()
{
if (hash_tt.keys)
memset(hash_tt.keys, 0, hash_tt.bytes);
hash_tt.used_buckets = 0;
hash_tt.used_keys = 0;
hash_tt.collisions = 0;
}
/**
* hash_delete() - delete hashtable data.
*
* free hashtable data.
*/
void hash_delete()
{
if (hash_tt.keys)
safe_free(hash_tt.keys);
memset(&hash_tt, 0, sizeof(hash_tt));
}

104
src/hash.h Normal file
View File

@@ -0,0 +1,104 @@
/* hash.h - hash management.
*
* Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#ifndef HASH_H
#define HASH_H
#include <assert.h>
#include "chessdefs.h"
#define NBUCKETS 4 /* buckets per hash table entry */
#define HASH_SIZE_DEFAULT 32 /* default: 32Mb */
#define HASH_SIZE_MIN 4
#define HASH_SIZE_MAX 32768 /* 32Gb */
#define key_t u64 /* cannot use typedef for key_t */
/**
* hentry_t: hashtable bucket.
*
* Size should be exactly 16 bytes. If impossible to fit necessary data in
* 16 bytes in future, it should be updated to be exactly 32 bytes.
*/
typedef struct {
key_t key; /* zobrist */
union {
u64 data;
struct {
u16 depth; /* ply in search */
s16 eval;
u16 move;
u8 flags; /* maybe for locking, etc... */
u8 filler;
};
};
} hentry_t;
typedef struct {
hentry_t buckets[NBUCKETS];
} bucket_t;
typedef struct {
bucket_t *keys; /* &hashtable entries */
/* memory size in bytes/mb */
size_t bytes;
u32 mb;
/* size in buckets/keys */
size_t nbuckets;
size_t nkeys; /* nbuckets * NBUCKETS */
/* internal representation */
u32 nbits; /* #buckets in bits, power of 2 */
u32 mask; /* nbuckets - 1, key mask */
/* stats - unsure about usage */
size_t used_buckets;
size_t used_keys;
u64 collisions;
} hasht_t;
/* hack:
* ep zobrist key index is 0-7 for each en-passant file, 8 for SQUARE_NONE.
* To transform :
* - ep == 64 (SQUARE_NONE) to id = 8
* - ep == 0~63 to idx = sq_file(ep), i.e. (ep & 7)
* we use the formula:
* idx = ( ( ep & SQUARE_NONE ) >> 3 ) | sq_file(ep);
*/
#define EP_ZOBRIST_IDX(ep) ( ( (ep) >> 3 ) | sq_file(ep) )
extern key_t zobrist_pieces[16][64];
extern key_t zobrist_castling[4 * 4 + 1];
extern key_t zobrist_turn; /* for black, XOR each ply */
extern key_t zobrist_ep[9]; /* 0-7: ep file, 8: SQUARE_NONE */
extern hasht_t hash_tt; /* main transposition table */
void zobrist_init(void);
key_t zobrist_calc(pos_t *pos);
#ifdef ZOBRIST_VERIFY
bool zobrist_verify(pos_t *pos);
#else
#define zobrist_verify(p) true
#endif
int hash_create(int Mb);
void hash_clear(void);
void hash_delete(void);
#endif /* HASH_H */

View File

@@ -21,7 +21,7 @@
#include "hash.h"
void init_all()
void init_all(void)
{
/* for printf() numeric thousands separator */
setlocale(LC_NUMERIC, "");
@@ -37,6 +37,6 @@ void init_all()
/* zobrist tables & default tt hashtable */
zobrist_init();
hash_create(HASH_DEFAULT);
hash_create(HASH_SIZE_DEFAULT);
}

View File

@@ -23,6 +23,7 @@
#include "move.h"
#include "position.h"
#include "move-do.h"
#include "hash.h"
/**
* move_do() - do move.
@@ -39,8 +40,12 @@
* - castling
* - en-passant
* - captured piece (excl. en-passant)
* - tt hash values are updated for:
* - side-to-move
* - en-passant
* - castling rights.
*
* @return: pos.
* @return: updated pos.
*/
pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
{
@@ -56,6 +61,12 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
piece_type_t ptype = PIECE(piece);
piece_t new_piece = piece;
int up = sq_up(us);
key_t key = pos->key;
/* update key: switch turn, reset castling and ep */
key ^= zobrist_turn;
key ^= zobrist_castling[pos->castle];
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
++pos->clock_50;
++pos->plycount;
@@ -74,6 +85,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
pos->clock_50 = 0;
//pos->captured = pos->board[to]; /* save capture info */
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
key ^= zobrist_pieces[captured][to];
pos_clr_sq(pos, to); /* clear square */
} else if (is_castle(move)) { /* handle rook move */
square_t rookfrom, rookto;
@@ -84,20 +96,26 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
rookfrom = sq_rel(A1, us);
rookto = sq_rel(D1, us);
}
key ^= zobrist_pieces[pos->board[rookfrom]][rookto] ^
zobrist_pieces[pos->board[rookfrom]][rookfrom];
pos_set_sq(pos, rookto, pos->board[rookfrom]);
pos_clr_sq(pos, rookfrom);
pos->castle = clr_castle(pos->castle, us);
//pos->castle = clr_castle(pos->castle, us);
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
pos->clock_50 = 0;
if (is_dpush(move)) /* if pawn double push, set e.p. */
if (is_dpush(move)) { /* if pawn double push, set e.p. */
pos->en_passant = from + up;
else if (is_enpassant(move)) { /* clear grabbed pawn */
/* update ep key */
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
} else if (is_enpassant(move)) { /* clear grabbed pawn */
square_t grabbed = to - up;
key ^= zobrist_pieces[pos->board[grabbed]][grabbed];
pos_clr_sq(pos, grabbed);
}
}
pos_clr_sq(pos, from); /* always clear "from" and set "to" */
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
pos_clr_sq(pos, from); /* clear "from" and set "to" */
pos_set_sq(pos, to, new_piece);
if (ptype == KING)
@@ -119,7 +137,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
else if (from == rel_h1)
pos->castle = clr_oo(pos->castle, us);
}
if (can_castle(pos->castle, them)) { /* do we save time with this test ? */
if (can_castle(pos->castle, them)) {
square_t rel_a8 = sq_rel(A8, us);
square_t rel_h8 = sq_rel(H8, us);
if (to == rel_a8)
@@ -128,6 +146,13 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
pos->castle = clr_oo(pos->castle, them);
}
/* update castle key */
key ^= zobrist_castling[pos->castle];
pos->key = key;
bug_on(zobrist_verify(pos) == false);
return pos;
}
@@ -143,9 +168,15 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
piece_type_t ptype = PIECE(piece);
piece_t new_piece = piece;
int up = sq_up(us);
key_t key = pos->key;
*state = pos->state; /* save irreversible changes */
/* update key: switch turn, reset castling and ep */
key ^= zobrist_turn;
key ^= zobrist_castling[pos->castle];
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
++pos->clock_50;
++pos->plycount;
pos->en_passant = SQUARE_NONE;
@@ -163,6 +194,7 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
pos->clock_50 = 0;
//pos->captured = pos->board[to]; /* save capture info */
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
key ^= zobrist_pieces[captured][to];
pos_clr_sq(pos, to); /* clear square */
} else if (is_castle(move)) { /* handle rook move */
square_t rookfrom, rookto;
@@ -173,20 +205,27 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
rookfrom = sq_rel(A1, us);
rookto = sq_rel(D1, us);
}
key ^= zobrist_pieces[pos->board[rookfrom]][rookto];
key ^= zobrist_pieces[pos->board[rookfrom]][rookfrom];
pos_set_sq(pos, rookto, pos->board[rookfrom]);
pos_clr_sq(pos, rookfrom);
pos->castle = clr_castle(pos->castle, us);
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
pos->clock_50 = 0;
if (is_dpush(move)) /* if pawn double push, set e.p. */
if (is_dpush(move)) { /* if pawn double push, set e.p. */
pos->en_passant = from + up;
else if (is_enpassant(move)) { /* clear grabbed pawn */
/* update key */
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
} else if (is_enpassant(move)) { /* clear grabbed pawn */
square_t grabbed = to - up;
key ^= zobrist_pieces[pos->board[grabbed]][grabbed];
pos_clr_sq(pos, grabbed);
}
}
pos_clr_sq(pos, from); /* always clear "from" and set "to" */
key ^= zobrist_pieces[piece][from];
key ^= zobrist_pieces[new_piece][to];
pos_clr_sq(pos, from); /* clear "from" and set "to" */
pos_set_sq(pos, to, new_piece);
if (ptype == KING)
@@ -208,7 +247,7 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
else if (from == rel_h1)
pos->castle = clr_oo(pos->castle, us);
}
if (can_castle(pos->castle, them)) { /* do we save time with this test ? */
if (can_castle(pos->castle, them)) {
square_t rel_a8 = sq_rel(A8, us);
square_t rel_h8 = sq_rel(H8, us);
if (to == rel_a8)
@@ -217,6 +256,13 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
pos->castle = clr_oo(pos->castle, them);
}
/* update castle key */
key ^= zobrist_castling[pos->castle];
pos->key = key;
bug_on(zobrist_verify(pos) == false);
return pos;
}

View File

@@ -62,6 +62,21 @@ pos_t *pos_dup(const pos_t *pos)
return newpos;
}
/**
* pos_copy() - copy a position into another one.
* @from: &position to duplicate.
* @to: &destination position.
*
* Return a copy of @from into @to.
*
* @Return: @to.
*/
pos_t *pos_copy(const pos_t *from, pos_t *to)
{
*to = *from;
return to;
}
/**
* pos_del() - delete a position.
* @pos: &position.
@@ -87,6 +102,7 @@ pos_t *pos_clear(pos_t *pos)
pos->turn = WHITE;
/* move_do/undo position state */
pos->key = 0;
pos->en_passant = SQUARE_NONE;
pos->castle = 0;
pos->clock_50 = 0;
@@ -341,6 +357,7 @@ bool pos_ok(const pos_t *pos, const bool strict)
# define BUG_ON
# undef WARN_ON
# define WARN_ON
# include <bug.h>
/* pawns on 1st ot 8th rank */
error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &

View File

@@ -16,11 +16,13 @@
#include <stdint.h>
#include "brlib.h"
#include "bitops.h"
#include "struct-group.h"
#include <brlib.h>
#include <bitops.h>
#include <struct-group.h>
#include <bug.h>
#include "chessdefs.h"
#include "hash.h"
#include "bitboard.h"
#include "piece.h"
#include "move.h"
@@ -41,6 +43,7 @@ typedef struct __pos_s {
* This allows a memcpy on this data (to save/restore position state).
*/
struct_group_tagged(state_s, state,
key_t key;
square_t en_passant;
castle_rights_t castle;
int clock_50;
@@ -72,11 +75,16 @@ static __always_inline void pos_set_sq(pos_t *pos, square_t square, piece_t piec
{
color_t color = COLOR(piece);
piece_type_t type = PIECE(piece);
bug_on(pos->board[square] != EMPTY);
pos->board[square] = piece;
pos->bb[color][type] |= BIT(square);
pos->bb[color][ALL_PIECES] |= BIT(square);
if (type == KING)
pos->king[color] = square;
//if (type == KING)
// pos->king[color] = square;
//pos->key ^= zobrist_pieces[piece][square];
}
/**
@@ -91,11 +99,16 @@ static __always_inline void pos_clr_sq(pos_t *pos, square_t square)
piece_t piece = pos->board[square];
piece_type_t type = PIECE(piece);
color_t color = COLOR(piece);
bug_on(pos->board[square] == EMPTY);
//pos->key ^= zobrist_pieces[piece][square];
pos->board[square] = EMPTY;
pos->bb[color][type] &= ~BIT(square);
pos->bb[color][ALL_PIECES] &= ~BIT(square);
if (type == KING)
pos->king[color] = SQUARE_NONE;
//if (type == KING)
// pos->king[color] = SQUARE_NONE;
}
/**
@@ -156,6 +169,7 @@ static __always_inline int pos_between_count(const pos_t *pos,
pos_t *pos_new();
pos_t *pos_dup(const pos_t *pos);
pos_t *pos_copy(const pos_t *from, pos_t *to);
void pos_del(pos_t *pos);
pos_t *pos_clear(pos_t *pos);
bool pos_cmp(const pos_t *pos1, const pos_t *pos2);

View File

@@ -60,7 +60,13 @@ u64 perft(pos_t *pos, int depth, int ply, bool output)
nodes++;
} else {
move_do(pos, *move);
subnodes = perft(pos, depth - 1, ply + 1, output);
if (depth == 2) {
movelist_t movelist2;
pos_set_checkers_pinners_blockers(pos);
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
} else {
subnodes = perft(pos, depth - 1, ply + 1, output);
}
if (output && ply == 1) {
char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes);
@@ -105,7 +111,13 @@ u64 perft_test(pos_t *pos, int depth, int ply, bool output)
nodes++;
} else {
move_do2(pos, *move, &state);
subnodes = perft(pos, depth - 1, ply + 1, output);
if (depth == 2) {
movelist_t movelist2;
pos_set_checkers_pinners_blockers(pos);
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
} else {
subnodes = perft_test(pos, depth - 1, ply + 1, output);
}
if (output && ply == 1) {
char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes);

View File

@@ -32,10 +32,7 @@ int main(int __unused ac, __unused char**av)
movelist_t pseudo;
move_t move;
setlinebuf(stdout); /* line-buffered stdout */
bitboard_init();
hyperbola_init();
init_all();
while ((fen = next_fen(MOVEDO))) {
test_line = cur_line();

View File

@@ -235,16 +235,16 @@ int main(int __unused ac, __unused char**av)
int i = 0, test_line;
u64 sf_count = 0, my_count;
char *fen;
pos_t *pos;
pos_t *pos = NULL, *fenpos;
pos_t *fishpos = pos_new();
movelist_t fishmoves;
//move_t move;
FILE *outfd = NULL;
struct {
s64 count, ms;
s64 minlps, maxlps;
int skipped;
} res[2] = {
} res[3] = {
{ .minlps=LONG_MAX },
{ .minlps=LONG_MAX },
{ .minlps=LONG_MAX },
};
@@ -271,34 +271,47 @@ int main(int __unused ac, __unused char**av)
return usage(*av);
}
}
//if (ac > 1)
// depth = atoi(av[1]);
//if (ac > 2)
// run = atoi(av[2]) & 3;
printf("depth = %d run = %x sf = %s\n", depth, run, sf_run? "true": "false");
printf("perft: depth = %d run = %x stockfish = %s\n",
depth, run, sf_run? "true": "false");
init_all();
if (!run)
exit(0);
setlocale(LC_NUMERIC, "");
setlinebuf(stdout); /* line-buffered stdout */
if (sf_run)
outfd = open_stockfish();
bitboard_init();
hyperbola_init();
CLOCK_DEFINE(clock, CLOCK_PROCESS);
CLOCK_DEFINE(clock, CLOCK_MONOTONIC);
while ((fen = next_fen(PERFT | MOVEDO))) {
test_line = cur_line();
if (!(pos = fen2pos(NULL, fen))) {
if (!(fenpos = fen2pos(pos, fen))) {
printf("wrong fen %d: [%s]\n", i, fen);
continue;
}
if (sf_run)
pos = fenpos;
if (sf_run) {
clock_start(&clock);
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
// savepos = pos_dup(pos);
ms = clock_elapsed_ms(&clock);
if (!ms) {
res[2].skipped++;
lps = 0;
} else {
lps = sf_count * 1000l / ms;
res[2].ms += ms;
res[2].count += sf_count;
if (lps > res[2].maxlps)
res[2].maxlps = lps;
if (lps < res[2].minlps)
res[2].minlps = lps;
}
printf("SF : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
test_line, sf_count, ms,
lps,
fen);
}
if (run & 1) {
clock_start(&clock);
@@ -357,11 +370,20 @@ int main(int __unused ac, __unused char**av)
}
printf("\n");
// pos_del(savepos);
pos_del(pos);
i++;
/* to run first test only */
// exit(0);
}
pos_del(pos);
if (sf_run) {
if (!res[2].ms)
res[2].ms = 1;
printf("total SF %'lums %'lums lps=%'lu min=%'lu max=%'lu (skipped %d)\n",
res[2].count, res[2].ms,
res[2].count * 1000l / res[2].ms,
res[2].minlps, res[2].maxlps,
res[2].skipped);
}
if (run & 1) {
if (!res[0].ms)
res[0].ms = 1;