#pragma once struct search_option { uint64_t hash; // + 64 (64 / 8) float score; // + 32 (96 / 12) struct move move; // + 32 (128 / 16) int depth : 4; // + 4 (132 / 17) int init : 1; // + 1 (133 / 17) enum tt_flag {TT_EXACT, TT_LOWER, TT_UPPER} flag : 3; // +3 (136 / 17) }; #define TT_ADDRESS_BITS 24 #define TT_ENTRIES (1ULL<mask; struct search_option tte = tt->entries[addr]; #ifndef NSTATS 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->mask; so.init = true; tt->entries[addr] = so; #ifndef NSTATS 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->mask; #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 NSTATS tt->insertions += 1; #endif }