2 Commits

Author SHA1 Message Date
148fef20ea add info in pos_print, start perft TT testing 2024-06-13 10:28:32 +02:00
8be03c6230 rename TT funcs to TT_xxx() 2024-06-12 07:50:19 +02:00
12 changed files with 462 additions and 51 deletions

View File

@@ -70,7 +70,7 @@ CPPFLAGS += -DBUG_ON # brlib bug.h
#CPPFLAGS += -DDEBUG_FEN # FEN decoding #CPPFLAGS += -DDEBUG_FEN # FEN decoding
# hash.c # hash.c
#CPPFLAGS += -HASH_VERIFY # chk zobrist consistency CPPFLAGS += -DZOBRIST_VERIFY # chk zobrist consistency
# attack.c # attack.c
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers #CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
@@ -339,7 +339,7 @@ memcheck: targets
.PHONY: testing test .PHONY: testing test
TEST := piece-test fen-test bitboard-test movegen-test attack-test TEST := piece-test fen-test bitboard-test movegen-test attack-test
TEST += movedo-test perft-test TEST += movedo-test perft-test tt-test
PIECE_OBJS := piece.o PIECE_OBJS := piece.o
FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \ FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \
@@ -349,6 +349,7 @@ MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o
ATTACK_OBJS := $(MOVEGEN_OBJS) ATTACK_OBJS := $(MOVEGEN_OBJS)
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o misc.o MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o misc.o
PERFT_OBJS := $(MOVEDO_OBJS) search.o PERFT_OBJS := $(MOVEDO_OBJS) search.o
TT_OBJS := $(MOVEDO_OBJS)
TEST := $(addprefix $(BINDIR)/,$(TEST)) TEST := $(addprefix $(BINDIR)/,$(TEST))
@@ -359,6 +360,7 @@ MOVEGEN_OBJS := $(addprefix $(OBJDIR)/,$(MOVEGEN_OBJS))
ATTACK_OBJS := $(addprefix $(OBJDIR)/,$(ATTACK_OBJS)) ATTACK_OBJS := $(addprefix $(OBJDIR)/,$(ATTACK_OBJS))
MOVEDO_OBJS := $(addprefix $(OBJDIR)/,$(MOVEDO_OBJS)) MOVEDO_OBJS := $(addprefix $(OBJDIR)/,$(MOVEDO_OBJS))
PERFT_OBJS := $(addprefix $(OBJDIR)/,$(PERFT_OBJS)) PERFT_OBJS := $(addprefix $(OBJDIR)/,$(PERFT_OBJS))
TT_OBJS := $(addprefix $(OBJDIR)/,$(TT_OBJS))
test: test:
echo TEST=$(TEST) echo TEST=$(TEST)
@@ -394,6 +396,10 @@ bin/perft-test: test/perft-test.c test/common-test.h $(PERFT_OBJS)
@echo compiling $@ test executable. @echo compiling $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(PERFT_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(PERFT_OBJS) $(ALL_LDFLAGS) -o $@
bin/tt-test: test/tt-test.c test/common-test.h $(TT_OBJS)
@echo compiling $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(TT_OBJS) $(ALL_LDFLAGS) -o $@
##################################### Makefile debug ##################################### Makefile debug
.PHONY: showflags wft .PHONY: showflags wft

View File

@@ -16,8 +16,8 @@
#include "brlib.h" /* brlib types */ #include "brlib.h" /* brlib types */
#define ONE 1ull #define ONE 1ul
#define U64(const_u64) const_u64##ULL #define U64(const_u64) const_u64##UL
#define BIT(i) ( (u64) (ONE << (i)) ) #define BIT(i) ( (u64) (ONE << (i)) )
#define BOARDSIZE (8*8) #define BOARDSIZE (8*8)
@@ -176,7 +176,7 @@ s64 clock_elapsed_μs(mclock_t *clock);
s64 clock_elapsed_ms(mclock_t *clock); s64 clock_elapsed_ms(mclock_t *clock);
double clock_elapsed_sec(mclock_t *clock); double clock_elapsed_sec(mclock_t *clock);
#define RAND_SEED_DEFAULT U64(1) #define RAND_SEED_DEFAULT U64(0xb0d1ccea)
void rand_init(u64 seed); void rand_init(u64 seed);
u64 rand64(void); u64 rand64(void);

View File

@@ -12,6 +12,7 @@
*/ */
#include <string.h> #include <string.h>
#include <assert.h>
#include <brlib.h> #include <brlib.h>
#include <bitops.h> #include <bitops.h>
@@ -99,9 +100,17 @@ hkey_t zobrist_calc(pos_t *pos)
* @return: True if Zobrist key is OK. * @return: True if Zobrist key is OK.
*/ */
#ifdef ZOBRIST_VERIFY #ifdef ZOBRIST_VERIFY
#pragma push_macro("BUG_ON") /* force BUG_ON and WARN_ON */
#pragma push_macro("WARN_ON")
#undef BUG_ON
#define BUG_ON
#undef WARN_ON
#define WARN_ON
bool zobrist_verify(pos_t *pos) bool zobrist_verify(pos_t *pos)
{ {
key_t diff, key = zobrist_calc(pos); hkey_t diff, key = zobrist_calc(pos);
if (pos->key == key) if (pos->key == key)
return true; return true;
@@ -120,17 +129,19 @@ bool zobrist_verify(pos_t *pos)
goto end; goto end;
} }
} }
for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c) for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c) {
if (diff == zobrist_castling[c]) { if (diff == zobrist_castling[c]) {
warn(true, "zobrist difference is castling:[%d]\n", c); warn(true, "zobrist difference is castling:[%d]\n", c);
goto end; goto end;
} }
}
for (file_t f = FILE_A; f <= FILE_H; ++f) for (file_t f = FILE_A; f <= FILE_H; ++f) {
if (diff == zobrist_ep[f]) { if (diff == zobrist_ep[f]) {
warn(true, "zobrist difference is ep:[%d]\n", f); warn(true, "zobrist difference is ep:[%d]\n", f);
goto end; goto end;
} }
}
if (diff == zobrist_turn) { if (diff == zobrist_turn) {
warn(true, "zobrist difference is turn\n"); warn(true, "zobrist difference is turn\n");
goto end; goto end;
@@ -138,11 +149,16 @@ bool zobrist_verify(pos_t *pos)
warn(true, "zobrist diff %lx is unknown\n", diff); warn(true, "zobrist diff %lx is unknown\n", diff);
end: end:
bug_on(false); bug_on(false);
/* not reached */
return true;
} }
#pragma pop_macro("WARN_ON")
#pragma pop_macro("BUG_ON")
#endif #endif
/** /**
* hash_create() - hashtable creation. * tt_create() - create transposition table
* @sizemb: s32 size of hash table in Mb * @sizemb: s32 size of hash table in Mb
* *
* Create a hash table of max @sizemb (or HASH_SIZE_MBif @sizemb <= 0) Mb size. * Create a hash table of max @sizemb (or HASH_SIZE_MBif @sizemb <= 0) Mb size.
@@ -164,7 +180,7 @@ end:
* @return: hash table size in Mb. If memory allocation fails, the function does * @return: hash table size in Mb. If memory allocation fails, the function does
* not return. * not return.
*/ */
int hash_create(s32 sizemb) int tt_create(s32 sizemb)
{ {
size_t bytes, target_nbuckets; size_t bytes, target_nbuckets;
u32 nbits; u32 nbits;
@@ -185,12 +201,12 @@ int hash_create(s32 sizemb)
if (hash_tt.nbits != nbits) { if (hash_tt.nbits != nbits) {
if (hash_tt.nbits) if (hash_tt.nbits)
hash_delete(); tt_delete();
hash_tt.nbits = nbits; hash_tt.nbits = nbits;
hash_tt.nbuckets = BIT(hash_tt.nbits); hash_tt.nbuckets = BIT(hash_tt.nbits);
hash_tt.nkeys = hash_tt.nbuckets * NBUCKETS; hash_tt.nkeys = hash_tt.nbuckets * ENTRIES_PER_BUCKET;
hash_tt.bytes = hash_tt.nbuckets * sizeof(bucket_t); hash_tt.bytes = hash_tt.nbuckets * sizeof(bucket_t);
hash_tt.mb = hash_tt.bytes / 1024 / 1024; hash_tt.mb = hash_tt.bytes / 1024 / 1024;
@@ -207,34 +223,173 @@ int hash_create(s32 sizemb)
// printf("unchanged (cleared)\n"); // printf("unchanged (cleared)\n");
//} //}
/* attention - may fail ! */ /* attention - may fail ! */
hash_clear(); tt_clear();
return hash_tt.nbits; return hash_tt.nbits;
} }
/** /**
* hash_clear() - clear hashtable data. * tt_clear() - clear transposition table
* *
* Reset hashtable entries (if available) and statistic information. * Reset hashtable entries (if available) and statistic information.
*/ */
void hash_clear() void tt_clear()
{ {
if (hash_tt.keys) if (hash_tt.keys)
memset(hash_tt.keys, 0, hash_tt.bytes); memset(hash_tt.keys, 0, hash_tt.bytes);
hash_tt.used_buckets = 0;
hash_tt.used_keys = 0; hash_tt.used_keys = 0;
hash_tt.collisions = 0; hash_tt.collisions = 0;
hash_tt.hits = 0;
hash_tt.misses = 0;
} }
/** /**
* hash_delete() - delete hashtable data. * tt_delete() - delete transposition table
* *
* free hashtable data. * free hashtable data.
*/ */
void hash_delete() void tt_delete()
{ {
if (hash_tt.keys) if (hash_tt.keys)
safe_free(hash_tt.keys); safe_free(hash_tt.keys);
memset(&hash_tt, 0, sizeof(hash_tt)); memset(&hash_tt, 0, sizeof(hash_tt));
} }
/**
* tt_probe() - probe tt for an entry
*
*
*/
hentry_t *tt_probe(hkey_t key)
{
bucket_t *bucket;
hentry_t *entry;
int i;
bug_on(!hash_tt.keys);
bucket = hash_tt.keys + (key & hash_tt.mask);
/* find key in buckets */
for (i = 0; i < ENTRIES_PER_BUCKET; ++i) {
entry = bucket->entry + i;
if (key == entry->key)
break;
}
if (i < ENTRIES_PER_BUCKET)
return entry;
return NULL;
}
/**
* tt_probe_perft() - probe tt for an entry (perft version)
* @key: Zobrist (hkey_t) key
* @depth: depth from search root
*
* Search transposition for @key entry with @depth depth.
*
* @return: @hentry_t address is found, TT_MISS otherwise.
*/
hentry_t *tt_probe_perft(const hkey_t key, const u16 depth)
{
bucket_t *bucket;
hentry_t *entry;
int i;
bug_on(!hash_tt.keys);
bucket = hash_tt.keys + (key & hash_tt.mask);
/* find key in buckets */
for (i = 0; i < ENTRIES_PER_BUCKET; ++i) {
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);
return entry;
}
}
//printf("tt miss: key=%lx bucket=%lu\n",
// key, bucket - hash_tt.keys);
hash_tt.misses++;
return TT_MISS;
}
/**
* tt_store_perft() - store a transposition table entry (perft version)
* @key: Zobrist (hkey_t) key
* @depth: depth from search root
* @nodes: value to store
*
*/
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;
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);
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;
break;
}
/* we replace hash if we are higher in tree */
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);
}
entry->key = key;
entry->data = data;
return entry;
} else {
printf("TT full, skip\n");
}
return NULL;
}
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);
}

View File

@@ -14,16 +14,18 @@
#ifndef HASH_H #ifndef HASH_H
#define HASH_H #define HASH_H
#include <assert.h> #include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#define NBUCKETS 4 /* buckets per hash table entry */ #define ENTRIES_PER_BUCKET 4 /* buckets per hash table entry */
#define HASH_SIZE_DEFAULT 32 /* default: 32Mb */ #define HASH_SIZE_DEFAULT 32 /* default: 32Mb */
#define HASH_SIZE_MIN 4 #define HASH_SIZE_MIN 4
#define HASH_SIZE_MAX 32768 /* 32Gb */ #define HASH_SIZE_MAX 32768 /* 32Gb */
#define TT_MISS NULL
typedef u64 hkey_t; /* cannot use typedef for key_t */ typedef u64 hkey_t; /* cannot use typedef for key_t */
/** /**
@@ -46,8 +48,18 @@ typedef struct {
}; };
} hentry_t; } hentry_t;
/* hentry perft data:
* 0-47: perft value
* 48-63: depth
*/
#define HASH_PERFT_MASK U64(0xffffffffffff)
#define HASH_PERFT(depth, val) ((((u64) depth) << 48) | ((val) & HASH_PERFT_MASK))
#define HASH_PERFT_VAL(data) ((data) & HASH_PERFT_MASK)
#define HASH_PERFT_DEPTH(data) ((u16)((data) >> 48))
typedef struct { typedef struct {
hentry_t buckets[NBUCKETS]; hentry_t entry[ENTRIES_PER_BUCKET];
} bucket_t; } bucket_t;
typedef struct { typedef struct {
@@ -66,9 +78,11 @@ typedef struct {
u32 mask; /* nbuckets - 1, key mask */ u32 mask; /* nbuckets - 1, key mask */
/* stats - unsure about usage */ /* stats - unsure about usage */
size_t used_buckets; //size_t used_buckets;
size_t used_keys; size_t used_keys;
u64 collisions; u64 collisions;
u64 hits;
u64 misses;
} hasht_t; } hasht_t;
/* hack: /* hack:
@@ -97,8 +111,25 @@ bool zobrist_verify(pos_t *pos);
#define zobrist_verify(p) true #define zobrist_verify(p) true
#endif #endif
int hash_create(int Mb); /**
void hash_clear(void); * tt_prefetch() - prefetch hash table entry
void hash_delete(void); * @hash: u64 key
*
* Prefetch memory for @key.
*/
static inline void tt_prefetch(hkey_t key)
{
bug_on(!hash_tt.keys);
__builtin_prefetch(hash_tt.keys + (key & hash_tt.mask));
}
int tt_create(int Mb);
void tt_clear(void);
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_stats(void);
#endif /* HASH_H */ #endif /* HASH_H */

View File

@@ -37,6 +37,6 @@ void init_all(void)
/* zobrist tables & default tt hashtable */ /* zobrist tables & default tt hashtable */
zobrist_init(); zobrist_init();
hash_create(HASH_SIZE_DEFAULT); tt_create(HASH_SIZE_DEFAULT);
} }

View File

@@ -108,7 +108,8 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state)
} }
} else if (is_enpassant(move)) { /* clear grabbed pawn */ } else if (is_enpassant(move)) { /* clear grabbed pawn */
square_t grabbed = to - up; square_t grabbed = to - up;
key ^= zobrist_pieces[pos->board[grabbed]][grabbed]; piece_t pc = pos->board[grabbed];
key ^= zobrist_pieces[pc][grabbed];
pos_clr_sq(pos, grabbed); pos_clr_sq(pos, grabbed);
} }
} }

View File

@@ -429,9 +429,10 @@ void pos_print(const pos_t *pos)
char str[128]; char str[128];
board_print(pos->board); board_print(pos->board);
printf("fen %s\n", pos2fen(pos, str)); printf("key:%lx ", pos->key);
printf("checkers: %s\n", pos_checkers2str(pos, str, sizeof(str))); printf("fen: %s\n", pos2fen(pos, str));
printf("pinners : %s\n", pos_pinners2str(pos, str, sizeof(str))); printf("checkers:%s ", pos_checkers2str(pos, str, sizeof(str)));
printf("pinners: %s ", pos_pinners2str(pos, str, sizeof(str)));
printf("blockers: %s\n", pos_blockers2str(pos, str, sizeof(str))); printf("blockers: %s\n", pos_blockers2str(pos, str, sizeof(str)));
} }

View File

@@ -43,13 +43,16 @@
*/ */
u64 perft(pos_t *pos, int depth, int ply, bool output) u64 perft(pos_t *pos, int depth, int ply, bool output)
{ {
int subnodes; static movelist_t stack;
u64 nodes = 0; //int subnodes;
u64 subnodes, nodes = 0;
movelist_t movelist; movelist_t movelist;
move_t *move, *last; move_t *move, *last;
state_t state; state_t state;
movelist.nmoves = 0; if (ply == 1)
stack.nmoves = 0;
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
pos_legal(pos, pos_gen_pseudo(pos, &movelist)); pos_legal(pos, pos_gen_pseudo(pos, &movelist));
@@ -59,19 +62,46 @@ u64 perft(pos_t *pos, int depth, int ply, bool output)
nodes++; nodes++;
} else { } else {
move_do(pos, *move, &state); move_do(pos, *move, &state);
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);
}
if (depth == 2) { if (depth == 2) {
movelist_t movelist2; movelist_t movelist2;
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; 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 { } else {
subnodes = perft(pos, depth - 1, ply + 1, output); 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) { if (output && ply == 1) {
char movestr[8]; char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes); printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes);
} }
nodes += subnodes; nodes += subnodes;
move_undo(pos, *move, &state); move_undo(pos, *move, &state);
stack.nmoves--;
} }
} }
@@ -99,7 +129,7 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output)
move_t *move, *last; move_t *move, *last;
state_t state; state_t state;
movelist.nmoves = 0; //movelist.nmoves = 0;
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
state = pos->state; state = pos->state;
@@ -119,7 +149,7 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output)
} }
if (output && ply == 1) { if (output && ply == 1) {
char movestr[8]; char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes); printf("%s: %d\n", move_to_str(movestr, *move, 0), subnodes);
} }
nodes += subnodes; nodes += subnodes;
move_undo_alt(pos, *move); move_undo_alt(pos, *move);

View File

@@ -28,14 +28,30 @@ struct fentest {
char *comment; char *comment;
char *fen; char *fen;
} fentest[] = { } fentest[] = {
/******************* TEMP TESTS BELOW *******************/
/* /*
{ __LINE__, 1, * { __LINE__, MOVEGEN | MOVEDO | PERFT,
"", * "bug perft TT après 1.b4 f5",
"" * "1nbqkbn1/ppp1p1pp/8/r1rpPpK1/1P6/8/P1PP1PPP/RNBQ1BNR w - f6 0 2"
}, * },
*/ */
/* ***************** TEMP TESTS ABOVE ************************** */ /*
* { __LINE__, MOVEGEN | MOVEDO | PERFT,
* "bug perft TT après 1.b4",
* "1nbqkbn1/ppp1pppp/8/r1rpP1K1/1P6/8/P1PP1PPP/RNBQ1BNR b - - 0 1",
* },
*/
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
"bug perft TT",
"1nbqkbn1/ppp1pppp/8/r1rpP1K1/8/8/PPPP1PPP/RNBQ1BNR w - d6 0 1",
},
/* ***************** END of TEMP TESTS ******************/
/* below line ignored if first test */
{ __LINE__, 0, NULL, NULL },
{ __LINE__, MOVEGEN | MOVEDO | PERFT, { __LINE__, MOVEGEN | MOVEDO | PERFT,
"illegal white e.p.", "illegal white e.p.",
@@ -425,6 +441,10 @@ static int fentest_cur = -1;
static char *next_fen(uint module) static char *next_fen(uint module)
{ {
fentest_cur++; fentest_cur++;
/* skip first entry if NULL - for special testing, see */
if (fentest_cur == 0 && fentest[fentest_cur].fen == NULL)
fentest_cur++;
while (fentest[fentest_cur].fen && !(fentest[fentest_cur].modules & module)) while (fentest[fentest_cur].fen && !(fentest[fentest_cur].modules & module))
fentest_cur++; fentest_cur++;
return fentest[fentest_cur].fen; return fentest[fentest_cur].fen;

View File

@@ -59,7 +59,7 @@ int main(int __unused ac, __unused char**av)
//fflush(stdout); //fflush(stdout);
if (!pos_ok(pos, false)) { if (!pos_ok(pos, false)) {
printf("*** fen %d [%s] move %d [%s] invalid position after move_do\n", printf("*** fen %d [%s] move %d [%s] invalid position after move_do\n",
test_line, fen, j, move_str(movebuf, *move, 0)); test_line, fen, j, move_to_str(movebuf, *move, 0));
exit(0); exit(0);
} }

View File

@@ -255,8 +255,8 @@ static __unused void compare_moves(movelist_t *fish, movelist_t *me)
static int usage(char *prg) static int usage(char *prg)
{ {
fprintf(stderr, "Usage: %s [-d depth] [-p pertf-modules] [-n][-v]\n", prg); fprintf(stderr, "Usage: %s [-cmv][-d depth] [-p perft-version] \n", prg);
fprintf(stderr, "\t-d: depth, -p: 1-3, -n: no SF res check, -v: output moves\n"); fprintf(stderr, "\t-c/m: print comments/moves, -n: no SF check, -d: depth, -p: 1-3, \n");
return 1; return 1;
} }
@@ -264,6 +264,7 @@ int main(int ac, char**av)
{ {
int test_line; int test_line;
u64 sf_count = 0, my_count; u64 sf_count = 0, my_count;
bool comment = false;
char *fen; char *fen;
pos_t *pos = NULL, *fenpos; pos_t *pos = NULL, *fenpos;
pos_t *fishpos = pos_new(); pos_t *fishpos = pos_new();
@@ -283,8 +284,11 @@ int main(int ac, char**av)
int opt, depth = 6, run = 3; int opt, depth = 6, run = 3;
bool sf_run = true, perft_output = false; bool sf_run = true, perft_output = false;
while ((opt = getopt(ac, av, "vnd:p:")) != -1) { while ((opt = getopt(ac, av, "cmnd:p:")) != -1) {
switch (opt) { switch (opt) {
case 'c':
comment = true;
break;
case 'd': case 'd':
depth = atoi(optarg); depth = atoi(optarg);
break; break;
@@ -294,7 +298,7 @@ int main(int ac, char**av)
case 'n': case 'n':
sf_run = false; sf_run = false;
break; break;
case 'v': case 'm':
perft_output = true; perft_output = true;
break; break;
default: default:
@@ -315,7 +319,10 @@ int main(int ac, char**av)
CLOCK_DEFINE(clock, CLOCK_MONOTONIC); CLOCK_DEFINE(clock, CLOCK_MONOTONIC);
while ((fen = next_fen(PERFT | MOVEDO))) { while ((fen = next_fen(PERFT | MOVEDO))) {
if (comment)
printf("%s\n", *cur_comment()? cur_comment(): "<FIXME>");
test_line = cur_line(); test_line = cur_line();
tt_clear();
if (!(fenpos = fen2pos(pos, fen))) { if (!(fenpos = fen2pos(pos, fen))) {
printf("wrong fen line = %d: [%s]\n", test_line, fen); printf("wrong fen line = %d: [%s]\n", test_line, fen);
continue; continue;
@@ -370,6 +377,7 @@ int main(int ac, char**av)
printf("pt1 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n", printf("pt1 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
test_line, sf_count, my_count, fen); test_line, sf_count, my_count, fen);
} }
tt_stats();
} }
if (run & 2) { if (run & 2) {

159
test/tt-test.c Normal file
View File

@@ -0,0 +1,159 @@
/* tt-test.c - transposition table test.
*
* Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include <locale.h>
#include <limits.h>
#include <brlib.h>
#include "chessdefs.h"
#include "fen.h"
#include "position.h"
#include "move.h"
#include "move-do.h"
#include "move-gen.h"
#include "search.h"
// #include "common-test.h"
static move_t move_in_movelist(movelist_t *ml, square_t from, square_t to, piece_type_t pt)
{
const int nmoves = ml->nmoves;
const move_t *moves = ml->move;
int movenum = 0;
move_t move;
for (movenum = 0; movenum < nmoves; ++movenum) {
move = moves[movenum];
printf("compare %s%s to %s%s pt=%d ",
sq_to_string(from), sq_to_string(to),
sq_to_string(move_from(move)),
sq_to_string(move_to(move)),
pt
);
if (move_from(move) == from && move_to(move) == to) {
printf("HIT!\n");
if (pt != NO_PIECE_TYPE && move_promoted(move) != pt)
continue;
printf("move_in_movelist(%s%s) found from=%s to=%s\n",
sq_to_string(from), sq_to_string(to),
sq_to_string(move_from(move)),
sq_to_string(move_to(move)));
return move;
} else
puts("");
}
return MOVE_NONE;
}
static move_t move_from_str(pos_t *pos, const char *move)
{
movelist_t movelist;
square_t from = sq_from_string(move);
square_t to = sq_from_string(move + 2);
piece_type_t promoted = piece_t_from_char(*(move + 4));
printf("from=%o to=%o promoted=%d\n", from, to, promoted);
pos_set_checkers_pinners_blockers(pos);
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
return move_in_movelist(&movelist, from, to, promoted);
}
static void pr_entry(hentry_t *entry)
{
if (!entry)
printf("entry: NULL\n");
else {
printf("entry: key=%lx depth=%d n=%lu\n",
entry->key, HASH_PERFT_DEPTH(entry->data),
HASH_PERFT_VAL(entry->data));
}
}
int main()
{
pos_t *pos = NULL;
char *token, *str, buf[128];
hentry_t *entry;
move_t move;
state_t state;
//movelist_t movelist;
const char *moves_array[] = {
"e2e4 e7e5 g1f3 b8c6",
"e2e4 b8c6 g1f3 e7e5"
};
init_all();
for (uint i = 0; i < ARRAY_SIZE(moves_array); ++i) {
int depth = 0;
str = strdup(moves_array[i]);
printf("%2d: ", i + 1);
pos = startpos(pos);
entry = tt_store_perft(pos->key, 0, 123 + depth);
pr_entry(entry);
token = strtok(str, " \t");
while (token) {
depth++;
printf("%s ", token);
//pos_set_checkers_pinners_blockers(pos);
//pos_legal(pos, pos_gen_pseudo(pos, &movelist));
move = move_from_str(pos, token);
printf("move: %s\n", move_to_str(buf, move, 0));
move_do(pos, move, &state);
if ((entry = tt_probe_perft(pos->key, depth))) {
printf("tt hit: depth=%d val=%lu",
HASH_PERFT_DEPTH(entry->data),
HASH_PERFT_VAL(entry->data));
} else {
tt_store_perft(pos->key, i + 1, depth);
printf("tt store: depth=%d val=%lu", depth, (u64)i * 123);
};
token = strtok(NULL, " \t");
}
printf("\n");
free(str);
}
return 0;
}
/* ccls bug report: https://github.com/emacs-lsp/emacs-ccls/issues/126
*/
/*
* int called(int), caller();
*
* /\**
* * called() - test ccls.
* * @x: int, the test value
* *
* * @called() description.
* *
* * @return: int, a very interesting value.
* *\/
* int called(int x) { return x; }
*
* int caller()
* {
* int i = 0;
* called(int x)
* return i;
* }
*/