From 038f6b5669eeebfd686c2057c4001d62235a9d87 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Tue, 14 May 2024 11:40:44 +0200 Subject: [PATCH 01/15] add hash.c: zobrist init + pos zobrist calc + tt hash creation --- src/hash.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hash.h | 89 ++++++++++++++++++++ 2 files changed, 324 insertions(+) create mode 100644 src/hash.c create mode 100644 src/hash.h diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..522a818 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,235 @@ +/* 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include + +#include +#include + +#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. + */ +void zobrist_init(void) +{ + 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; + zobrist_turn = rand64(); +} + +/** + * zobrist_calc() - calculate a position zobrist hash. + * + * 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 + * + */ +key zobrist_calc(pos_t *pos) +{ + key 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 ^= pos->castle; + key ^= EP_ZOBRIST_IDX(pos->en_passant); + + return key; +} + +/** + * 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. + */ +#include +#include + +static void zob(char *str, size_t alloc) +{ + extern char etext, edata, end; + printf("%s %lu ", str, alloc); + //printf(" program text (etext) %10p\n", &etext); + //printf(" initialized data (edata) %10p\n", &edata); + //printf(" uninitialized data (end) %10p\n", &end); + + fflush(stdout); + + printf("\n\tpress a key..."); + getchar(); +} + +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"); + //hash_clear(); + } + /* 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)); +} + +// #define zob() + +int main() +{ + printf("entry=%lu bucket=%lu\n", sizeof(hentry_t), sizeof(bucket_t)); + zob("before alloc", 0); + setlocale(LC_NUMERIC, ""); + hash_create(-1); + zob("after", -1); + hash_create(1); + hash_create(2); + hash_create(3); + hash_create(4); + hash_create(10); + zob("after", 10); + hash_create(20); + hash_create(40); + hash_create(100); + zob("after", 100); + hash_create(200); + hash_create(400); + hash_create(1000); + zob("after", 1000); + hash_create(1000); + zob("after", 1024); + //hash_create(2000); + //zob("after", 100); + hash_create(4096); + zob("after", 4096); + //hash_create(32767); + //hash_create(32768); + //hash_create(32769); + //hash_create(65536); + //hash_create(400000); + return 0; +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..9fc014f --- /dev/null +++ b/src/hash.h @@ -0,0 +1,89 @@ +/* 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef HASH_H +#define HASH_H + +#include + +#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 */ + +typedef u64 key; + +/** + * 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 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) ) + +void zobrist_init(void); +int hash_create(int Mb); +void hash_clear(); +void hash_delete(); + +#endif /* HASH_H */ From 9ef262af485b858bd919880aad17eb7f6a34613c Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Tue, 14 May 2024 11:57:51 +0200 Subject: [PATCH 02/15] clean hash.c --- src/hash.c | 64 +++++------------------------------------------------- 1 file changed, 5 insertions(+), 59 deletions(-) diff --git a/src/hash.c b/src/hash.c index 522a818..6ca0e0b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -105,23 +105,6 @@ key zobrist_calc(pos_t *pos) * @return: hash table size in Mb. If memory allocation fails, the function does * not return. */ -#include -#include - -static void zob(char *str, size_t alloc) -{ - extern char etext, edata, end; - printf("%s %lu ", str, alloc); - //printf(" program text (etext) %10p\n", &etext); - //printf(" initialized data (edata) %10p\n", &edata); - //printf(" uninitialized data (end) %10p\n", &end); - - fflush(stdout); - - printf("\n\tpress a key..."); - getchar(); -} - int hash_create(s32 sizemb) { size_t bytes, target_nbuckets; @@ -129,12 +112,12 @@ int hash_create(s32 sizemb) static_assert(sizeof(hentry_t) == 16, "fatal: hentry_t size != 16"); - printf("mb = %'7u ", sizemb); + //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); + //printf("-> %'6d ", sizemb); bytes = sizemb * 1024ull * 1024ull; /* bytes wanted */ target_nbuckets = bytes / sizeof(bucket_t); /* target buckets */ @@ -160,10 +143,10 @@ int hash_create(s32 sizemb) //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"); - //hash_clear(); } + //else { + // printf("unchanged (cleared)\n"); + //} /* attention - may fail ! */ hash_clear(); @@ -196,40 +179,3 @@ void hash_delete() safe_free(hash_tt.keys); memset(&hash_tt, 0, sizeof(hash_tt)); } - -// #define zob() - -int main() -{ - printf("entry=%lu bucket=%lu\n", sizeof(hentry_t), sizeof(bucket_t)); - zob("before alloc", 0); - setlocale(LC_NUMERIC, ""); - hash_create(-1); - zob("after", -1); - hash_create(1); - hash_create(2); - hash_create(3); - hash_create(4); - hash_create(10); - zob("after", 10); - hash_create(20); - hash_create(40); - hash_create(100); - zob("after", 100); - hash_create(200); - hash_create(400); - hash_create(1000); - zob("after", 1000); - hash_create(1000); - zob("after", 1024); - //hash_create(2000); - //zob("after", 100); - hash_create(4096); - zob("after", 4096); - //hash_create(32767); - //hash_create(32768); - //hash_create(32769); - //hash_create(65536); - //hash_create(400000); - return 0; -} From 022daf0a89423cdcce3d47dc0bebfd2d8a7fbd45 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Wed, 15 May 2024 09:42:33 +0200 Subject: [PATCH 03/15] typedef key -> #define key_t - can't use typedef, due to --- Makefile | 2 +- src/hash.c | 4 ++-- src/hash.h | 17 +++++++++++++---- src/move-do.c | 14 ++++++++++++-- src/position.h | 8 +++++--- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index bae6a13..0928bf6 100644 --- a/Makefile +++ b/Makefile @@ -346,7 +346,7 @@ FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.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 +MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o hash.o PERFT_OBJS := $(MOVEDO_OBJS) search.o misc.o TEST := $(addprefix $(BINDIR)/,$(TEST)) diff --git a/src/hash.c b/src/hash.c index 6ca0e0b..befa61c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -59,9 +59,9 @@ void zobrist_init(void) * - To verify incremental Zobrist calculation is correct * */ -key zobrist_calc(pos_t *pos) +key_t zobrist_calc(pos_t *pos) { - key key = 0; + key_t key = 0; if (pos->turn == BLACK) key ^= zobrist_turn; diff --git a/src/hash.h b/src/hash.h index 9fc014f..76cc880 100644 --- a/src/hash.h +++ b/src/hash.h @@ -24,7 +24,7 @@ #define HASH_SIZE_MIN 4 #define HASH_SIZE_MAX 32768 /* 32Gb */ -typedef u64 key; +#define key_t u64 /* cannot use typedef for key_t */ /** * hentry_t: hashtable bucket. @@ -33,7 +33,7 @@ typedef u64 key; * 16 bytes in future, it should be updated to be exactly 32 bytes. */ typedef struct { - key key; /* zobrist */ + key_t key; /* zobrist */ union { u64 data; struct { @@ -81,9 +81,18 @@ typedef struct { */ #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); + int hash_create(int Mb); -void hash_clear(); -void hash_delete(); +void hash_clear(void); +void hash_delete(void); #endif /* HASH_H */ diff --git a/src/move-do.c b/src/move-do.c index fe62ea2..6a27021 100644 --- a/src/move-do.c +++ b/src/move-do.c @@ -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) { @@ -57,6 +62,9 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state) piece_t new_piece = piece; int up = sq_up(us); + /* update turn, reset castling and ep */ + pos->key ^= zobrist_turn; + ++pos->clock_50; ++pos->plycount; pos->en_passant = SQUARE_NONE; @@ -119,7 +127,8 @@ 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 +137,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state) pos->castle = clr_oo(pos->castle, them); } + return pos; } diff --git a/src/position.h b/src/position.h index c859188..3885710 100644 --- a/src/position.h +++ b/src/position.h @@ -16,11 +16,12 @@ #include -#include "brlib.h" -#include "bitops.h" -#include "struct-group.h" +#include +#include +#include #include "chessdefs.h" +#include "hash.h" #include "bitboard.h" #include "piece.h" #include "move.h" @@ -41,6 +42,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; From 86f8184c56724dfd1a43ce47debf0325837660a2 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Wed, 15 May 2024 18:34:50 +0200 Subject: [PATCH 04/15] misc.c: init_all() --- Makefile | 11 +++++++---- src/chessdefs.h | 2 ++ src/init.c | 4 ++-- test/movedo-test.c | 5 +---- test/perft-test.c | 7 ++----- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 0928bf6..b9b359c 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,9 @@ CPPFLAGS += -DWARN_ON # brlib bug.h # fen.c #CPPFLAGS += -DDEBUG_FEN # FEN decoding +# hash +CPPFLAGS += -DDEBUG_HASH # chk zobrist consistency + # attack.c #CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers #CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details @@ -342,12 +345,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 hash.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)) @@ -387,7 +390,7 @@ bin/attack-test: test/attack-test.c test/common-test.h $(ATTACK_OBJS) bin/movedo-test: test/movedo-test.c test/common-test.h $(MOVEDO_OBJS) @echo compiling $@ test executable. - @$(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@ + $(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@ bin/perft-test: test/perft-test.c test/common-test.h $(PERFT_OBJS) @echo compiling $@ test executable. diff --git a/src/chessdefs.h b/src/chessdefs.h index 59f2837..75e9665 100644 --- a/src/chessdefs.h +++ b/src/chessdefs.h @@ -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 */ diff --git a/src/init.c b/src/init.c index a12957a..175594e 100644 --- a/src/init.c +++ b/src/init.c @@ -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); } diff --git a/test/movedo-test.c b/test/movedo-test.c index 1415c29..bc534ff 100644 --- a/test/movedo-test.c +++ b/test/movedo-test.c @@ -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(); diff --git a/test/perft-test.c b/test/perft-test.c index 872e8e3..2a1e07e 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -277,17 +277,14 @@ int main(int __unused ac, __unused char**av) // run = atoi(av[2]) & 3; printf("depth = %d run = %x sf = %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); while ((fen = next_fen(PERFT | MOVEDO))) { test_line = cur_line(); From 5db45a760a8eebf5de2efd5d784c75ddf93f0640 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Wed, 15 May 2024 18:36:30 +0200 Subject: [PATCH 05/15] fen: calc pos hash, hash: fix zobrist_init, add zobrist_verify --- src/fen.c | 4 +++- src/hash.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/hash.h | 1 + 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/fen.c b/src/fen.c index 2818000..6f8d2c1 100644 --- a/src/fen.c +++ b/src/fen.c @@ -250,8 +250,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"); diff --git a/src/hash.c b/src/hash.c index befa61c..b8eb00d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -51,6 +51,7 @@ void zobrist_init(void) /** * zobrist_calc() - calculate a position zobrist hash. + * @pos: &position * * Normally, Zobrist keys are incrementally calculated when doing or * undoing a move. @@ -58,6 +59,7 @@ void zobrist_init(void) * - When starting a new position * - To verify incremental Zobrist calculation is correct * + * @return: @pos Zobrist key */ key_t zobrist_calc(pos_t *pos) { @@ -76,12 +78,64 @@ key_t zobrist_calc(pos_t *pos) } } } - key ^= pos->castle; - key ^= EP_ZOBRIST_IDX(pos->en_passant); + 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 DEBUG_HASH is not set. + * + * @return: True if Zobrist key is OK. + */ +#ifdef DEBUG_HASH +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: + return false; +} +#endif + /** * hash_create() - hashtable creation. * @sizemb: s32 size of hash table in Mb diff --git a/src/hash.h b/src/hash.h index 76cc880..e639250 100644 --- a/src/hash.h +++ b/src/hash.h @@ -90,6 +90,7 @@ extern hasht_t hash_tt; /* main transposition table */ void zobrist_init(void); key_t zobrist_calc(pos_t *pos); +bool zobrist_verify(pos_t *pos); int hash_create(int Mb); void hash_clear(void); From 2069d6073d6a1fabd47ce554540398b18b66bfa5 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 07:16:17 +0200 Subject: [PATCH 06/15] add pos_copy(); pos->king[] set at higher level --- Makefile | 6 +++--- src/fen.c | 2 ++ src/hash.c | 2 +- src/hash.h | 5 +++++ src/move-do.c | 58 ++++++++++++++++++++++++++++++++++++++++---------- src/position.c | 18 +++++++++++++++- src/position.h | 20 +++++++++++++---- 7 files changed, 91 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index b9b359c..1e917ee 100644 --- a/Makefile +++ b/Makefile @@ -68,8 +68,8 @@ CPPFLAGS += -DWARN_ON # brlib bug.h # fen.c #CPPFLAGS += -DDEBUG_FEN # FEN decoding -# hash -CPPFLAGS += -DDEBUG_HASH # chk zobrist consistency +# hash.c +#CPPFLAGS += -HASH_VERIFY # chk zobrist consistency # attack.c #CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers @@ -390,7 +390,7 @@ bin/attack-test: test/attack-test.c test/common-test.h $(ATTACK_OBJS) bin/movedo-test: test/movedo-test.c test/common-test.h $(MOVEDO_OBJS) @echo compiling $@ test executable. - $(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@ + @$(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@ bin/perft-test: test/perft-test.c test/common-test.h $(PERFT_OBJS) @echo compiling $@ test executable. diff --git a/src/fen.c b/src/fen.c index 6f8d2c1..bf7a3f0 100644 --- a/src/fen.c +++ b/src/fen.c @@ -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; diff --git a/src/hash.c b/src/hash.c index b8eb00d..762ea70 100644 --- a/src/hash.c +++ b/src/hash.c @@ -93,7 +93,7 @@ key_t zobrist_calc(pos_t *pos) * * @return: True if Zobrist key is OK. */ -#ifdef DEBUG_HASH +#ifdef ZOBRIST_VERIFY bool zobrist_verify(pos_t *pos) { key_t diff, key = zobrist_calc(pos); diff --git a/src/hash.h b/src/hash.h index e639250..438ffee 100644 --- a/src/hash.h +++ b/src/hash.h @@ -90,7 +90,12 @@ 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); diff --git a/src/move-do.c b/src/move-do.c index 6a27021..8fbf9e4 100644 --- a/src/move-do.c +++ b/src/move-do.c @@ -61,9 +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 turn, reset castling and ep */ - pos->key ^= zobrist_turn; + /* 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; @@ -82,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; @@ -92,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) @@ -127,7 +137,6 @@ 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)) { square_t rel_a8 = sq_rel(A8, us); square_t rel_h8 = sq_rel(H8, us); @@ -137,6 +146,12 @@ 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; } @@ -153,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; @@ -173,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; @@ -183,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) @@ -218,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) @@ -227,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; } diff --git a/src/position.c b/src/position.c index ab277ec..f95bda3 100644 --- a/src/position.c +++ b/src/position.c @@ -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; @@ -336,9 +352,9 @@ bool pos_ok(const pos_t *pos, const bool strict) /* force BUG_ON and WARN_ON */ # pragma push_macro("BUG_ON") -# pragma push_macro("WARN_ON") # undef BUG_ON # define BUG_ON +# pragma push_macro("WARN_ON") # undef WARN_ON # define WARN_ON diff --git a/src/position.h b/src/position.h index 3885710..b99bb30 100644 --- a/src/position.h +++ b/src/position.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "chessdefs.h" #include "hash.h" @@ -74,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]; } /** @@ -93,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; } /** @@ -158,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); From d1cb1f3c2cf98fa05b4c5a291fd8f4ec6613c007 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 07:27:35 +0200 Subject: [PATCH 07/15] perft-test: re-use pos --- test/perft-test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/perft-test.c b/test/perft-test.c index 2a1e07e..87d6e60 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -235,7 +235,7 @@ 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; @@ -288,10 +288,12 @@ int main(int __unused ac, __unused char**av) CLOCK_DEFINE(clock, CLOCK_PROCESS); while ((fen = next_fen(PERFT | MOVEDO))) { test_line = cur_line(); - if (!(pos = fen2pos(NULL, fen))) { + printf("pos = %p\n", pos); + if (!(fenpos = fen2pos(pos, fen))) { printf("wrong fen %d: [%s]\n", i, fen); continue; } + pos = fenpos; if (sf_run) sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth); @@ -354,11 +356,11 @@ 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 (run & 1) { if (!res[0].ms) res[0].ms = 1; From a012af30fc186d2bc11a8d6b95d6492c66141a1f Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 07:27:59 +0200 Subject: [PATCH 08/15] fix wrong recursive call in perft_test() --- src/search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.c b/src/search.c index 1fbef4b..06f889b 100644 --- a/src/search.c +++ b/src/search.c @@ -105,7 +105,7 @@ 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); + 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); From 239498bc2ac4755a0e9cf19b02821f3f83a04b18 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 07:29:02 +0200 Subject: [PATCH 09/15] cleanup --- test/perft-test.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/perft-test.c b/test/perft-test.c index 87d6e60..33140f0 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -288,7 +288,6 @@ int main(int __unused ac, __unused char**av) CLOCK_DEFINE(clock, CLOCK_PROCESS); while ((fen = next_fen(PERFT | MOVEDO))) { test_line = cur_line(); - printf("pos = %p\n", pos); if (!(fenpos = fen2pos(pos, fen))) { printf("wrong fen %d: [%s]\n", i, fen); continue; From 4a0c734ebaf75a7f2b531bc44878d578f882e4c2 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 09:06:44 +0200 Subject: [PATCH 10/15] perft: Avoid recursion at depth 2 --- src/search.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/search.c b/src/search.c index 06f889b..9fd90cf 100644 --- a/src/search.c +++ b/src/search.c @@ -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_test(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); From f657f8498a07f8b9cad6f9efaac98064dce70ddc Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Thu, 16 May 2024 09:07:15 +0200 Subject: [PATCH 11/15] perft-test: output also SF perf --- test/perft-test.c | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/test/perft-test.c b/test/perft-test.c index 33140f0..63d3cb4 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -238,13 +238,13 @@ int main(int __unused ac, __unused char**av) 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,11 +271,9 @@ 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(); @@ -285,7 +283,7 @@ int main(int __unused ac, __unused char**av) if (sf_run) outfd = open_stockfish(); - CLOCK_DEFINE(clock, CLOCK_PROCESS); + CLOCK_DEFINE(clock, CLOCK_MONOTONIC); while ((fen = next_fen(PERFT | MOVEDO))) { test_line = cur_line(); if (!(fenpos = fen2pos(pos, fen))) { @@ -293,10 +291,27 @@ int main(int __unused ac, __unused char**av) continue; } pos = fenpos; - if (sf_run) + 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); @@ -360,6 +375,15 @@ int main(int __unused ac, __unused char**av) // 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; From 6da0f80d4642cb82235549158a2a61150d5dbae9 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sat, 18 May 2024 13:37:23 +0200 Subject: [PATCH 12/15] allow bug.h multiple inclusions (w/ different BUG_ON/WARN_ON values) --- brlib | 2 +- src/position.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/brlib b/brlib index 8ff163d..7bedfdd 160000 --- a/brlib +++ b/brlib @@ -1 +1 @@ -Subproject commit 8ff163dcf569105bbdec28860eff100280e32898 +Subproject commit 7bedfddfba09e9f93615fee2623d44a9d0e1a605 diff --git a/src/position.c b/src/position.c index f95bda3..08cb05c 100644 --- a/src/position.c +++ b/src/position.c @@ -352,11 +352,12 @@ bool pos_ok(const pos_t *pos, const bool strict) /* force BUG_ON and WARN_ON */ # pragma push_macro("BUG_ON") +# pragma push_macro("WARN_ON") # undef BUG_ON # define BUG_ON -# pragma push_macro("WARN_ON") # undef WARN_ON # define WARN_ON +# include /* pawns on 1st ot 8th rank */ error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & From 77695574aa39eb5ee223e2ca17fce7d1b6c59e1b Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sat, 18 May 2024 13:38:27 +0200 Subject: [PATCH 13/15] fetch-all.sh --- scripts/fetch-all.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 scripts/fetch-all.sh diff --git a/scripts/fetch-all.sh b/scripts/fetch-all.sh new file mode 100755 index 0000000..399d2a8 --- /dev/null +++ b/scripts/fetch-all.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +git remote | xargs -n 1 git fetch -a From 07a545adae499078272fb5bc53692e9d0ccc6bcb Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Tue, 21 May 2024 07:49:49 +0200 Subject: [PATCH 14/15] protect hash_init() against multiple calls --- src/hash.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/hash.c b/src/hash.c index 762ea70..f9b4112 100644 --- a/src/hash.c +++ b/src/hash.c @@ -32,21 +32,26 @@ hasht_t hash_tt; /* main transposition table */ /** * zobrist_init() - initialize zobrist tables. * - * Initialize all zobrist random bitmasks. + * 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) { - 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(); + 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(); } - 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; - zobrist_turn = rand64(); } /** @@ -89,7 +94,7 @@ key_t zobrist_calc(pos_t *pos) * @pos: &position * * Verify that position Zobrist key matches a full Zobrist calculation. - * This function cannot be called if DEBUG_HASH is not set. + * This function cannot be called if ZOBRIST_VERIFY is not set. * * @return: True if Zobrist key is OK. */ @@ -132,7 +137,7 @@ bool zobrist_verify(pos_t *pos) } warn(true, "zobrist diff %lx is unknown\n", diff); end: - return false; + bug_on(false); } #endif From 1670b21dfa1236974dd07abc20ac1825404c6493 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Tue, 21 May 2024 07:52:01 +0200 Subject: [PATCH 15/15] fetch-all: add possible local branch creation (still only echo) --- Makefile | 6 ++---- scripts/fetch-all.sh | 45 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1e917ee..11a0c41 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -81,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)) diff --git a/scripts/fetch-all.sh b/scripts/fetch-all.sh index 399d2a8..df04b1c 100755 --- a/scripts/fetch-all.sh +++ b/scripts/fetch-all.sh @@ -1,3 +1,46 @@ #!/usr/bin/env bash -git remote | xargs -n 1 git fetch -a +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