working TT with perft
This commit is contained in:
116
src/hash.c
116
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");
|
||||
}
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
67
src/search.c
67
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user