From 1898add0142b70b3fef5af78a6f3d7399a3f2cd5 Mon Sep 17 00:00:00 2001 From: tslil Date: Wed, 16 Sep 2026 20:10:33 +0100 Subject: fix tt issue for non-self-play A little subtle, but in non-self-play games sharing tt entries is incorrect. We must therefore key additionally on the evaulation function itself. --- include/negamax.c | 4 ++-- include/negamax.h | 1 - include/nn.h | 2 ++ include/tt.c | 12 +++++++----- include/tt.h | 11 ++++++----- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/negamax.c b/include/negamax.c index f9a52e6..9c4ddbd 100644 --- a/include/negamax.c +++ b/include/negamax.c @@ -164,7 +164,7 @@ static float negamax(tak_state_p state, const uint8_t cur_depth, // the scratch buffer is per-level so that recursion does not clobber const uint32_t level = init_depth - cur_depth; - tt_entry_t *entry = tt_seek(hash); + tt_entry_t *entry = tt_seek(hash, evaluate); // The root never early-returns from the table. Within one game the new // root was only ever stored at depth D-1, so an early return could not @@ -283,7 +283,7 @@ static float negamax(tak_state_p state, const uint8_t cur_depth, else if (best_value <= orig_alpha) flag = TT_UPPERBOUND; - entry = tt_store(hash, flag, cur_depth, best_value, best_action); + entry = tt_store(hash, evaluate, flag, cur_depth, best_value, best_action); #ifdef RECORD_PV if (entry != NULL) entry->leaf = best_leaf; diff --git a/include/negamax.h b/include/negamax.h index 7b32233..db5d640 100644 --- a/include/negamax.h +++ b/include/negamax.h @@ -49,7 +49,6 @@ void negamax_init(const uint8_t new_board_size); * Override the leaf evaluation function (negamax_init picks one by * board size). */ -typedef float (*nn_function)(tak_state_p); void negamax_set_evaluator(const nn_function f); void negamax_free(void); diff --git a/include/nn.h b/include/nn.h index 3a2277a..1d3eba0 100644 --- a/include/nn.h +++ b/include/nn.h @@ -41,6 +41,8 @@ int nn_last_cell_idxs(uint8_t *out, tak_state_p state); // Network // =================================================================== +typedef float (*nn_function)(tak_state_p); + float eval_net(const float *board, const unsigned int n_inp, const float *w, const float *biases, const float *logit_w, const float logit_b, const unsigned int n_dense, diff --git a/include/tt.c b/include/tt.c index 8ad6c56..c996791 100644 --- a/include/tt.c +++ b/include/tt.c @@ -36,20 +36,21 @@ int tt_init(void) { return EXIT_SUCCESS; } -tt_entry_t *tt_seek(const uint64_t key) { +tt_entry_t *tt_seek(const uint64_t key, const nn_function eval) { tt_entry_t *e = &table[key & TT_SIZE]; - if (e->gen == tt_gen && e->key == key) + if (e->gen == tt_gen && e->key == key && e->eval == eval) return e; return NULL; } -tt_entry_t *tt_store(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action) { +tt_entry_t *tt_store(const uint64_t key, const nn_function eval, + const enum TT_FLAG flag, const uint8_t depth, + const float value, const action_t action) { tt_entry_t *e = &table[key & TT_SIZE]; if (e->gen == tt_gen && e->key == key) { // The slot holds this very position: update it (gen and key are already // correct). + e->eval = eval; e->flag = flag; e->value = value; e->depth = depth; @@ -61,6 +62,7 @@ tt_entry_t *tt_store(const uint64_t key, const enum TT_FLAG flag, if (e->gen == tt_gen && e->depth > depth) return NULL; e->key = key; + e->eval = eval; e->value = value; e->action = action; e->gen = tt_gen; diff --git a/include/tt.h b/include/tt.h index 60b9b66..5834860 100644 --- a/include/tt.h +++ b/include/tt.h @@ -19,7 +19,7 @@ #define TT_H #include - +#include #include // =================================================================== @@ -35,6 +35,7 @@ enum TT_FLAG { TT_EXACT, TT_LOWERBOUND, TT_UPPERBOUND }; typedef struct tt_node_s { uint16_t gen; uint64_t key; + nn_function eval; enum TT_FLAG flag; uint8_t depth; float value; @@ -61,7 +62,7 @@ typedef struct tt_node_s { // entries are otherwise kept across plies on purpose (see negamax.c). int tt_init(void); -tt_entry_t *tt_seek(const uint64_t key); +tt_entry_t *tt_seek(const uint64_t key, const nn_function eval); // Store a search result for `key', returning the entry it was written to, or // NULL when the replacement policy keeps the current occupant instead. @@ -73,8 +74,8 @@ tt_entry_t *tt_seek(const uint64_t key); // - otherwise (empty slot, stale generation, or a different key): replace the // occupant unless it is a deeper search of a different position, which is // kept. -tt_entry_t *tt_store(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action); +tt_entry_t *tt_store(const uint64_t key, const nn_function eval, + const enum TT_FLAG flag, const uint8_t depth, + const float value, const action_t action); #endif -- cgit v1.3.1