Merge branch 'hash'
This commit is contained in:
15
Makefile
15
Makefile
@@ -55,8 +55,9 @@ CPPFILES := $(SRC:.c=.i) $(TSTSRC:.c=.i)
|
|||||||
##################################### pre-processor flags
|
##################################### pre-processor flags
|
||||||
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
|
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR)
|
||||||
|
|
||||||
CPPFLAGS += -DNDEBUG # assert
|
CPPFLAGS += -DNDEBUG # assert (unused)
|
||||||
CPPFLAGS += -DWARN_ON # brlib bug.h
|
CPPFLAGS += -DWARN_ON # brlib bug.h
|
||||||
|
CPPFLAGS += -DBUG_ON # brlib bug.h
|
||||||
|
|
||||||
#CPPFLAGS += -DDEBUG # global - unused
|
#CPPFLAGS += -DDEBUG # global - unused
|
||||||
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
||||||
@@ -68,6 +69,9 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
|
|||||||
# fen.c
|
# fen.c
|
||||||
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
|
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
|
||||||
|
|
||||||
|
# hash.c
|
||||||
|
#CPPFLAGS += -HASH_VERIFY # chk zobrist consistency
|
||||||
|
|
||||||
# attack.c
|
# attack.c
|
||||||
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
|
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
|
||||||
#CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
|
#CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
|
||||||
@@ -78,9 +82,6 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
|
|||||||
|
|
||||||
CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams
|
CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams
|
||||||
|
|
||||||
# Never comment this one !
|
|
||||||
CPPFLAGS += -DBUG_ON # brlib bug.h
|
|
||||||
|
|
||||||
# remove extraneous spaces (due to spaces before comments)
|
# remove extraneous spaces (due to spaces before comments)
|
||||||
CPPFLAGS := $(strip $(CPPFLAGS))
|
CPPFLAGS := $(strip $(CPPFLAGS))
|
||||||
|
|
||||||
@@ -342,12 +343,12 @@ TEST += movedo-test perft-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 \
|
||||||
hyperbola-quintessence.o attack.o
|
hyperbola-quintessence.o attack.o hash.o init.o
|
||||||
BB_OBJS := $(FEN_OBJS)
|
BB_OBJS := $(FEN_OBJS)
|
||||||
MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o
|
MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o
|
||||||
ATTACK_OBJS := $(MOVEGEN_OBJS)
|
ATTACK_OBJS := $(MOVEGEN_OBJS)
|
||||||
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o
|
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o misc.o
|
||||||
PERFT_OBJS := $(MOVEDO_OBJS) search.o misc.o
|
PERFT_OBJS := $(MOVEDO_OBJS) search.o
|
||||||
|
|
||||||
TEST := $(addprefix $(BINDIR)/,$(TEST))
|
TEST := $(addprefix $(BINDIR)/,$(TEST))
|
||||||
|
|
||||||
|
2
brlib
2
brlib
Submodule brlib updated: 8ff163dcf5...7bedfddfba
46
scripts/fetch-all.sh
Executable file
46
scripts/fetch-all.sh
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
origin=origin
|
||||||
|
|
||||||
|
declare -a remotes local
|
||||||
|
|
||||||
|
readarray -t remotes < <(git remote)
|
||||||
|
declare -A aremotes alocal_b
|
||||||
|
|
||||||
|
# fetch all remotes
|
||||||
|
for remote in "${remotes[@]}"; do
|
||||||
|
aremotes["$remote"]=1
|
||||||
|
echo doing git fetch -a "$remote"
|
||||||
|
done
|
||||||
|
|
||||||
|
# get local branches
|
||||||
|
readarray -t local_b < <(git for-each-ref --format='%(refname:short)' refs/heads/)
|
||||||
|
|
||||||
|
# build local ref array
|
||||||
|
for ref in "${local_b[@]}"; do
|
||||||
|
alocal_b[$ref]=1
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
readarray -t orig_b < <(git for-each-ref --format='%(refname:short)' \
|
||||||
|
refs/remotes/"$origin"/)
|
||||||
|
|
||||||
|
declare -p remotes
|
||||||
|
#declare -p aremotes
|
||||||
|
declare -p local_b orig_b
|
||||||
|
|
||||||
|
# find-out missing local branches
|
||||||
|
for remote_b in "${orig_b[@]}"; do
|
||||||
|
short=${remote_b#"$origin"/};
|
||||||
|
echo "$remote_b -> $short ${alocal_b[$short]}"
|
||||||
|
if ! [[ -v alocal_b[$short] ]]; then
|
||||||
|
echo git switch -t "$remote_b"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#git remote | xargs -n 1 git fetch -a
|
@@ -178,4 +178,6 @@ double clock_elapsed_sec(mclock_t *clock);
|
|||||||
void rand_init(u64 seed);
|
void rand_init(u64 seed);
|
||||||
u64 rand64(void);
|
u64 rand64(void);
|
||||||
|
|
||||||
|
void init_all(void);
|
||||||
|
|
||||||
#endif /* _CHESSDEFS_H */
|
#endif /* _CHESSDEFS_H */
|
||||||
|
@@ -184,6 +184,8 @@ pos_t *fen2pos(pos_t *pos, const char *fen)
|
|||||||
piece, PIECE(piece), COLOR(piece));
|
piece, PIECE(piece), COLOR(piece));
|
||||||
# endif
|
# endif
|
||||||
pos_set_sq(&tmppos, sq_make(file, rank), piece);
|
pos_set_sq(&tmppos, sq_make(file, rank), piece);
|
||||||
|
if (PIECE(piece) == KING)
|
||||||
|
tmppos.king[COLOR(piece)] = sq_make(file, rank);
|
||||||
file++;
|
file++;
|
||||||
} else { /* error */
|
} else { /* error */
|
||||||
err_line = __LINE__, err_char = *cur, err_pos = cur - fen;
|
err_line = __LINE__, err_char = *cur, err_pos = cur - fen;
|
||||||
@@ -250,8 +252,10 @@ end:
|
|||||||
}
|
}
|
||||||
if (fen_check(&tmppos) < 0)
|
if (fen_check(&tmppos) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
tmppos.key = zobrist_calc(&tmppos);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
pos = pos_dup(&tmppos);
|
pos = pos_new();
|
||||||
|
pos_copy(&tmppos, pos);
|
||||||
//puts("prout 1");
|
//puts("prout 1");
|
||||||
//pos_print_raw(&tmppos, 1);
|
//pos_print_raw(&tmppos, 1);
|
||||||
//puts("prout 2");
|
//puts("prout 2");
|
||||||
|
240
src/hash.c
Normal file
240
src/hash.c
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/* hash.c - hash management.
|
||||||
|
*
|
||||||
|
* 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 <string.h>
|
||||||
|
|
||||||
|
#include <brlib.h>
|
||||||
|
#include <bitops.h>
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "position.h"
|
||||||
|
#include "piece.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
u64 zobrist_pieces[16][64];
|
||||||
|
u64 zobrist_castling[4 * 4 + 1];
|
||||||
|
u64 zobrist_turn; /* for black, XOR each ply */
|
||||||
|
u64 zobrist_ep[9]; /* 0-7: ep file, 8: SQUARE_NONE */
|
||||||
|
|
||||||
|
hasht_t hash_tt; /* main transposition table */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zobrist_init() - initialize zobrist tables.
|
||||||
|
*
|
||||||
|
* Initialize all zobrist random bitmasks. Must be called before any other
|
||||||
|
* zobrist function, and can be called once only (further calls will be ignored).
|
||||||
|
*/
|
||||||
|
void zobrist_init(void)
|
||||||
|
{
|
||||||
|
static bool called = false;
|
||||||
|
if (!called) {
|
||||||
|
called = true;
|
||||||
|
for (color_t c = WHITE; c <= BLACK; ++c) {
|
||||||
|
for (piece_type_t p = PAWN; p <= KING; ++p)
|
||||||
|
for (square_t sq = A1; sq <= H8; ++sq)
|
||||||
|
zobrist_pieces[MAKE_PIECE(p, c)][sq] = rand64();
|
||||||
|
}
|
||||||
|
for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c)
|
||||||
|
zobrist_castling[c] = rand64();
|
||||||
|
for (file_t f = FILE_A; f <= FILE_H; ++f)
|
||||||
|
zobrist_ep[f] = rand64();
|
||||||
|
zobrist_ep[8] = 0; /* see EP_ZOBRIST_IDX macro */
|
||||||
|
zobrist_turn = rand64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zobrist_calc() - calculate a position zobrist hash.
|
||||||
|
* @pos: &position
|
||||||
|
*
|
||||||
|
* Normally, Zobrist keys are incrementally calculated when doing or
|
||||||
|
* undoing a move.
|
||||||
|
* This function should normally only be called:
|
||||||
|
* - When starting a new position
|
||||||
|
* - To verify incremental Zobrist calculation is correct
|
||||||
|
*
|
||||||
|
* @return: @pos Zobrist key
|
||||||
|
*/
|
||||||
|
key_t zobrist_calc(pos_t *pos)
|
||||||
|
{
|
||||||
|
key_t key = 0;
|
||||||
|
|
||||||
|
if (pos->turn == BLACK)
|
||||||
|
key ^= zobrist_turn;
|
||||||
|
|
||||||
|
for (color_t c = WHITE; c <= BLACK; ++c) {
|
||||||
|
for (piece_type_t pt = PAWN; pt <= KING; ++pt) {
|
||||||
|
piece_t piece = MAKE_PIECE(pt, c);
|
||||||
|
bitboard_t bb = pos->bb[c][pt];
|
||||||
|
while (bb) {
|
||||||
|
square_t sq = bb_next(&bb);
|
||||||
|
key ^= zobrist_pieces[piece][sq];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zobrist_verify() - verify current position Zobrist key.
|
||||||
|
* @pos: &position
|
||||||
|
*
|
||||||
|
* Verify that position Zobrist key matches a full Zobrist calculation.
|
||||||
|
* This function cannot be called if ZOBRIST_VERIFY is not set.
|
||||||
|
*
|
||||||
|
* @return: True if Zobrist key is OK.
|
||||||
|
*/
|
||||||
|
#ifdef ZOBRIST_VERIFY
|
||||||
|
bool zobrist_verify(pos_t *pos)
|
||||||
|
{
|
||||||
|
key_t diff, key = zobrist_calc(pos);
|
||||||
|
|
||||||
|
if (pos->key == key)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
printf("key verify: cur=%#lx != %#lx\n", pos->key, key);
|
||||||
|
|
||||||
|
/* try to find-out the key in different zobrist tables */
|
||||||
|
diff = pos->key ^ key;
|
||||||
|
|
||||||
|
for (color_t c = WHITE; c <= BLACK; ++c) {
|
||||||
|
for (piece_type_t p = PAWN; p <= KING; ++p)
|
||||||
|
for (square_t sq = A1; sq <= H8; ++sq)
|
||||||
|
if (diff == zobrist_pieces[MAKE_PIECE(p, c)][sq]) {
|
||||||
|
warn(true, "zobrist difference is piece:[%s][%s]\n",
|
||||||
|
piece_to_fen(MAKE_PIECE(p, c)), sq_to_string(sq));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (castle_rights_t c = CASTLE_NONE; c <= CASTLE_ALL; ++c)
|
||||||
|
if (diff == zobrist_castling[c]) {
|
||||||
|
warn(true, "zobrist difference is castling:[%d]\n", c);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (file_t f = FILE_A; f <= FILE_H; ++f)
|
||||||
|
if (diff == zobrist_ep[f]) {
|
||||||
|
warn(true, "zobrist difference is ep:[%d]\n", f);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (diff == zobrist_turn) {
|
||||||
|
warn(true, "zobrist difference is turn\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
warn(true, "zobrist diff %lx is unknown\n", diff);
|
||||||
|
end:
|
||||||
|
bug_on(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash_create() - hashtable creation.
|
||||||
|
* @sizemb: s32 size of hash table in Mb
|
||||||
|
*
|
||||||
|
* Create a hash table of max @sizemb (or HASH_SIZE_MBif @sizemb <= 0) Mb size.
|
||||||
|
* This function must be called at startup.
|
||||||
|
*
|
||||||
|
* The number of bucket_t entries fitting in @sizemb is calculated, and rounded
|
||||||
|
* (down) to a power of 2.
|
||||||
|
* This means the actual size could be lower than @sizemb (nearly halved in
|
||||||
|
* worst case).
|
||||||
|
*
|
||||||
|
* If transposition hashtable already exists and new size would not change,
|
||||||
|
* the old one is cleared.
|
||||||
|
* If transposition hashtable already exists and new size is different,
|
||||||
|
* the old one is destroyed first (old data is not preserved).
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - Rebuild old hashtable data ?
|
||||||
|
*
|
||||||
|
* @return: hash table size in Mb. If memory allocation fails, the function does
|
||||||
|
* not return.
|
||||||
|
*/
|
||||||
|
int hash_create(s32 sizemb)
|
||||||
|
{
|
||||||
|
size_t bytes, target_nbuckets;
|
||||||
|
u32 nbits;
|
||||||
|
|
||||||
|
static_assert(sizeof(hentry_t) == 16, "fatal: hentry_t size != 16");
|
||||||
|
|
||||||
|
//printf("mb = %'7u ", sizemb);
|
||||||
|
/* adjust tt size */
|
||||||
|
if (sizemb <= 0)
|
||||||
|
sizemb = HASH_SIZE_DEFAULT;
|
||||||
|
sizemb = clamp(sizemb, HASH_SIZE_MIN, HASH_SIZE_MAX);
|
||||||
|
//printf("-> %'6d ", sizemb);
|
||||||
|
|
||||||
|
bytes = sizemb * 1024ull * 1024ull; /* bytes wanted */
|
||||||
|
target_nbuckets = bytes / sizeof(bucket_t); /* target buckets */
|
||||||
|
|
||||||
|
nbits = msb64(target_nbuckets); /* adjust to power of 2 */
|
||||||
|
|
||||||
|
if (hash_tt.nbits != nbits) {
|
||||||
|
if (hash_tt.nbits)
|
||||||
|
hash_delete();
|
||||||
|
|
||||||
|
hash_tt.nbits = nbits;
|
||||||
|
|
||||||
|
hash_tt.nbuckets = BIT(hash_tt.nbits);
|
||||||
|
hash_tt.nkeys = hash_tt.nbuckets * NBUCKETS;
|
||||||
|
|
||||||
|
hash_tt.bytes = hash_tt.nbuckets * sizeof(bucket_t);
|
||||||
|
hash_tt.mb = hash_tt.bytes / 1024 / 1024;
|
||||||
|
|
||||||
|
hash_tt.mask = -1ull >> (64 - nbits);
|
||||||
|
|
||||||
|
hash_tt.keys = safe_malloc(hash_tt.bytes);
|
||||||
|
|
||||||
|
//printf("bits=%2d size=%'15lu/%'6d Mb/%'14lu buckets ",
|
||||||
|
// hash_tt.nbits, hash_tt.bytes, hash_tt.mb, hash_tt.nbuckets);
|
||||||
|
//printf("mask=%9x\n", hash_tt.mask);
|
||||||
|
}
|
||||||
|
//else {
|
||||||
|
// printf("unchanged (cleared)\n");
|
||||||
|
//}
|
||||||
|
/* attention - may fail ! */
|
||||||
|
hash_clear();
|
||||||
|
|
||||||
|
return hash_tt.nbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash_clear() - clear hashtable data.
|
||||||
|
*
|
||||||
|
* Reset hashtable entries (if available) and statistic information.
|
||||||
|
*/
|
||||||
|
void hash_clear()
|
||||||
|
{
|
||||||
|
if (hash_tt.keys)
|
||||||
|
memset(hash_tt.keys, 0, hash_tt.bytes);
|
||||||
|
|
||||||
|
hash_tt.used_buckets = 0;
|
||||||
|
hash_tt.used_keys = 0;
|
||||||
|
hash_tt.collisions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash_delete() - delete hashtable data.
|
||||||
|
*
|
||||||
|
* free hashtable data.
|
||||||
|
*/
|
||||||
|
void hash_delete()
|
||||||
|
{
|
||||||
|
if (hash_tt.keys)
|
||||||
|
safe_free(hash_tt.keys);
|
||||||
|
memset(&hash_tt, 0, sizeof(hash_tt));
|
||||||
|
}
|
104
src/hash.h
Normal file
104
src/hash.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/* hash.h - hash management.
|
||||||
|
*
|
||||||
|
* 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>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HASH_H
|
||||||
|
#define HASH_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
|
|
||||||
|
#define NBUCKETS 4 /* buckets per hash table entry */
|
||||||
|
|
||||||
|
#define HASH_SIZE_DEFAULT 32 /* default: 32Mb */
|
||||||
|
#define HASH_SIZE_MIN 4
|
||||||
|
#define HASH_SIZE_MAX 32768 /* 32Gb */
|
||||||
|
|
||||||
|
#define key_t u64 /* cannot use typedef for key_t */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hentry_t: hashtable bucket.
|
||||||
|
*
|
||||||
|
* Size should be exactly 16 bytes. If impossible to fit necessary data in
|
||||||
|
* 16 bytes in future, it should be updated to be exactly 32 bytes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
key_t key; /* zobrist */
|
||||||
|
union {
|
||||||
|
u64 data;
|
||||||
|
struct {
|
||||||
|
u16 depth; /* ply in search */
|
||||||
|
s16 eval;
|
||||||
|
u16 move;
|
||||||
|
u8 flags; /* maybe for locking, etc... */
|
||||||
|
u8 filler;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} hentry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
hentry_t buckets[NBUCKETS];
|
||||||
|
} bucket_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bucket_t *keys; /* &hashtable entries */
|
||||||
|
|
||||||
|
/* memory size in bytes/mb */
|
||||||
|
size_t bytes;
|
||||||
|
u32 mb;
|
||||||
|
|
||||||
|
/* size in buckets/keys */
|
||||||
|
size_t nbuckets;
|
||||||
|
size_t nkeys; /* nbuckets * NBUCKETS */
|
||||||
|
|
||||||
|
/* internal representation */
|
||||||
|
u32 nbits; /* #buckets in bits, power of 2 */
|
||||||
|
u32 mask; /* nbuckets - 1, key mask */
|
||||||
|
|
||||||
|
/* stats - unsure about usage */
|
||||||
|
size_t used_buckets;
|
||||||
|
size_t used_keys;
|
||||||
|
u64 collisions;
|
||||||
|
} hasht_t;
|
||||||
|
|
||||||
|
/* hack:
|
||||||
|
* ep zobrist key index is 0-7 for each en-passant file, 8 for SQUARE_NONE.
|
||||||
|
* To transform :
|
||||||
|
* - ep == 64 (SQUARE_NONE) to id = 8
|
||||||
|
* - ep == 0~63 to idx = sq_file(ep), i.e. (ep & 7)
|
||||||
|
* we use the formula:
|
||||||
|
* idx = ( ( ep & SQUARE_NONE ) >> 3 ) | sq_file(ep);
|
||||||
|
*/
|
||||||
|
#define EP_ZOBRIST_IDX(ep) ( ( (ep) >> 3 ) | sq_file(ep) )
|
||||||
|
|
||||||
|
extern key_t zobrist_pieces[16][64];
|
||||||
|
extern key_t zobrist_castling[4 * 4 + 1];
|
||||||
|
extern key_t zobrist_turn; /* for black, XOR each ply */
|
||||||
|
extern key_t zobrist_ep[9]; /* 0-7: ep file, 8: SQUARE_NONE */
|
||||||
|
|
||||||
|
extern hasht_t hash_tt; /* main transposition table */
|
||||||
|
|
||||||
|
void zobrist_init(void);
|
||||||
|
key_t zobrist_calc(pos_t *pos);
|
||||||
|
|
||||||
|
#ifdef ZOBRIST_VERIFY
|
||||||
|
bool zobrist_verify(pos_t *pos);
|
||||||
|
#else
|
||||||
|
#define zobrist_verify(p) true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int hash_create(int Mb);
|
||||||
|
void hash_clear(void);
|
||||||
|
void hash_delete(void);
|
||||||
|
|
||||||
|
#endif /* HASH_H */
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
void init_all()
|
void init_all(void)
|
||||||
{
|
{
|
||||||
/* for printf() numeric thousands separator */
|
/* for printf() numeric thousands separator */
|
||||||
setlocale(LC_NUMERIC, "");
|
setlocale(LC_NUMERIC, "");
|
||||||
@@ -37,6 +37,6 @@ void init_all()
|
|||||||
|
|
||||||
/* zobrist tables & default tt hashtable */
|
/* zobrist tables & default tt hashtable */
|
||||||
zobrist_init();
|
zobrist_init();
|
||||||
hash_create(HASH_DEFAULT);
|
hash_create(HASH_SIZE_DEFAULT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "move-do.h"
|
#include "move-do.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* move_do() - do move.
|
* move_do() - do move.
|
||||||
@@ -39,8 +40,12 @@
|
|||||||
* - castling
|
* - castling
|
||||||
* - en-passant
|
* - en-passant
|
||||||
* - captured piece (excl. en-passant)
|
* - captured piece (excl. en-passant)
|
||||||
|
* - tt hash values are updated for:
|
||||||
|
* - side-to-move
|
||||||
|
* - en-passant
|
||||||
|
* - castling rights.
|
||||||
*
|
*
|
||||||
* @return: pos.
|
* @return: updated pos.
|
||||||
*/
|
*/
|
||||||
pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
||||||
{
|
{
|
||||||
@@ -56,6 +61,12 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
piece_type_t ptype = PIECE(piece);
|
piece_type_t ptype = PIECE(piece);
|
||||||
piece_t new_piece = piece;
|
piece_t new_piece = piece;
|
||||||
int up = sq_up(us);
|
int up = sq_up(us);
|
||||||
|
key_t key = pos->key;
|
||||||
|
|
||||||
|
/* update key: switch turn, reset castling and ep */
|
||||||
|
key ^= zobrist_turn;
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
|
||||||
++pos->clock_50;
|
++pos->clock_50;
|
||||||
++pos->plycount;
|
++pos->plycount;
|
||||||
@@ -74,6 +85,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
//pos->captured = pos->board[to]; /* save capture info */
|
//pos->captured = pos->board[to]; /* save capture info */
|
||||||
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
||||||
|
key ^= zobrist_pieces[captured][to];
|
||||||
pos_clr_sq(pos, to); /* clear square */
|
pos_clr_sq(pos, to); /* clear square */
|
||||||
} else if (is_castle(move)) { /* handle rook move */
|
} else if (is_castle(move)) { /* handle rook move */
|
||||||
square_t rookfrom, rookto;
|
square_t rookfrom, rookto;
|
||||||
@@ -84,20 +96,26 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
rookfrom = sq_rel(A1, us);
|
rookfrom = sq_rel(A1, us);
|
||||||
rookto = sq_rel(D1, us);
|
rookto = sq_rel(D1, us);
|
||||||
}
|
}
|
||||||
|
key ^= zobrist_pieces[pos->board[rookfrom]][rookto] ^
|
||||||
|
zobrist_pieces[pos->board[rookfrom]][rookfrom];
|
||||||
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
||||||
pos_clr_sq(pos, rookfrom);
|
pos_clr_sq(pos, rookfrom);
|
||||||
pos->castle = clr_castle(pos->castle, us);
|
//pos->castle = clr_castle(pos->castle, us);
|
||||||
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
if (is_dpush(move)) /* if pawn double push, set e.p. */
|
if (is_dpush(move)) { /* if pawn double push, set e.p. */
|
||||||
pos->en_passant = from + up;
|
pos->en_passant = from + up;
|
||||||
else if (is_enpassant(move)) { /* clear grabbed pawn */
|
/* update ep key */
|
||||||
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
} 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];
|
||||||
pos_clr_sq(pos, grabbed);
|
pos_clr_sq(pos, grabbed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_clr_sq(pos, from); /* always clear "from" and set "to" */
|
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
|
||||||
|
pos_clr_sq(pos, from); /* clear "from" and set "to" */
|
||||||
pos_set_sq(pos, to, new_piece);
|
pos_set_sq(pos, to, new_piece);
|
||||||
|
|
||||||
if (ptype == KING)
|
if (ptype == KING)
|
||||||
@@ -119,7 +137,7 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
else if (from == rel_h1)
|
else if (from == rel_h1)
|
||||||
pos->castle = clr_oo(pos->castle, us);
|
pos->castle = clr_oo(pos->castle, us);
|
||||||
}
|
}
|
||||||
if (can_castle(pos->castle, them)) { /* do we save time with this test ? */
|
if (can_castle(pos->castle, them)) {
|
||||||
square_t rel_a8 = sq_rel(A8, us);
|
square_t rel_a8 = sq_rel(A8, us);
|
||||||
square_t rel_h8 = sq_rel(H8, us);
|
square_t rel_h8 = sq_rel(H8, us);
|
||||||
if (to == rel_a8)
|
if (to == rel_a8)
|
||||||
@@ -128,6 +146,13 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
|||||||
pos->castle = clr_oo(pos->castle, them);
|
pos->castle = clr_oo(pos->castle, them);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* update castle key */
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
|
||||||
|
pos->key = key;
|
||||||
|
|
||||||
|
bug_on(zobrist_verify(pos) == false);
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,9 +168,15 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
|
|||||||
piece_type_t ptype = PIECE(piece);
|
piece_type_t ptype = PIECE(piece);
|
||||||
piece_t new_piece = piece;
|
piece_t new_piece = piece;
|
||||||
int up = sq_up(us);
|
int up = sq_up(us);
|
||||||
|
key_t key = pos->key;
|
||||||
|
|
||||||
*state = pos->state; /* save irreversible changes */
|
*state = pos->state; /* save irreversible changes */
|
||||||
|
|
||||||
|
/* update key: switch turn, reset castling and ep */
|
||||||
|
key ^= zobrist_turn;
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
|
||||||
++pos->clock_50;
|
++pos->clock_50;
|
||||||
++pos->plycount;
|
++pos->plycount;
|
||||||
pos->en_passant = SQUARE_NONE;
|
pos->en_passant = SQUARE_NONE;
|
||||||
@@ -163,6 +194,7 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
|
|||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
//pos->captured = pos->board[to]; /* save capture info */
|
//pos->captured = pos->board[to]; /* save capture info */
|
||||||
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
||||||
|
key ^= zobrist_pieces[captured][to];
|
||||||
pos_clr_sq(pos, to); /* clear square */
|
pos_clr_sq(pos, to); /* clear square */
|
||||||
} else if (is_castle(move)) { /* handle rook move */
|
} else if (is_castle(move)) { /* handle rook move */
|
||||||
square_t rookfrom, rookto;
|
square_t rookfrom, rookto;
|
||||||
@@ -173,20 +205,27 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
|
|||||||
rookfrom = sq_rel(A1, us);
|
rookfrom = sq_rel(A1, us);
|
||||||
rookto = sq_rel(D1, us);
|
rookto = sq_rel(D1, us);
|
||||||
}
|
}
|
||||||
|
key ^= zobrist_pieces[pos->board[rookfrom]][rookto];
|
||||||
|
key ^= zobrist_pieces[pos->board[rookfrom]][rookfrom];
|
||||||
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
||||||
pos_clr_sq(pos, rookfrom);
|
pos_clr_sq(pos, rookfrom);
|
||||||
pos->castle = clr_castle(pos->castle, us);
|
pos->castle = clr_castle(pos->castle, us);
|
||||||
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
if (is_dpush(move)) /* if pawn double push, set e.p. */
|
if (is_dpush(move)) { /* if pawn double push, set e.p. */
|
||||||
pos->en_passant = from + up;
|
pos->en_passant = from + up;
|
||||||
else if (is_enpassant(move)) { /* clear grabbed pawn */
|
/* update key */
|
||||||
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
} 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];
|
||||||
pos_clr_sq(pos, grabbed);
|
pos_clr_sq(pos, grabbed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_clr_sq(pos, from); /* always clear "from" and set "to" */
|
key ^= zobrist_pieces[piece][from];
|
||||||
|
key ^= zobrist_pieces[new_piece][to];
|
||||||
|
pos_clr_sq(pos, from); /* clear "from" and set "to" */
|
||||||
pos_set_sq(pos, to, new_piece);
|
pos_set_sq(pos, to, new_piece);
|
||||||
|
|
||||||
if (ptype == KING)
|
if (ptype == KING)
|
||||||
@@ -208,7 +247,7 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
|
|||||||
else if (from == rel_h1)
|
else if (from == rel_h1)
|
||||||
pos->castle = clr_oo(pos->castle, us);
|
pos->castle = clr_oo(pos->castle, us);
|
||||||
}
|
}
|
||||||
if (can_castle(pos->castle, them)) { /* do we save time with this test ? */
|
if (can_castle(pos->castle, them)) {
|
||||||
square_t rel_a8 = sq_rel(A8, us);
|
square_t rel_a8 = sq_rel(A8, us);
|
||||||
square_t rel_h8 = sq_rel(H8, us);
|
square_t rel_h8 = sq_rel(H8, us);
|
||||||
if (to == rel_a8)
|
if (to == rel_a8)
|
||||||
@@ -217,6 +256,13 @@ pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
|
|||||||
pos->castle = clr_oo(pos->castle, them);
|
pos->castle = clr_oo(pos->castle, them);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* update castle key */
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
|
||||||
|
pos->key = key;
|
||||||
|
|
||||||
|
bug_on(zobrist_verify(pos) == false);
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,6 +62,21 @@ pos_t *pos_dup(const pos_t *pos)
|
|||||||
return newpos;
|
return newpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pos_copy() - copy a position into another one.
|
||||||
|
* @from: &position to duplicate.
|
||||||
|
* @to: &destination position.
|
||||||
|
*
|
||||||
|
* Return a copy of @from into @to.
|
||||||
|
*
|
||||||
|
* @Return: @to.
|
||||||
|
*/
|
||||||
|
pos_t *pos_copy(const pos_t *from, pos_t *to)
|
||||||
|
{
|
||||||
|
*to = *from;
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pos_del() - delete a position.
|
* pos_del() - delete a position.
|
||||||
* @pos: &position.
|
* @pos: &position.
|
||||||
@@ -87,6 +102,7 @@ pos_t *pos_clear(pos_t *pos)
|
|||||||
pos->turn = WHITE;
|
pos->turn = WHITE;
|
||||||
|
|
||||||
/* move_do/undo position state */
|
/* move_do/undo position state */
|
||||||
|
pos->key = 0;
|
||||||
pos->en_passant = SQUARE_NONE;
|
pos->en_passant = SQUARE_NONE;
|
||||||
pos->castle = 0;
|
pos->castle = 0;
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
@@ -341,6 +357,7 @@ bool pos_ok(const pos_t *pos, const bool strict)
|
|||||||
# define BUG_ON
|
# define BUG_ON
|
||||||
# undef WARN_ON
|
# undef WARN_ON
|
||||||
# define WARN_ON
|
# define WARN_ON
|
||||||
|
# include <bug.h>
|
||||||
|
|
||||||
/* pawns on 1st ot 8th rank */
|
/* pawns on 1st ot 8th rank */
|
||||||
error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &
|
error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &
|
||||||
|
@@ -16,11 +16,13 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "brlib.h"
|
#include <brlib.h>
|
||||||
#include "bitops.h"
|
#include <bitops.h>
|
||||||
#include "struct-group.h"
|
#include <struct-group.h>
|
||||||
|
#include <bug.h>
|
||||||
|
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
|
#include "hash.h"
|
||||||
#include "bitboard.h"
|
#include "bitboard.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
@@ -41,6 +43,7 @@ typedef struct __pos_s {
|
|||||||
* This allows a memcpy on this data (to save/restore position state).
|
* This allows a memcpy on this data (to save/restore position state).
|
||||||
*/
|
*/
|
||||||
struct_group_tagged(state_s, state,
|
struct_group_tagged(state_s, state,
|
||||||
|
key_t key;
|
||||||
square_t en_passant;
|
square_t en_passant;
|
||||||
castle_rights_t castle;
|
castle_rights_t castle;
|
||||||
int clock_50;
|
int clock_50;
|
||||||
@@ -72,11 +75,16 @@ static __always_inline void pos_set_sq(pos_t *pos, square_t square, piece_t piec
|
|||||||
{
|
{
|
||||||
color_t color = COLOR(piece);
|
color_t color = COLOR(piece);
|
||||||
piece_type_t type = PIECE(piece);
|
piece_type_t type = PIECE(piece);
|
||||||
|
|
||||||
|
bug_on(pos->board[square] != EMPTY);
|
||||||
|
|
||||||
pos->board[square] = piece;
|
pos->board[square] = piece;
|
||||||
pos->bb[color][type] |= BIT(square);
|
pos->bb[color][type] |= BIT(square);
|
||||||
pos->bb[color][ALL_PIECES] |= BIT(square);
|
pos->bb[color][ALL_PIECES] |= BIT(square);
|
||||||
if (type == KING)
|
//if (type == KING)
|
||||||
pos->king[color] = square;
|
// pos->king[color] = square;
|
||||||
|
|
||||||
|
//pos->key ^= zobrist_pieces[piece][square];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,11 +99,16 @@ static __always_inline void pos_clr_sq(pos_t *pos, square_t square)
|
|||||||
piece_t piece = pos->board[square];
|
piece_t piece = pos->board[square];
|
||||||
piece_type_t type = PIECE(piece);
|
piece_type_t type = PIECE(piece);
|
||||||
color_t color = COLOR(piece);
|
color_t color = COLOR(piece);
|
||||||
|
|
||||||
|
bug_on(pos->board[square] == EMPTY);
|
||||||
|
|
||||||
|
//pos->key ^= zobrist_pieces[piece][square];
|
||||||
|
|
||||||
pos->board[square] = EMPTY;
|
pos->board[square] = EMPTY;
|
||||||
pos->bb[color][type] &= ~BIT(square);
|
pos->bb[color][type] &= ~BIT(square);
|
||||||
pos->bb[color][ALL_PIECES] &= ~BIT(square);
|
pos->bb[color][ALL_PIECES] &= ~BIT(square);
|
||||||
if (type == KING)
|
//if (type == KING)
|
||||||
pos->king[color] = SQUARE_NONE;
|
// pos->king[color] = SQUARE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +169,7 @@ static __always_inline int pos_between_count(const pos_t *pos,
|
|||||||
|
|
||||||
pos_t *pos_new();
|
pos_t *pos_new();
|
||||||
pos_t *pos_dup(const pos_t *pos);
|
pos_t *pos_dup(const pos_t *pos);
|
||||||
|
pos_t *pos_copy(const pos_t *from, pos_t *to);
|
||||||
void pos_del(pos_t *pos);
|
void pos_del(pos_t *pos);
|
||||||
pos_t *pos_clear(pos_t *pos);
|
pos_t *pos_clear(pos_t *pos);
|
||||||
bool pos_cmp(const pos_t *pos1, const pos_t *pos2);
|
bool pos_cmp(const pos_t *pos1, const pos_t *pos2);
|
||||||
|
16
src/search.c
16
src/search.c
@@ -60,7 +60,13 @@ u64 perft(pos_t *pos, int depth, int ply, bool output)
|
|||||||
nodes++;
|
nodes++;
|
||||||
} else {
|
} else {
|
||||||
move_do(pos, *move);
|
move_do(pos, *move);
|
||||||
subnodes = perft(pos, depth - 1, ply + 1, output);
|
if (depth == 2) {
|
||||||
|
movelist_t movelist2;
|
||||||
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
|
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
|
||||||
|
} 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: %d\n", move_str(movestr, *move, 0), subnodes);
|
||||||
@@ -105,7 +111,13 @@ u64 perft_test(pos_t *pos, int depth, int ply, bool output)
|
|||||||
nodes++;
|
nodes++;
|
||||||
} else {
|
} else {
|
||||||
move_do2(pos, *move, &state);
|
move_do2(pos, *move, &state);
|
||||||
subnodes = perft(pos, depth - 1, ply + 1, output);
|
if (depth == 2) {
|
||||||
|
movelist_t movelist2;
|
||||||
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
|
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
|
||||||
|
} else {
|
||||||
|
subnodes = perft_test(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: %d\n", move_str(movestr, *move, 0), subnodes);
|
||||||
|
@@ -32,10 +32,7 @@ int main(int __unused ac, __unused char**av)
|
|||||||
movelist_t pseudo;
|
movelist_t pseudo;
|
||||||
move_t move;
|
move_t move;
|
||||||
|
|
||||||
setlinebuf(stdout); /* line-buffered stdout */
|
init_all();
|
||||||
|
|
||||||
bitboard_init();
|
|
||||||
hyperbola_init();
|
|
||||||
|
|
||||||
while ((fen = next_fen(MOVEDO))) {
|
while ((fen = next_fen(MOVEDO))) {
|
||||||
test_line = cur_line();
|
test_line = cur_line();
|
||||||
|
@@ -235,16 +235,16 @@ int main(int __unused ac, __unused char**av)
|
|||||||
int i = 0, test_line;
|
int i = 0, test_line;
|
||||||
u64 sf_count = 0, my_count;
|
u64 sf_count = 0, my_count;
|
||||||
char *fen;
|
char *fen;
|
||||||
pos_t *pos;
|
pos_t *pos = NULL, *fenpos;
|
||||||
pos_t *fishpos = pos_new();
|
pos_t *fishpos = pos_new();
|
||||||
movelist_t fishmoves;
|
movelist_t fishmoves;
|
||||||
//move_t move;
|
|
||||||
FILE *outfd = NULL;
|
FILE *outfd = NULL;
|
||||||
struct {
|
struct {
|
||||||
s64 count, ms;
|
s64 count, ms;
|
||||||
s64 minlps, maxlps;
|
s64 minlps, maxlps;
|
||||||
int skipped;
|
int skipped;
|
||||||
} res[2] = {
|
} res[3] = {
|
||||||
|
{ .minlps=LONG_MAX },
|
||||||
{ .minlps=LONG_MAX },
|
{ .minlps=LONG_MAX },
|
||||||
{ .minlps=LONG_MAX },
|
{ .minlps=LONG_MAX },
|
||||||
};
|
};
|
||||||
@@ -271,34 +271,47 @@ int main(int __unused ac, __unused char**av)
|
|||||||
return usage(*av);
|
return usage(*av);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if (ac > 1)
|
|
||||||
// depth = atoi(av[1]);
|
printf("perft: depth = %d run = %x stockfish = %s\n",
|
||||||
//if (ac > 2)
|
depth, run, sf_run? "true": "false");
|
||||||
// run = atoi(av[2]) & 3;
|
|
||||||
printf("depth = %d run = %x sf = %s\n", depth, run, sf_run? "true": "false");
|
init_all();
|
||||||
|
|
||||||
if (!run)
|
if (!run)
|
||||||
exit(0);
|
exit(0);
|
||||||
setlocale(LC_NUMERIC, "");
|
|
||||||
setlinebuf(stdout); /* line-buffered stdout */
|
|
||||||
|
|
||||||
if (sf_run)
|
if (sf_run)
|
||||||
outfd = open_stockfish();
|
outfd = open_stockfish();
|
||||||
|
|
||||||
bitboard_init();
|
CLOCK_DEFINE(clock, CLOCK_MONOTONIC);
|
||||||
hyperbola_init();
|
|
||||||
|
|
||||||
CLOCK_DEFINE(clock, CLOCK_PROCESS);
|
|
||||||
while ((fen = next_fen(PERFT | MOVEDO))) {
|
while ((fen = next_fen(PERFT | MOVEDO))) {
|
||||||
test_line = cur_line();
|
test_line = cur_line();
|
||||||
if (!(pos = fen2pos(NULL, fen))) {
|
if (!(fenpos = fen2pos(pos, fen))) {
|
||||||
printf("wrong fen %d: [%s]\n", i, fen);
|
printf("wrong fen %d: [%s]\n", i, fen);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (sf_run)
|
pos = fenpos;
|
||||||
|
if (sf_run) {
|
||||||
|
clock_start(&clock);
|
||||||
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
|
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
|
||||||
|
ms = clock_elapsed_ms(&clock);
|
||||||
// savepos = pos_dup(pos);
|
if (!ms) {
|
||||||
|
res[2].skipped++;
|
||||||
|
lps = 0;
|
||||||
|
} else {
|
||||||
|
lps = sf_count * 1000l / ms;
|
||||||
|
res[2].ms += ms;
|
||||||
|
res[2].count += sf_count;
|
||||||
|
if (lps > res[2].maxlps)
|
||||||
|
res[2].maxlps = lps;
|
||||||
|
if (lps < res[2].minlps)
|
||||||
|
res[2].minlps = lps;
|
||||||
|
}
|
||||||
|
printf("SF : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
|
||||||
|
test_line, sf_count, ms,
|
||||||
|
lps,
|
||||||
|
fen);
|
||||||
|
}
|
||||||
|
|
||||||
if (run & 1) {
|
if (run & 1) {
|
||||||
clock_start(&clock);
|
clock_start(&clock);
|
||||||
@@ -357,11 +370,20 @@ int main(int __unused ac, __unused char**av)
|
|||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
// pos_del(savepos);
|
// pos_del(savepos);
|
||||||
pos_del(pos);
|
|
||||||
i++;
|
i++;
|
||||||
/* to run first test only */
|
/* to run first test only */
|
||||||
// exit(0);
|
// exit(0);
|
||||||
}
|
}
|
||||||
|
pos_del(pos);
|
||||||
|
if (sf_run) {
|
||||||
|
if (!res[2].ms)
|
||||||
|
res[2].ms = 1;
|
||||||
|
printf("total SF %'lums %'lums lps=%'lu min=%'lu max=%'lu (skipped %d)\n",
|
||||||
|
res[2].count, res[2].ms,
|
||||||
|
res[2].count * 1000l / res[2].ms,
|
||||||
|
res[2].minlps, res[2].maxlps,
|
||||||
|
res[2].skipped);
|
||||||
|
}
|
||||||
if (run & 1) {
|
if (run & 1) {
|
||||||
if (!res[0].ms)
|
if (!res[0].ms)
|
||||||
res[0].ms = 1;
|
res[0].ms = 1;
|
||||||
|
Reference in New Issue
Block a user