#pragma once struct search_option { /* TODO: optimize order of fields and size */ double score; struct move move; uint64_t hash; uint8_t init : 1; enum tt_flag {TT_EXACT, TT_LOWER, TT_UPPER} flag : 3; int8_t depth : 4; }; #define TT_ADDRESS_BITS 24 #define TT_ENTRIES (1ULL<entries[addr]; #ifndef NDEBUG tt->probes += 1; if (tte.init && tte.hash == hash) { tt->hits += 1; } else if (tte.init && tte.hash != hash) { tt->collisions += 1; } #endif return tte; } static inline void tt_insert(struct tt* tt, uint64_t hash, struct search_option so) { uint64_t const addr = hash % TT_ENTRIES; so.init = true; tt->entries[addr] = so; #ifndef NDEBUG tt->insertions += 1; #endif } /* tt_insert_maybe inserts only if heuristics say it's a good idea. There are * two considerations: * - higher depth saves more work per probe hit * - entries closer to the leaves are more likely to be searched multiple time */ static inline void tt_insert_maybe(struct tt* tt, uint64_t hash, struct search_option so) { uint64_t const addr = hash % TT_ENTRIES; #if 0 struct search_option* tte = &tt->entries[addr]; if (so.depth < tte->depth) { *tte = so; } #endif so.init = true; tt->entries[addr] = so; #ifndef NDEBUG tt->insertions += 1; #endif }