From f1657e9806de53f6a9291028b54808c507939be1 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Mon, 17 Jun 2024 07:45:57 +0200 Subject: [PATCH] working TT with perft --- src/hash.c | 116 ++++++++++++++++++++++++++++++++------------------- src/hash.h | 5 ++- src/search.c | 67 ++++++++++++----------------- 3 files changed, 102 insertions(+), 86 deletions(-) diff --git a/src/hash.c b/src/hash.c index 6e34c0c..6615ba4 100644 --- a/src/hash.c +++ b/src/hash.c @@ -111,7 +111,6 @@ hkey_t zobrist_calc(pos_t *pos) bool zobrist_verify(pos_t *pos) { hkey_t diff, key = zobrist_calc(pos); - if (pos->key == key) return true; @@ -251,9 +250,11 @@ void tt_clear() */ void tt_delete() { - if (hash_tt.keys) + if (hash_tt.keys) { safe_free(hash_tt.keys); - memset(&hash_tt, 0, sizeof(hash_tt)); + hash_tt.keys = NULL; + } + tt_clear(); } /** @@ -304,13 +305,17 @@ hentry_t *tt_probe_perft(const hkey_t key, const u16 depth) entry = bucket->entry + i; if (key == entry->key && HASH_PERFT_DEPTH(entry->data) == depth) { hash_tt.hits++; - //printf("tt hit: key=%lx bucket=%lu entry=%d!\n", - // key, bucket - hash_tt.keys, i); + /* + * printf("tt hit: key=%lx depth=%d bucket=%lu entry=%d!\n", + * key, depth, bucket - hash_tt.keys, i); + */ return entry; } } - //printf("tt miss: key=%lx bucket=%lu\n", - // key, bucket - hash_tt.keys); + /* + * printf("tt miss: key=%lx depth=%d ucket=%lu\n", + * key, depth, bucket - hash_tt.keys); + */ hash_tt.misses++; return TT_MISS; } @@ -326,70 +331,93 @@ hentry_t *tt_store_perft(const hkey_t key, const u16 depth, const u64 nodes) { bucket_t *bucket; hentry_t *entry; - int replace = -1, newkey = 0; + int replace = -1; uint mindepth = 1024; u64 data = HASH_PERFT(depth, nodes); //printf("tt_store: key=%lx data=%lx depth=%d=%d nodes=%lu=%lu\n", // key, data, depth, HASH_PERFT_DEPTH(data), nodes, HASH_PERFT_VAL(data)); - printf("tt_store: key=%lx depth=%d nodes=%lu ", - key, depth, nodes); + /* + * printf("tt_store: key=%lx depth=%d nodes=%lu ", + * key, depth, nodes); + */ bug_on(!hash_tt.keys); bucket = hash_tt.keys + (key & hash_tt.mask); /* find key in buckets */ for (int i = 0; i < ENTRIES_PER_BUCKET; ++i) { entry = bucket->entry + i; - if (key == entry->key && HASH_PERFT_DEPTH(entry->data)) { - printf("tt_store: sup key/depth, this should not happen!\n"); - return NULL; + //if (!entry->key) { + // replace = i; + //hash_tt.used_keys++; + // break; + //} + if (key == entry->key) { + if (depth == HASH_PERFT_DEPTH(entry->data)) { + printf("tt_store: dup key=%lx depth=%d, this should not happen!\n", + key, depth); + return NULL; + } } - if (!entry->key) { - replace = i; - break; - } - /* we replace hash if we are higher in tree */ + /* always keep higher nodes */ if (HASH_PERFT_DEPTH(entry->data) < mindepth) { mindepth = HASH_PERFT_DEPTH(entry->data); replace = i; } - /* - * else { - * - * if (key == entry->key && HASH_PERFT_DEPTH(entry->data) > mindepth) { - * mindepth = HASH_PERFT_DEPTH(entry->data); - * replace = i; - * } - * } - */ } + if (replace >= 0) { entry = bucket->entry + replace; - if (HASH_PERFT_VAL(entry->data)) { - printf("REPL entry=%lu[%d] key=%lx->%lx val=%lu->%lu\n", - bucket - hash_tt.keys, replace, - entry->key, key, - HASH_PERFT_VAL(entry->data), nodes); - } else { - printf("NEW entry=%lu[%d] key=%lx val=%lu\n", - bucket - hash_tt.keys, replace, - entry->key, nodes); - } + + hash_tt.used_keys += entry->key == 0; + hash_tt.collisions += entry->key && (key != entry->key); + /* + * if (HASH_PERFT_VAL(entry->data)) { + * printf("REPL entry=%lu[%d] key=%lx->%lx val=%lu->%lu\n", + * bucket - hash_tt.keys, replace, + * entry->key, key, + * HASH_PERFT_VAL(entry->data), nodes); + * } else { + * printf("NEW entry=%lu[%d] key=%lx val=%lu\n", + * bucket - hash_tt.keys, replace, + * entry->key, nodes); + * } + */ entry->key = key; entry->data = data; return entry; } else { - printf("TT full, skip\n"); + //printf("TT full, skip\n"); } return NULL; } +/** + * tt_info() - print hash-table information. + */ +void tt_info() +{ + if (hash_tt.keys) { + printf("TT: Mb:%d buckets:%'lu (bits:%u mask:%#x) entries:%'lu\n", + hash_tt.mb, hash_tt.nbuckets, hash_tt.nbits, + hash_tt.mask, hash_tt.nkeys); + } else { + printf("TT: not set.\n"); + } +} + +/** + * tt_stats() - print hash-table usage. + */ void tt_stats() { - printf("TT: sz=%u bits=%u bcks=%'lu entries=%'lu mask=%10x" - "used=%lu hits/miss=%'lu/%'lu\n", - hash_tt.mb, hash_tt.nbits, hash_tt.nbuckets, hash_tt.nkeys, hash_tt.mask, - hash_tt.used_keys, hash_tt.hits, hash_tt.misses); - //printf("\tused=%lu hits/miss=%lu/%lu\n", - // hash_tt.used_keys, hash_tt.hits, hash_tt.misses); + if (hash_tt.keys) { + float percent = 100.0 * hash_tt.used_keys / hash_tt.nkeys; + printf("hash: used:%'lu/%'lu (%.2f%%) hit:%'lu miss:%'lu coll:%'lu\n", + hash_tt.used_keys, hash_tt.nkeys, percent, + hash_tt.hits, hash_tt.misses, + hash_tt.collisions); + } else { + printf("hash: not set.\n"); + } } diff --git a/src/hash.h b/src/hash.h index 7119bd1..c57eed8 100644 --- a/src/hash.h +++ b/src/hash.h @@ -24,7 +24,9 @@ #define HASH_SIZE_MIN 4 #define HASH_SIZE_MAX 32768 /* 32Gb */ -#define TT_MISS NULL +#define TT_MISS NULL +#define TT_DUP (void *) U64(0x01) +#define TT_OK(p) ((p) > (void *)U64(0xF)) typedef u64 hkey_t; /* cannot use typedef for key_t */ @@ -130,6 +132,7 @@ void tt_delete(void); hentry_t *tt_probe(hkey_t key); hentry_t *tt_probe_perft(const hkey_t key, const u16 depth); hentry_t *tt_store_perft(const hkey_t key, const u16 depth, const u64 nodes); +void tt_info(void); void tt_stats(void); #endif /* HASH_H */ diff --git a/src/search.c b/src/search.c index 4718927..411272b 100644 --- a/src/search.c +++ b/src/search.c @@ -23,9 +23,10 @@ /** * perft() - Perform perft on position - * @pos: &position to search - * @depth: Wanted depth. - * @ply: perft depth level. + * @pos: &position to search + * @depth: Wanted depth. + * @ply: current perft depth level (root = 1) + * @output: output total for 1st level moves. * * Run perft on a position. This function displays the available moves at @depth * level for each possible first move, and the total of moves. @@ -43,15 +44,15 @@ */ u64 perft(pos_t *pos, int depth, int ply, bool output) { - static movelist_t stack; - //int subnodes; u64 subnodes, nodes = 0; movelist_t movelist; move_t *move, *last; state_t state; - +# ifdef PERFT_MOVE_HISTORY + static movelist_t stack; if (ply == 1) stack.nmoves = 0; +# endif pos_set_checkers_pinners_blockers(pos); @@ -62,38 +63,23 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) nodes++; } else { move_do(pos, *move, &state); +# ifdef PERFT_MOVE_HISTORY stack.move[stack.nmoves++] = *move; - if (ply == 2 && - //move_from(*move) == F7 && - //move_to(*move) == F5 && - move_from(stack.move[stack.nmoves-2]) == B2 && - move_to(stack.move[stack.nmoves-2]) == B4 && - move_from(stack.move[stack.nmoves-1]) == F7 && - move_to(stack.move[stack.nmoves-1]) == F5 - ) { - //&& pos->board[F5] == B_PAWN) { - moves_print(&stack, 0); - pos_print(pos); - } +# endif if (depth == 2) { movelist_t movelist2; pos_set_checkers_pinners_blockers(pos); subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; - } else { - hentry_t *entry; - //if (ply >= 4 && ply <= 8) { - if (ply == 4) { - if ((entry = tt_probe_perft(pos->key, depth))) { - subnodes = HASH_PERFT_VAL(entry->data); - printf("tt hit key=%lx ply=%d depth=%d nodes=%lu\n", - pos->key, ply, depth, subnodes); - } else { - subnodes = perft(pos, depth - 1, ply + 1, output); - tt_store_perft(pos->key, depth, subnodes); - } + } else if (ply >= 4) { + hentry_t *entry = tt_probe_perft(pos->key, depth); + if (entry != TT_MISS) { + subnodes = HASH_PERFT_VAL(entry->data); } else { subnodes = perft(pos, depth - 1, ply + 1, output); + tt_store_perft(pos->key, depth, subnodes); } + } else { + subnodes = perft(pos, depth - 1, ply + 1, output); } if (output && ply == 1) { char movestr[8]; @@ -101,7 +87,9 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) } nodes += subnodes; move_undo(pos, *move, &state); +# ifdef PERFT_MOVE_HISTORY stack.nmoves--; +# endif } } @@ -112,9 +100,10 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) /** * perft_alt() - Perform perft on position, experimental version. - * @pos: &position to search - * @depth: Wanted depth. - * @ply: perft depth level. + * @pos: &position to search + * @depth: Wanted depth. + * @ply: current perft depth level (root = 1) + * @output: output total for 1st level moves. * * Run perft on a position. This function displays the available moves at @depth * level for each possible first move, and the total of moves. @@ -123,15 +112,12 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) */ u64 perft_alt(pos_t *pos, int depth, int ply, bool output) { - int subnodes; - u64 nodes = 0; + u64 subnodes, nodes = 0; movelist_t movelist; move_t *move, *last; state_t state; - //movelist.nmoves = 0; pos_set_checkers_pinners_blockers(pos); - state = pos->state; pos_legal(pos, pos_gen_pseudo(pos, &movelist)); last = movelist.move + movelist.nmoves; @@ -139,7 +125,7 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output) if (depth == 1) { nodes++; } else { - move_do_alt(pos, *move); + move_do_alt(pos, *move, &state); if (depth == 2) { movelist_t movelist2; pos_set_checkers_pinners_blockers(pos); @@ -149,11 +135,10 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output) } if (output && ply == 1) { char movestr[8]; - printf("%s: %d\n", move_to_str(movestr, *move, 0), subnodes); + printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); } nodes += subnodes; - move_undo_alt(pos, *move); - pos->state = state; + move_undo_alt(pos, *move, &state); } }