16 Commits

Author SHA1 Message Date
32ade1777f ren macros mask->BIT/C64->U64, del pinners/checkers/blockers in state_s 2024-05-06 07:41:27 +02:00
c710da4bf9 move_do2: save/restore state inside func; perft: add silent option 2024-04-18 09:54:58 +02:00
36e1d987f3 rename second perft function, perft_test() 2024-04-17 18:43:09 +02:00
a13bdb04f1 sq_is_attacked: N before P 2024-04-17 12:10:45 +02:00
b884c1d65c Makefile: Use -Og instead of -O1 for dev build 2024-04-17 12:09:38 +02:00
2505217c70 rename pos_all_legal() to pos_legal_dup(), new pos_legal() 2024-04-17 09:13:21 +02:00
8b3202fac0 add CFLAGS -Wshadow and -funroll-loops, fix related common-test.h 2024-04-17 08:21:20 +02:00
473cc8683e perf-test: add command-line options, optional SF's perft compare 2024-04-16 12:33:11 +02:00
f0acdb6a66 pos_ok(): always set BUG_ON and WARN_ON 2024-04-16 12:32:37 +02:00
a49c712471 Makefile add support for multiple targets w/ first one not parallel 2024-04-14 09:35:53 +02:00
2b72fac45e comments, removal useless Makefile CFLAGS, etc... 2024-04-14 09:10:31 +02:00
0330696f87 pseudo_is_legal(): use sq_is_attacked() instead of sq_attackers() 2024-04-13 06:52:27 +02:00
a6eedebc19 perft: always use set_checkers_pinners_blockers() - To be cont'd 2024-04-11 10:04:13 +02:00
ab31274d17 movegen: add some generic fonctions 2024-04-11 10:03:35 +02:00
03da11cc9c cleanup when using bug_on()/warn_on() 2024-04-11 10:02:49 +02:00
bfed0f417d merge movegen-review. Performance issue was in perft, not movegen ! 2024-04-10 17:49:08 +02:00
22 changed files with 601 additions and 299 deletions

View File

@@ -1,3 +1,3 @@
((nil . ((compile-command . (concat "make -C " ((nil . ((compile-command . (concat "make -C "
(vc-root-dir) (vc-root-dir)
" -k -j2 testing"))))) " -k -j4 testing")))))

View File

@@ -70,15 +70,14 @@ CPPFLAGS += -DWARN_ON # brlib bug.h
#CPPFLAGS += -DDEBUG_FEN # FEN decoding #CPPFLAGS += -DDEBUG_FEN # FEN decoding
# attack.c # attack.c
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS1 # sq_attackers details #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
#CPPFLAGS += -DDEBUG_EVAL # eval functions #CPPFLAGS += -DDEBUG_EVAL # eval functions
#CPPFLAGS += -DDEBUG_PIECE # piece list management #CPPFLAGS += -DDEBUG_PIECE # piece list management
#CPPFLAGS += -DDEBUG_SEARCH # move search #CPPFLAGS += -DDEBUG_SEARCH # move search
CPPFLAGS += -DDIAGRAM_SYM # diagram with symbols CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams
# remove extraneous spaces (due to spaces before comments) # remove extraneous spaces (due to spaces before comments)
CPPFLAGS := $(strip $(CPPFLAGS)) CPPFLAGS := $(strip $(CPPFLAGS))
@@ -89,27 +88,29 @@ CFLAGS := -std=gnu11
### dev OR release ### dev OR release
# dev # dev
# CFLAGS += -O1
CFLAGS += -g # symbols (gdb, perf, etc.) CFLAGS += -g # symbols (gdb, perf, etc.)
CFLAGS += -ginline-points # inlined funcs debug info CFLAGS += -ginline-points # inlined funcs debug info
#CFLAGS += -Og
# for gprof # for gprof
#CFLAGS += -pg #CFLAGS += -pg
# Next one may be useful for valgrind (when invalid instructions) # Next one may be useful for valgrind (when invalid instructions)
#CFLAGS += -mno-tbm #CFLAGS += -mno-tbm
# release # release
CFLAGS += -Ofast CFLAGS += -O3
CFLAGS += -march=native CFLAGS += -march=native
CFLAGS += -flto CFLAGS += -flto
CFLAGS += -funroll-loops
CFLAGS += -Wall CFLAGS += -Wall
CFLAGS += -Wextra CFLAGS += -Wextra
CFLAGS += -Wshadow
CFLAGS += -Wmissing-declarations CFLAGS += -Wmissing-declarations
CFLAGS := $(strip $(CFLAGS)) CFLAGS := $(strip $(CFLAGS))
# development CFLAGS - unused - TODO # development CFLAGS - unused - TODO
#DEV_CFLAGS := -O1 #DEV_CFLAGS := -Og
#DEV_CFLAGS += -g #DEV_CFLAGS += -g
# release CFLAGS - unused - TODO # release CFLAGS - unused - TODO
@@ -130,6 +131,38 @@ DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$*.d
ALL_CFLAGS = $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) ALL_CFLAGS = $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS) $(LIBS) ALL_LDFLAGS = $(LDFLAGS) $(LIBS)
##################################### Multi-targets
# We can have an issue with Make's "-j" option, in some situations,
# for example "make -j2 clean testing".
# See https://stackoverflow.com/a/8496333/3079831
# Check if job server supported:
ifeq ($(filter jobserver, $(.FEATURES)),)
# Job server not supported: sub-makes will only start one job unless
# you specify a higher number here. Here we use a MS Windows environment
# variable specifying number of processors.
JOBSARG := -j $(NUMBER_OF_PROCESSORS)
else
# Job server is supported; let GNU Make work as normal.
JOBSARG :=
endif
# .FEATURES only works in GNU Make 3.81+.
# If GNU make is older, assume job server support.
ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))),3.81)
# If you are using GNU Make < 3.81 that does not support job servers, you
# might want to specify -jN parameter here instead.
JOBSARG :=
endif
ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
# The "all" target is required in the list,
# in case user invokes make with no targets.
$(sort all $(MAKECMDGOALS)):
@$(MAKE) $(JOBSARG) -f $(firstword $(MAKEFILE_LIST)) $@
else
##################################### General targets ##################################### General targets
.PHONY: all compile clean cleanall .PHONY: all compile clean cleanall
@@ -380,3 +413,6 @@ wtf:
zob: zob:
$(CC) $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $< $(LIBS) src/util.c -o util $(CC) $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $< $(LIBS) src/util.c -o util
##################################### End of multi-targets
endif

View File

@@ -42,6 +42,15 @@ bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, c
{ {
color_t opp = OPPONENT(c); color_t opp = OPPONENT(c);
/*
* return (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN])
* || hyperbola_rook_moves(occ, sq) & (pos->bb[c][ROOK] | pos->bb[c][QUEEN])
* || bb_pawn_attacks[opp][sq] & pos->bb[c][PAWN]
* || bb_knight_moves(pos->bb[c][KNIGHT], sq)
* || bb_king_moves(pos->bb[c][KING], sq)
* )
*/
/* bishop / queen */ /* bishop / queen */
if (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN])) if (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN]))
return true; return true;
@@ -50,14 +59,14 @@ bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, c
if (hyperbola_rook_moves(occ, sq) & (pos->bb[c][ROOK] | pos->bb[c][QUEEN])) if (hyperbola_rook_moves(occ, sq) & (pos->bb[c][ROOK] | pos->bb[c][QUEEN]))
return true; return true;
/* pawn */
if (bb_pawn_attacks[opp][sq] & pos->bb[c][PAWN])
return true;
/* knight */ /* knight */
if (bb_knight_moves(pos->bb[c][KNIGHT], sq)) if (bb_knight_moves(pos->bb[c][KNIGHT], sq))
return true; return true;
/* pawn */
if (bb_pawn_attacks[opp][sq] & pos->bb[c][PAWN])
return true;
/* king */ /* king */
if (bb_king_moves(pos->bb[c][KING], sq)) if (bb_king_moves(pos->bb[c][KING], sq))
return true; return true;
@@ -100,8 +109,7 @@ bool is_in_check(const pos_t *pos, const color_t color)
bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t sq, const color_t c) bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t sq, const color_t c)
{ {
bitboard_t attackers = 0, tmp; bitboard_t attackers = 0, tmp;
bitboard_t sqbb = mask(sq); bitboard_t sqbb = BIT(sq);
//bitboard_t occ = pos_occ(pos);
bitboard_t to; bitboard_t to;
color_t opp = OPPONENT(c); color_t opp = OPPONENT(c);
@@ -109,12 +117,12 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
to = pos->bb[c][PAWN]; to = pos->bb[c][PAWN];
tmp = pawn_shift_upleft(sqbb, opp) & to; tmp = pawn_shift_upleft(sqbb, opp) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att pawn upleft", tmp); bb_print("att pawn upleft", tmp);
# endif # endif
tmp = pawn_shift_upright(sqbb, opp) & to; tmp = pawn_shift_upright(sqbb, opp) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att pawn upright", tmp); bb_print("att pawn upright", tmp);
# endif # endif
@@ -122,13 +130,13 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
to = pos->bb[c][KNIGHT]; to = pos->bb[c][KNIGHT];
tmp = bb_knight_moves(to, sq); tmp = bb_knight_moves(to, sq);
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att knight", tmp); bb_print("att knight", tmp);
# endif # endif
to = pos->bb[c][KING]; to = pos->bb[c][KING];
tmp = bb_king_moves(to, sq); tmp = bb_king_moves(to, sq);
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att king", tmp); bb_print("att king", tmp);
# endif # endif
@@ -136,7 +144,7 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
to = pos->bb[c][BISHOP] | pos->bb[c][QUEEN]; to = pos->bb[c][BISHOP] | pos->bb[c][QUEEN];
tmp = hyperbola_bishop_moves(occ, sq) & to; tmp = hyperbola_bishop_moves(occ, sq) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att bishop/queen", tmp); bb_print("att bishop/queen", tmp);
# endif # endif
@@ -144,7 +152,7 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
to = pos->bb[c][ROOK] | pos->bb[c][QUEEN]; to = pos->bb[c][ROOK] | pos->bb[c][QUEEN];
tmp = hyperbola_rook_moves(occ, sq) & to; tmp = hyperbola_rook_moves(occ, sq) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att rook/queen", tmp); bb_print("att rook/queen", tmp);
bb_print("ATTACKERS", attackers); bb_print("ATTACKERS", attackers);
printf("attackers=%lx\n", attackers); printf("attackers=%lx\n", attackers);
@@ -178,7 +186,7 @@ bitboard_t sq_pinners(const pos_t *pos, const square_t sq, const color_t color)
bitboard_t between = bb_between_excl[maybe_pinner][sq]; bitboard_t between = bb_between_excl[maybe_pinner][sq];
/* keep only squares between AND on sq diag/anti */ /* keep only squares between AND on sq diag/anti */
if (popcount64(between & lines) == 1) if (popcount64(between & lines) == 1)
pinners |= mask(maybe_pinner); pinners |= BIT(maybe_pinner);
} }
/* same for rook type */ /* same for rook type */
@@ -187,7 +195,7 @@ bitboard_t sq_pinners(const pos_t *pos, const square_t sq, const color_t color)
bit_for_each64(maybe_pinner, tmp, attackers) { bit_for_each64(maybe_pinner, tmp, attackers) {
bitboard_t between = bb_between_excl[maybe_pinner][sq]; bitboard_t between = bb_between_excl[maybe_pinner][sq];
if (popcount64(between & lines) == 1) if (popcount64(between & lines) == 1)
pinners |= mask(maybe_pinner); pinners |= BIT(maybe_pinner);
} }
# ifdef DEBUG_ATTACK_ATTACKERS1 # ifdef DEBUG_ATTACK_ATTACKERS1
char str[32]; char str[32];

View File

@@ -53,8 +53,8 @@ static int king_vector[8] = {
bitboard_t bitboard_between_excl(square_t sq1, square_t sq2) bitboard_t bitboard_between_excl(square_t sq1, square_t sq2)
{ {
const bitboard_t m1 = -1; const bitboard_t m1 = -1;
const bitboard_t a2a7 = C64(0x0001010101010100); const bitboard_t a2a7 = U64(0x0001010101010100);
const bitboard_t b7h1 = C64(0x0002040810204080); const bitboard_t b7h1 = U64(0x0002040810204080);
bitboard_t btwn_bits, ray_bits; bitboard_t btwn_bits, ray_bits;
u32 rank_diff, file_diff, anti_diff, diag_diff; u32 rank_diff, file_diff, anti_diff, diag_diff;
@@ -109,7 +109,7 @@ void bitboard_init(void)
* in-between, sq2 excluded * in-between, sq2 excluded
*/ */
for (square_t sq1 = A1; sq1 <= H8; ++sq1) { for (square_t sq1 = A1; sq1 <= H8; ++sq1) {
bb_sq[sq1] = mask(sq1); bb_sq[sq1] = BIT(sq1);
for (square_t sq2 = A1; sq2 <= H8; ++sq2) for (square_t sq2 = A1; sq2 <= H8; ++sq2)
bb_between_excl[sq1][sq2] = bitboard_between_excl(sq1, sq2); bb_between_excl[sq1][sq2] = bitboard_between_excl(sq1, sq2);
} }
@@ -121,15 +121,15 @@ void bitboard_init(void)
file_t f = sq_file(sq); file_t f = sq_file(sq);
rank_t r = sq_rank(sq); rank_t r = sq_rank(sq);
for (int vec = 0; vec < 4; ++vec) { for (int vec = 0; vec < 4; ++vec) {
tmpbb[sq][vec] |= mask(sq_make(f, r)); tmpbb[sq][vec] |= BIT(sq_make(f, r));
for (int dir = -1; dir <= 1; dir += 2) { for (int dir = -1; dir <= 1; dir += 2) {
file_t df = dir * vecs[vec].df, f2 = f + df; file_t df = dir * vecs[vec].df, f2 = f + df;
rank_t dr = dir * vecs[vec].dr, r2 = r + dr; rank_t dr = dir * vecs[vec].dr, r2 = r + dr;
bitboard_t mask_between = 0; bitboard_t mask_between = 0;
while (sq_coord_ok(f2) && sq_coord_ok(r2)) { while (sq_coord_ok(f2) && sq_coord_ok(r2)) {
square_t dest = sq_make(f2, r2); square_t dest = sq_make(f2, r2);
tmpbb[sq][vec] |= mask(dest); tmpbb[sq][vec] |= BIT(dest);
mask_between |= mask(dest); mask_between |= BIT(dest);
bb_between[sq][dest] = mask_between; bb_between[sq][dest] = mask_between;
f2 += df, r2 += dr; f2 += df, r2 += dr;
} }
@@ -161,9 +161,9 @@ void bitboard_init(void)
*/ */
for (square_t sq = A1; sq <= H8; ++sq) { for (square_t sq = A1; sq <= H8; ++sq) {
if (sq >= A2) if (sq >= A2)
bb_pawn_attacks[BLACK][sq] = pawn_attacks_bb(mask(sq), BLACK); bb_pawn_attacks[BLACK][sq] = pawn_attacks_bb(BIT(sq), BLACK);
if (sq <= H7) if (sq <= H7)
bb_pawn_attacks[WHITE][sq] = pawn_attacks_bb(mask(sq), WHITE); bb_pawn_attacks[WHITE][sq] = pawn_attacks_bb(BIT(sq), WHITE);
for (int vec = 0; vec < 8; ++vec) { for (int vec = 0; vec < 8; ++vec) {
int dst = sq + knight_vector[vec]; int dst = sq + knight_vector[vec];
@@ -281,7 +281,7 @@ char *bb_rank_sprint(char *str, const uchar bb8)
{ {
file_t f; file_t f;
for (f = FILE_A; f <= FILE_H; ++f) { for (f = FILE_A; f <= FILE_H; ++f) {
*(str + f) = bb8 & mask(f) ? '1': '.'; *(str + f) = bb8 & BIT(f) ? '1': '.';
} }
*(str + f) = 0; *(str + f) = 0;
//printf(" 0 1 2 3 4 5 6 7\n"); //printf(" 0 1 2 3 4 5 6 7\n");

View File

@@ -260,7 +260,7 @@ static __always_inline bool bb_sq_aligned(square_t sq1, square_t sq2)
*/ */
static __always_inline bool bb_sq_aligned3(square_t sq1, square_t sq2, square_t sq3) static __always_inline bool bb_sq_aligned3(square_t sq1, square_t sq2, square_t sq3)
{ {
return bb_line[sq1][sq2] & mask(sq3); return bb_line[sq1][sq2] & BIT(sq3);
} }
/** /**
@@ -273,7 +273,7 @@ static __always_inline bool bb_sq_aligned3(square_t sq1, square_t sq2, square_t
*/ */
static __always_inline bitboard_t bb_sq_between(square_t sq, square_t sq1, square_t sq2) static __always_inline bitboard_t bb_sq_between(square_t sq, square_t sq1, square_t sq2)
{ {
return bb_between_excl[sq1][sq2] & mask(sq); return bb_between_excl[sq1][sq2] & BIT(sq);
} }
/* TODO: when OK, replace with macros */ /* TODO: when OK, replace with macros */

View File

@@ -93,7 +93,7 @@ void board_print_mask(const piece_t *board, const bitboard_t mask)
for (int file = 0; file < 8; ++file) { for (int file = 0; file < 8; ++file) {
square_t sq = sq_make(file, rank); square_t sq = sq_make(file, rank);
piece_t pc = board[sq]; piece_t pc = board[sq];
bitboard_t set = mask(sq) & mask; bitboard_t set = BIT(sq) & mask;
printf("%s", set? REVERSE : " "); printf("%s", set? REVERSE : " ");
# ifdef DIAGRAM_SYM # ifdef DIAGRAM_SYM
printf("%s", pc? piece_to_sym(pc): " "); printf("%s", pc? piece_to_sym(pc): " ");

View File

@@ -17,8 +17,8 @@
#include "brlib.h" /* brlib types */ #include "brlib.h" /* brlib types */
#define ONE 1ull #define ONE 1ull
#define C64(const_u64) const_u64##ULL #define U64(const_u64) const_u64##ULL
#define mask(i) ( (u64) (ONE << (i)) ) #define BIT(i) ( (u64) (ONE << (i)) )
#define BOARDSIZE (8*8) #define BOARDSIZE (8*8)
@@ -50,17 +50,19 @@
/* castle_t bits structure /* castle_t bits structure
*/ */
typedef enum { typedef enum {
CASTLE_WK = (1 << 0), /* 0x01 00000001 */ CASTLE_NONE = 0,
CASTLE_WQ = (1 << 1), /* 0x02 00000010 */ CASTLE_WK = (1 << 0), /* 0001 */
CASTLE_BK = (1 << 2), /* 0x04 00000100 */ CASTLE_WQ = (1 << 1), /* 0010 */
CASTLE_BQ = (1 << 3), /* 0x08 00001000 */ CASTLE_BK = (1 << 2), /* 0100 */
CASTLE_BQ = (1 << 3), /* 1000 */
CASTLE_W = (CASTLE_WK | CASTLE_WQ), /* 00000011 W castle mask */ CASTLE_W = (CASTLE_WK | CASTLE_WQ), /* 0011 = 3 = W castle mask */
CASTLE_B = (CASTLE_BK | CASTLE_BQ), /* 00001100 B castle mask */ CASTLE_B = (CASTLE_BK | CASTLE_BQ), /* 1100 = 12 = B castle mask */
CASTLE_ALL = (CASTLE_W | CASTLE_B), /* 1111 = 15 */
CASTLE_K = (1 << 0), /* generic K/Q, bits 0 and 1 */ CASTLE_K = (1 << 0), /* generic K/Q, bits 0 and 1 */
CASTLE_Q = (1 << 1), CASTLE_Q = (1 << 1),
CASTLE_KQ = (CASTLE_K |CASTLE_Q) CASTLE_KQ = (CASTLE_K |CASTLE_Q),
} castle_rights_t; } castle_rights_t;
/* determine is oo or ooo is possible with castle flags f and color c /* determine is oo or ooo is possible with castle flags f and color c
@@ -171,4 +173,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);
void rand_init(u64 seed);
u64 rand64(void);
#endif /* _CHESSDEFS_H */ #endif /* _CHESSDEFS_H */

View File

@@ -162,7 +162,7 @@ pos_t *fen2pos(pos_t *pos, const char *fen)
char *p; char *p;
short rank, file, tmp; short rank, file, tmp;
piece_t piece; piece_t piece;
int consumed, err_line = 0, err_pos, err_char; int consumed, err_line = 0, err_pos = 0, err_char = 0;
pos_t tmppos; pos_t tmppos;
pos_clear(&tmppos); pos_clear(&tmppos);
@@ -324,7 +324,7 @@ char *pos2fen(const pos_t *pos, char *fen)
fen[cur++] = '-'; fen[cur++] = '-';
} else { } else {
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
if (pos->castle & mask(i)) if (pos->castle & BIT(i))
fen[cur++] = castle_str[i]; fen[cur++] = castle_str[i];
} }
fen[cur++] = ' '; fen[cur++] = ' ';

View File

@@ -129,8 +129,8 @@ bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
bitboard_t r = bswap64(o); bitboard_t r = bswap64(o);
square_t r_sq = FLIP_V(sq); square_t r_sq = FLIP_V(sq);
return ( (o - 2 * mask(sq) ) return ( (o - 2 * BIT(sq) )
^ bswap64(r - 2 * mask(r_sq))) ^ bswap64(r - 2 * BIT(r_sq)))
& mask; & mask;
} }

View File

@@ -54,7 +54,6 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
piece_t piece = pos->board[from]; piece_t piece = pos->board[from];
piece_t captured = pos->board[to]; piece_t captured = pos->board[to];
piece_type_t ptype = PIECE(piece); piece_type_t ptype = PIECE(piece);
color_t pcolor = COLOR(piece);
piece_t new_piece = piece; piece_t new_piece = piece;
int up = sq_up(us); int up = sq_up(us);
@@ -64,7 +63,96 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
pos->turn = them; pos->turn = them;
pos->captured = captured; pos->captured = captured;
bug_on(pcolor != us); bug_on(COLOR(piece) != us);
if (is_promotion(move)) {
bug_on(sq_rank(to) != sq_rel_rank(RANK_8, us));
new_piece = MAKE_PIECE(move_promoted(move), us);
}
if (captured != EMPTY) {
pos->clock_50 = 0;
//pos->captured = pos->board[to]; /* save capture info */
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
pos_clr_sq(pos, to); /* clear square */
} else if (is_castle(move)) { /* handle rook move */
square_t rookfrom, rookto;
if (is_castle_K(move)) {
rookfrom = sq_rel(H1, us);
rookto = sq_rel(F1, us);
} else {
rookfrom = sq_rel(A1, us);
rookto = sq_rel(D1, us);
}
pos_set_sq(pos, rookto, pos->board[rookfrom]);
pos_clr_sq(pos, rookfrom);
pos->castle = clr_castle(pos->castle, us);
} else if (ptype == PAWN) { /* pawn non capture or e.p. */
pos->clock_50 = 0;
if (is_dpush(move)) /* if pawn double push, set e.p. */
pos->en_passant = from + up;
else if (is_enpassant(move)) { /* clear grabbed pawn */
square_t grabbed = to - up;
pos_clr_sq(pos, grabbed);
}
}
pos_clr_sq(pos, from); /* always clear "from" and set "to" */
pos_set_sq(pos, to, new_piece);
if (ptype == KING)
pos->king[us] = to;
/* update castling flags
* As we always consider flags are valid, we :
* - adjust our flags if relative from is "E1", "A1", H1"
* - adjust opp flags if relative to if "A8", H8"
*/
if (can_castle(pos->castle, us)) { /* do we save time with this test ? */
square_t rel_e1 = sq_rel(E1, us);
square_t rel_a1 = sq_rel(A1, us);
square_t rel_h1 = sq_rel(H1, us);
if (from == rel_e1)
pos->castle = clr_castle(pos->castle, us);
else if (from == rel_a1)
pos->castle = clr_ooo(pos->castle, us);
else if (from == rel_h1)
pos->castle = clr_oo(pos->castle, us);
}
if (can_castle(pos->castle, them)) { /* do we save time with this test ? */
square_t rel_a8 = sq_rel(A8, us);
square_t rel_h8 = sq_rel(H8, us);
if (to == rel_a8)
pos->castle = clr_ooo(pos->castle, them);
else if (to == rel_h8)
pos->castle = clr_oo(pos->castle, them);
}
return pos;
}
pos_t *move_do2(pos_t *pos, const move_t move, state_t *state)
{
//# ifdef DEBUG_MOVE_DO
// move_print(move, M_PR_NL | M_PR_LONG);
//# endif
color_t us = pos->turn, them = OPPONENT(us);
square_t from = move_from(move), to = move_to(move);
piece_t piece = pos->board[from];
piece_t captured = pos->board[to];
piece_type_t ptype = PIECE(piece);
piece_t new_piece = piece;
int up = sq_up(us);
*state = pos->state; /* save irreversible changes */
++pos->clock_50;
++pos->plycount;
pos->en_passant = SQUARE_NONE;
pos->turn = them;
pos->captured = captured;
bug_on(COLOR(piece) != us);
if (is_promotion(move)) { if (is_promotion(move)) {
bug_on(sq_rank(to) != sq_rel_rank(RANK_8, us)); bug_on(sq_rank(to) != sq_rel_rank(RANK_8, us));
@@ -149,12 +237,8 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
* *
* @return: pos. * @return: pos.
*/ */
pos_t *move_undo(pos_t *pos, const move_t move)//, const state_t *state) pos_t *move_undo(pos_t *pos, const move_t move)
{ {
//# ifdef DEBUG_MOVE
//log(1, "new move: ");
//move_print(0, move, M_PR_NL | M_PR_LONG);
//# endif
color_t them = pos->turn, us = OPPONENT(them); color_t them = pos->turn, us = OPPONENT(them);
square_t from = move_from(move), to = move_to(move); square_t from = move_from(move), to = move_to(move);
piece_t piece = pos->board[to]; piece_t piece = pos->board[to];
@@ -191,3 +275,42 @@ pos_t *move_undo(pos_t *pos, const move_t move)//, const state_t *state)
pos->turn = us; pos->turn = us;
return pos; return pos;
} }
pos_t *move_undo2(pos_t *pos, const move_t move, const state_t *state)
{
color_t them = pos->turn, us = OPPONENT(them);
square_t from = move_from(move), to = move_to(move);
piece_t piece = pos->board[to];
int up = sq_up(them);
if (is_promotion(move))
piece = MAKE_PIECE(PAWN, us);
pos_clr_sq(pos, to); /* always clear "to" ... */
pos_set_sq(pos, from, piece); /* ... and set "from" */
if (PIECE(piece) == KING)
pos->king[us] = from;
if (pos->captured != EMPTY) {
pos_set_sq(pos, to, pos->captured); /* restore captured piece */
} else if (is_castle(move)) { /* make reverse rook move */
square_t rookfrom, rookto;
if (is_castle_K(move)) {
rookfrom = sq_rel(F1, us);
rookto = sq_rel(H1, us);
} else {
rookfrom = sq_rel(D1, us);
rookto = sq_rel(A1, us);
}
pos_set_sq(pos, rookto, pos->board[rookfrom]);
pos_clr_sq(pos, rookfrom);
} else if (is_enpassant(move)) { /* restore grabbed pawn */
square_t grabbed = to + up;
pos_set_sq(pos, grabbed, MAKE_PIECE(PAWN, them));
}
pos->state = *state; /* restore irreversible changes */
pos->turn = us;
return pos;
}

View File

@@ -19,4 +19,7 @@
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);
pos_t *move_undo(pos_t *pos, const move_t move);//, const state_t *state); pos_t *move_undo(pos_t *pos, const move_t move);//, const state_t *state);
pos_t *move_do2(pos_t *pos, const move_t move, state_t *state);
pos_t *move_undo2(pos_t *pos, const move_t move, const state_t *state);
#endif /* MOVE_DO_H */ #endif /* MOVE_DO_H */

View File

@@ -41,7 +41,7 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
square_t king = pos->king[us]; square_t king = pos->king[us];
bitboard_t kingbb = pos->bb[us][KING]; bitboard_t kingbb = pos->bb[us][KING];
bitboard_t occ = pos_occ(pos); bitboard_t occ = pos_occ(pos);
u64 pinned = mask(from) & pos->blockers; u64 pinned = BIT(from) & pos->blockers;
u64 checkers = pos->checkers; u64 checkers = pos->checkers;
/* (1) - Castling & King /* (1) - Castling & King
@@ -53,10 +53,10 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
if (unlikely(from == king)) { if (unlikely(from == king)) {
if (unlikely(is_castle(move))) { if (unlikely(is_castle(move))) {
square_t dir = to > from? 1: -1; square_t dir = to > from? 1: -1;
if (sq_attackers(pos, occ, from + dir, them)) if (sq_is_attacked(pos, occ, from + dir, them))
return false; return false;
} }
return !sq_attackers(pos, occ ^ kingbb, to, them); return !sq_is_attacked(pos, occ ^ kingbb, to, them);
} }
/* (2) - King is in check /* (2) - King is in check
@@ -86,8 +86,8 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
/* (3) - pinned pieces /* (3) - pinned pieces
* We verify here that pinned piece P stays on line King-P. * We verify here that pinned piece P stays on line King-P.
*/ */
if (mask(from) & pos->blockers) { if (BIT(from) & pos->blockers) {
return bb_line[from][king] & mask(to); /* is to on pinner line ? */ return bb_line[from][king] & BIT(to); /* is to on pinner line ? */
} }
/* (4) - En-passant /* (4) - En-passant
@@ -99,7 +99,7 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
bitboard_t rank5 = us == WHITE? RANK_5bb: RANK_4bb; bitboard_t rank5 = us == WHITE? RANK_5bb: RANK_4bb;
if ((pos->bb[us][KING] & rank5)) { if ((pos->bb[us][KING] & rank5)) {
bitboard_t exclude = mask(pos->en_passant - sq_up(us)) | mask(from); bitboard_t exclude = BIT(pos->en_passant - sq_up(us)) | BIT(from);
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5; bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
while (rooks) { while (rooks) {
@@ -138,24 +138,52 @@ move_t pos_next_legal(const pos_t *pos, movelist_t *movelist, int *start)
} }
/** /**
* pos_all_legal() - get the list of legal moves from pseudo-legal. * pos_legal_dup() - get legal moves from pseudo-legal ones in new list.
* @pos: position * @pos: position
* @movelist: &pseudo-legal movelist_t * @pseudo: &movelist_t pseudo-legal moves list
* @dest: &destination movelist_t * @legal: &movelist_t legal moves
* *
* The pseudo-legal moves must be already calculated before calling this function. * The pseudo-legal moves must be already calculated before calling this function.
* No check is done on @dest limits. * No check is done on @legal limits.
* This function is similar to pos_legal(), but creates a new list for legal moves.
* It should only be used for debug purpose, when we want to keep a copy of
* pseudo-legal moves.
* *
* @Return: @dest * @return: @legal
*/ */
movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *dest) movelist_t *pos_legal_dup(const pos_t *pos, movelist_t *pseudo, movelist_t *legal)
{ {
int tmp = dest->nmoves = 0; int tmp = legal->nmoves = 0;
move_t move; move_t move;
while ((move = pos_next_legal(pos, movelist, &tmp)) != MOVE_NONE) while ((move = pos_next_legal(pos, pseudo, &tmp)) != MOVE_NONE)
dest->move[dest->nmoves++] = move; legal->move[legal->nmoves++] = move;
return dest; return legal;
}
/**
* pos_legal() - get legal moves from pseudo-legal ones in new list.
* @pos: position
* @list: &movelist_t pseudo-legal moves list
*
* The pseudo-legal moves must be already calculated before calling this function.
* @list is replaced by legal moves.
*
* @return: @list
*/
movelist_t *pos_legal(const pos_t *pos, movelist_t *list)
{
move_t *cur = list->move, *last = list->move + list->nmoves;
while (cur < last) {
if (pseudo_is_legal(pos, *cur))
cur++;
else {
*cur = *--last;
}
}
list->nmoves = last - list->move;
return list;
} }
/** /**
@@ -230,16 +258,40 @@ static inline __unused move_t *gen_pseudo_king(move_t *moves, square_t from,
*/ */
/** /**
* move_make_promotions() - generate all promotions for given pawn and dest. * moves_gen_flags() - generate all moves from square to bitboard (with flags).
* @moves: &move_t array where to store moves
* @from: square_t piece position
* @to_bb: destination bitboard
* @flags: flags to apply
*
* Generate (at address @moves) moves from square @from to each square in @to_bb,
* with flags @flags.
*
* @Return: New @moves.
*/
static inline __unused move_t *moves_gen_flags(move_t *moves, square_t from, bitboard_t to_bb,
__unused move_flags_t flags)
{
square_t to;
while(to_bb) {
to = bb_next(&to_bb);
*moves++ = move_make_flags(from, to, flags);
}
return moves;
}
/**
* move_gen_promotions() - generate all promotions for given pawn and dest.
* @moves: &move_t array where to store moves * @moves: &move_t array where to store moves
* @from: pawn position * @from: pawn position
* @to: promotion square * @to: promotion square
* *
* Generate all (Q/R/B/N) promotion moves on @to for pawn @from. * Generate (at address @moves) all promotion (Q/R/B/N) moves on @to for
* pawn @from.
* *
* @Return: New @moves (incremented by 4). * @Return: New @moves.
*/ */
static inline move_t *move_make_promotions(move_t *moves, square_t from, square_t to) static inline move_t *move_gen_promotions(move_t *moves, square_t from, square_t to)
{ {
for (piece_type_t pt = QUEEN; pt >= KNIGHT; --pt) for (piece_type_t pt = QUEEN; pt >= KNIGHT; --pt)
*moves++ = move_make_promote(from, to, pt); *moves++ = move_make_promote(from, to, pt);
@@ -247,7 +299,28 @@ static inline move_t *move_make_promotions(move_t *moves, square_t from, square_
} }
/** /**
* pos_gen_pseudomoves() - generate position pseudo-legal moves * moves_gen() - generate all moves from square to bitboard.
* @moves: &move_t array where to store moves
* @from: square_t piece position
* @to_bb: destination bitboard
*
* Generate (at address @moves) moves from square @from to each square in @to_bb.
*
* @Return: New @moves.
*/
static inline move_t *moves_gen(move_t *moves, square_t from, bitboard_t to_bb)
{
square_t to;
// bb_print(sq_to_string(from), to_bb);
while(to_bb) {
to = bb_next(&to_bb);
*moves++ = move_make(from, to);
}
return moves;
}
/**
* pos_gen_pseudo() - generate position pseudo-legal moves
* @pos: position * @pos: position
* @movelist: &movelist_t array to store pseudo-moves * @movelist: &movelist_t array to store pseudo-moves
* *
@@ -267,9 +340,9 @@ static inline move_t *move_make_promotions(move_t *moves, square_t from, square_
* *
* TODO: move code to specific functions (especially castling, pawn push/capture) * TODO: move code to specific functions (especially castling, pawn push/capture)
* *
* @Return: The total number of moves. * @Return: movelist
*/ */
int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist) movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
{ {
color_t us = pos->turn; color_t us = pos->turn;
color_t them = OPPONENT(us); color_t them = OPPONENT(us);
@@ -289,12 +362,13 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
//*nmoves = 0; //*nmoves = 0;
/* king - MUST BE FIRST (we stop if doubler check) */ /* king - MUST BE FIRST */
to_bb = bb_king_moves(dest_squares, king); to_bb = bb_king_moves(dest_squares, king);
while(to_bb) { moves = moves_gen(moves, king, to_bb);
to = bb_next(&to_bb); //while(to_bb) {
*moves++ = move_make(king, to); // to = bb_next(&to_bb);
} // *moves++ = move_make(king, to);
//}
if (bb_multiple(pos->checkers)) /* double check, we stop here */ if (bb_multiple(pos->checkers)) /* double check, we stop here */
goto finish; goto finish;
@@ -334,19 +408,21 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
while (from_bb) { while (from_bb) {
from = bb_next(&from_bb); from = bb_next(&from_bb);
to_bb = hyperbola_bishop_moves(occ, from) & dest_squares; to_bb = hyperbola_bishop_moves(occ, from) & dest_squares;
while(to_bb) { moves = moves_gen(moves, from, to_bb);
to = bb_next(&to_bb); //while(to_bb) {
*moves++ = move_make(from, to); // to = bb_next(&to_bb);
} // *moves++ = move_make(from, to);
//}
} }
from_bb = pos->bb[us][ROOK] | pos->bb[us][QUEEN]; from_bb = pos->bb[us][ROOK] | pos->bb[us][QUEEN];
while (from_bb) { while (from_bb) {
from = bb_next(&from_bb); from = bb_next(&from_bb);
to_bb = hyperbola_rook_moves(occ, from) & dest_squares; to_bb = hyperbola_rook_moves(occ, from) & dest_squares;
while(to_bb) { moves = moves_gen(moves, from, to_bb);
to = bb_next(&to_bb); //while(to_bb) {
*moves++ = move_make(from, to); // to = bb_next(&to_bb);
} // *moves++ = move_make(from, to);
//}
} }
/* knight */ /* knight */
@@ -354,10 +430,11 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
while (from_bb) { while (from_bb) {
from = bb_next(&from_bb); from = bb_next(&from_bb);
to_bb = bb_knight_moves(dest_squares, from); to_bb = bb_knight_moves(dest_squares, from);
while(to_bb) { moves = moves_gen(moves, from, to_bb);
to = bb_next(&to_bb); //while(to_bb) {
*moves++ = move_make(from, to); // to = bb_next(&to_bb);
} // *moves++ = move_make(from, to);
//}
} }
/* pawn: relative rank and files */ /* pawn: relative rank and files */
@@ -374,11 +451,11 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
from = to - shift; from = to - shift;
*moves++ = move_make(from, to); *moves++ = move_make(from, to);
} }
to_bb = tmp_bb & rel_rank8 & dest_squares; /* promotions */ to_bb = tmp_bb & rel_rank8 & dest_squares; /* promotions */
while(to_bb) { while(to_bb) {
to = bb_next(&to_bb); to = bb_next(&to_bb);
from = to - shift; from = to - shift;
moves = move_make_promotions(moves, from, to); moves = move_gen_promotions(moves, from, to);
} }
/* possible second push */ /* possible second push */
@@ -428,7 +505,7 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
while (to_bb) { while (to_bb) {
to = bb_next(&to_bb); to = bb_next(&to_bb);
from = to - shift; from = to - shift;
moves = move_make_promotions(moves, from, to); moves = move_gen_promotions(moves, from, to);
} }
/* pawn: captures right */ /* pawn: captures right */
@@ -445,7 +522,7 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
while (to_bb) { while (to_bb) {
to = bb_next(&to_bb); to = bb_next(&to_bb);
from = to - shift; from = to - shift;
moves = move_make_promotions(moves, from, to); moves = move_gen_promotions(moves, from, to);
} }
/* pawn: en-passant /* pawn: en-passant
@@ -458,23 +535,11 @@ int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist)
*moves++ = move_make_enpassant(from, to); *moves++ = move_make_enpassant(from, to);
} }
} }
/*
* to_bb = mask(to);
* /\* if e.p not on file H, we may add an e.p move to "up-left" *\/
* filter = ~bb_rel_file(FILE_A, us);
* shift = sq_upleft(us);
* if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
* *moves++ = move_make_enpassant(to - shift, to);
*
* filter = ~bb_rel_file(FILE_H, us);
* shift = sq_upright(us);
* if (bb_shift(pos->bb[us][PAWN] & filter, shift) & to_bb)
* *moves++ = move_make_enpassant(to - shift, to);
* }
*/
/* TODO: add function per piece, and type, for easier debug /* TODO: add function per piece, and type, for easier debug
*/ */
finish: finish:
return movelist->nmoves = moves - movelist->move; movelist->nmoves = moves - movelist->move;
return movelist;
//return movelist->nmoves = moves - movelist->move;
} }

View File

@@ -23,7 +23,9 @@
bool pseudo_is_legal(const pos_t *pos, const move_t move); bool pseudo_is_legal(const pos_t *pos, const move_t move);
move_t pos_next_legal(const pos_t *pos, movelist_t *movelist, int *start); move_t pos_next_legal(const pos_t *pos, movelist_t *movelist, int *start);
movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *dest); movelist_t *pos_legal_dup(const pos_t *pos, movelist_t *pseudo, movelist_t *legal);
int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist); movelist_t *pos_legal(const pos_t *pos, movelist_t *list);
movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist);
#endif /* MOVEGEN_H */ #endif /* MOVEGEN_H */

View File

@@ -47,13 +47,13 @@ enum {
}; };
typedef enum { typedef enum {
M_CAPTURE = mask(M_OFF_FLAGS + 0), M_CAPTURE = BIT(M_OFF_FLAGS + 0),
M_ENPASSANT = mask(M_OFF_FLAGS + 1), M_ENPASSANT = BIT(M_OFF_FLAGS + 1),
M_PROMOTION = mask(M_OFF_FLAGS + 2), M_PROMOTION = BIT(M_OFF_FLAGS + 2),
M_CASTLE_K = mask(M_OFF_FLAGS + 3), /* maybe only one ? */ M_CASTLE_K = BIT(M_OFF_FLAGS + 3), /* maybe only one ? */
M_CASTLE_Q = mask(M_OFF_FLAGS + 5), /* maybe only one ? */ M_CASTLE_Q = BIT(M_OFF_FLAGS + 5), /* maybe only one ? */
M_CHECK = mask(M_OFF_FLAGS + 6), /* maybe unknown/useless ? */ M_CHECK = BIT(M_OFF_FLAGS + 6), /* maybe unknown/useless ? */
M_DPUSH = mask(M_OFF_FLAGS + 7) /* pawn double push */ M_DPUSH = BIT(M_OFF_FLAGS + 7) /* pawn double push */
} move_flags_t; } move_flags_t;
#define move_set_flags(move, flags) ((move) | (flags)) #define move_set_flags(move, flags) ((move) | (flags))
@@ -101,7 +101,8 @@ static inline move_t move_make(square_t from, square_t to)
static inline move_t move_make_flags(square_t from, square_t to, move_flags_t flags) static inline move_t move_make_flags(square_t from, square_t to, move_flags_t flags)
{ {
return move_set_flags(move_make(from, to), flags); return (to << M_OFF_TO) | from | flags;
//move_set_flags(move_make(from, to), flags);
} }
static inline move_t move_make_capture(square_t from, square_t to) static inline move_t move_make_capture(square_t from, square_t to)

View File

@@ -18,8 +18,8 @@
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include "brlib.h" #include <brlib.h>
#include "bitops.h" #include <bitops.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "position.h" #include "position.h"
@@ -65,6 +65,7 @@ pos_t *pos_dup(const pos_t *pos)
/** /**
* pos_del() - delete a position. * pos_del() - delete a position.
* @pos: &position. * @pos: &position.
*
*/ */
void pos_del(pos_t *pos) void pos_del(pos_t *pos)
{ {
@@ -90,7 +91,7 @@ pos_t *pos_clear(pos_t *pos)
pos->castle = 0; pos->castle = 0;
pos->clock_50 = 0; pos->clock_50 = 0;
pos->plycount = 0; pos->plycount = 0;
//pos->captured = NO_PIECE; pos->captured = NO_PIECE;
for (square_t sq = A1; sq <= H8; ++sq) for (square_t sq = A1; sq <= H8; ++sq)
pos->board[sq] = EMPTY; pos->board[sq] = EMPTY;
@@ -120,50 +121,29 @@ bool pos_cmp(__unused const pos_t *pos1, __unused const pos_t *pos2)
{ {
#define _cmpf(a) (pos1->a != pos2->a) #define _cmpf(a) (pos1->a != pos2->a)
bool ret = false; bool ret = false;
if (warn_on(_cmpf(node_count)))
goto end; if (_cmpf(node_count) || _cmpf(turn))
if (warn_on(_cmpf(turn)))
goto end; goto end;
/* move_do/undo position state */ /* move_do/undo position state */
if (warn_on(_cmpf(en_passant))) if (_cmpf(en_passant) || _cmpf(castle) ||
_cmpf(clock_50) || _cmpf(plycount))
goto end; goto end;
if (warn_on(_cmpf(castle)))
goto end;
if (warn_on(_cmpf(clock_50)))
goto end;
if (warn_on(_cmpf(plycount)))
goto end;
//if (warn_on(_cmpf(captured)))
// goto end;
for (square_t sq = A1; sq <= H8; ++sq) for (square_t sq = A1; sq <= H8; ++sq)
if (warn_on(_cmpf(board[sq]))) if (_cmpf(board[sq]))
goto end; goto end;
for (color_t color = WHITE; color <= BLACK; ++color) { for (color_t color = WHITE; color <= BLACK; ++color) {
for (piece_type_t piece = 0; piece <= KING; ++piece) for (piece_type_t piece = 0; piece <= KING; ++piece)
if (warn_on(_cmpf(bb[color][piece]))) if (_cmpf(bb[color][piece]))
goto end; goto end;
//pos->controlled[color] = 0; if (_cmpf(king[color]))
if (warn_on(_cmpf(king[color])))
goto end; goto end;
} }
if (warn_on(_cmpf(checkers))) if (_cmpf(checkers) ||_cmpf(pinners) || _cmpf(blockers))
goto end; goto end;
if (warn_on(_cmpf(pinners)))
goto end;
if (warn_on(_cmpf(blockers)))
goto end;
/*
* if (warn_on(_cmpf(moves.nmoves)))
* goto end;
* for (int i = 0; i < pos1->moves.nmoves; ++i)
* if (warn_on(_cmpf(moves.move[i])))
* goto end;
*/
ret = true; ret = true;
end: end:
@@ -179,7 +159,7 @@ end:
* Get a bitboard of all checkers on @color king. * Get a bitboard of all checkers on @color king.
* Just a wrapper over @sq_attackers(). * Just a wrapper over @sq_attackers().
* *
* @return: a bitboard of attackers. * @return: a bitboard of checkers.
*/ */
bitboard_t pos_checkers(const pos_t *pos, const color_t color) bitboard_t pos_checkers(const pos_t *pos, const color_t color)
{ {
@@ -192,7 +172,7 @@ bitboard_t pos_checkers(const pos_t *pos, const color_t color)
* @pos: &position * @pos: &position
* *
* Set position checkers, pinners and blockers on player-to-play king. * Set position checkers, pinners and blockers on player-to-play king.
* It should be faster than @pos_checkers + @pos_set_pinners_blockers, as * It should be slightly faster than @pos_checkers + @pos_set_pinners_blockers, as
* some calculation will be done once. * some calculation will be done once.
*/ */
void pos_set_checkers_pinners_blockers(pos_t *pos) void pos_set_checkers_pinners_blockers(pos_t *pos)
@@ -228,7 +208,7 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
/* blockers = we find occupied squares between pinner and king */ /* blockers = we find occupied squares between pinner and king */
while (tmppinners) { while (tmppinners) {
pinner = bb_next(&tmppinners); pinner = bb_next(&tmppinners);
pinners |= mask(pinner); pinners |= BIT(pinner);
blockers |= bb_between[pinner][king] & maybeblockers; blockers |= bb_between[pinner][king] & maybeblockers;
} }
} }
@@ -246,7 +226,7 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
tmppinners = targets & attackers; tmppinners = targets & attackers;
while (tmppinners) { while (tmppinners) {
pinner = bb_next(&tmppinners); pinner = bb_next(&tmppinners);
pinners |= mask(pinner); pinners |= BIT(pinner);
blockers |= bb_between[pinner][king] & maybeblockers; blockers |= bb_between[pinner][king] & maybeblockers;
} }
} }
@@ -336,11 +316,11 @@ bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboa
* - total number of pieces > 16 or zero (per color) * - total number of pieces > 16 or zero (per color)
* - number of kings != 1 (per color) * - number of kings != 1 (per color)
* - discrepancy between board and king (per color) * - discrepancy between board and king (per color)
* - discrepancy between piece bitboards and ALL_PIECES bitboards (per color)
* - discrepancy between bitboards and board (per color) * - discrepancy between bitboards and board (per color)
* - side-to-move already checking opponent king * - side-to-move already checking opponent king
* - side-to-move in check more than twice * - side-to-move in check more than twice
* - kings distance is 1 * - kings distance is 1
* - TODO: discrepancy between piece bitboards and ALL_PIECES bitboards (per color)
* *
* In case of errors, and @strict is true, @bug_on() is called, and program will * In case of errors, and @strict is true, @bug_on() is called, and program will
* be terminated. * be terminated.
@@ -348,19 +328,23 @@ bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboa
* (eg after fen parsing), and with @strict == true otherwise (as we have some data * (eg after fen parsing), and with @strict == true otherwise (as we have some data
* corruption). * corruption).
* *
* TODO: add more checks:
* - kings attacking each other
*
* @return: (if @strict is false) return true if check is ok, false otherwise. * @return: (if @strict is false) return true if check is ok, false otherwise.
*/ */
bool pos_ok(__unused const pos_t *pos, __unused const bool strict) bool pos_ok(const pos_t *pos, const bool strict)
{ {
int n, count = 0, bbcount = 0, error = 0; int n, count = 0, bbcount = 0, error = 0;
__unused bitboard_t tmp;
/* force BUG_ON and WARN_ON */
# pragma push_macro("BUG_ON")
# pragma push_macro("WARN_ON")
# undef BUG_ON
# define BUG_ON
# undef WARN_ON
# define WARN_ON
/* pawns on 1st ot 8th rank */ /* pawns on 1st ot 8th rank */
tmp = (pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & (RANK_1bb | RANK_8bb); error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &
error += warn_on(tmp); (RANK_1bb | RANK_8bb));
for (color_t color = WHITE; color <= BLACK; ++color) { for (color_t color = WHITE; color <= BLACK; ++color) {
/* pawn count */ /* pawn count */
@@ -378,26 +362,31 @@ bool pos_ok(__unused const pos_t *pos, __unused const bool strict)
} }
for (square_t sq = 0; sq < 64; ++sq) { for (square_t sq = 0; sq < 64; ++sq) {
piece_t piece = pos->board[sq]; piece_t piece = pos->board[sq];
__unused bitboard_t match; bitboard_t match;
if (piece == EMPTY) if (piece == EMPTY)
continue; continue;
color_t c = COLOR(piece); color_t c = COLOR(piece);
piece_type_t p = PIECE(piece); piece_type_t p = PIECE(piece);
match = pos->bb[c][p] & mask(sq); match = pos->bb[c][p] & BIT(sq);
error += warn_on(!match); error += warn_on(!match);
count++; count++;
} }
/* occupied occupation is different from bitboards */ /* occupied board is different from bitboards */
error += warn_on(count != bbcount); error += warn_on(count != bbcount);
/* is opponent already in check ? */ /* is opponent already in check ? */
error += warn_on(pos_checkers(pos, OPPONENT(pos->turn))); error += warn_on(pos_checkers(pos, OPPONENT(pos->turn)));
/* is color to play in check more than twice ? */ /* is color to play in check more than twice ? */
error += warn_on(popcount64(pos_checkers(pos, OPPONENT(pos->turn))) > 2); error += warn_on(popcount64(pos_checkers(pos, pos->turn)) > 2);
/* kings distance is less than 2 */ /* kings distance is less than 2 */
error += warn_on(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2); error += warn_on(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2);
bug_on(strict && error); if (strict) {
bug_on(error);
/* not reached */
}
return error? false: true; return error? false: true;
# pragma pop_macro("WARN_ON")
# pragma pop_macro("BUG_ON")
} }
/** /**

View File

@@ -30,9 +30,12 @@ typedef struct __pos_s {
u64 node_count; /* evaluated nodes */ u64 node_count; /* evaluated nodes */
int turn; /* WHITE or BLACK */ int turn; /* WHITE or BLACK */
/* data which cannot be recovered by move_undo (like castle_rights, ...), /* data which cannot be recovered by move_undo (like castle_rights, ...).
* or would be expensive to recover (checkers, ...) *
* following data can be accessed either directly, either via "movesave" * Attention: checkers/pinners/blockers are not included here, and
* are not available in move_undo or any following legality check.
*
* Following data can be accessed either directly, either via "state"
* structure name. * structure name.
* For example, pos->en_passant and pos->state.en_passant are the same. * For example, pos->en_passant and pos->state.en_passant are the same.
* This allows a memcpy on this data (to save/restore position state). * This allows a memcpy on this data (to save/restore position state).
@@ -40,19 +43,17 @@ typedef struct __pos_s {
struct_group_tagged(state_s, state, struct_group_tagged(state_s, state,
square_t en_passant; square_t en_passant;
castle_rights_t castle; castle_rights_t castle;
u16 clock_50; int clock_50;
u16 plycount; /* plies so far, start from 1 */ int plycount; /* plies so far, start from 1 */
piece_t captured; /* only for move_undo */ piece_t captured; /* only used in move_undo */
bitboard_t checkers; /* opponent checkers */
bitboard_t pinners; /* opponent pinners */
bitboard_t blockers; /* pieces blocking pin */
); );
bitboard_t checkers; /* opponent checkers */
bitboard_t pinners; /* opponent pinners */
bitboard_t blockers; /* pieces blocking pin */
piece_t board[BOARDSIZE]; piece_t board[BOARDSIZE];
bitboard_t bb[2][PIECE_TYPE_MAX]; /* bb[0][PAWN], bb[1][ALL_PIECES] */ bitboard_t bb[2][PIECE_TYPE_MAX]; /* bb[0][PAWN], bb[1][ALL_PIECES] */
//bitboard_t controlled[2]; /* unsure */
square_t king[2]; /* dup with bb, faster retrieval */ square_t king[2]; /* dup with bb, faster retrieval */
//movelist_t moves;
} pos_t; } pos_t;
typedef struct state_s state_t; typedef struct state_s state_t;
@@ -72,8 +73,8 @@ 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);
pos->board[square] = piece; pos->board[square] = piece;
pos->bb[color][type] |= mask(square); pos->bb[color][type] |= BIT(square);
pos->bb[color][ALL_PIECES] |= mask(square); pos->bb[color][ALL_PIECES] |= BIT(square);
if (type == KING) if (type == KING)
pos->king[color] = square; pos->king[color] = square;
} }
@@ -91,8 +92,8 @@ static __always_inline void pos_clr_sq(pos_t *pos, square_t square)
piece_type_t type = PIECE(piece); piece_type_t type = PIECE(piece);
color_t color = COLOR(piece); color_t color = COLOR(piece);
pos->board[square] = EMPTY; pos->board[square] = EMPTY;
pos->bb[color][type] &= ~mask(square); pos->bb[color][type] &= ~BIT(square);
pos->bb[color][ALL_PIECES] &= ~mask(square); pos->bb[color][ALL_PIECES] &= ~BIT(square);
if (type == KING) if (type == KING)
pos->king[color] = SQUARE_NONE; pos->king[color] = SQUARE_NONE;
} }

View File

@@ -33,49 +33,51 @@
* This version uses the algorithm: * This version uses the algorithm:
* if last depth * if last depth
* return 1; * return 1;
* gen pseudo-legal moves * gen legal moves
* loop for each legal move * loop for legal move
* do-move * do-move
* perft (depth -1) * perft (depth -1)
* undo-move * undo-move
* *
* @return: total moves found at @depth level. * @return: total moves found at @depth level.
*/ */
u64 perft(pos_t *pos, int depth, int ply) u64 perft(pos_t *pos, int depth, int ply, bool output)
{ {
int subnodes, movetmp = 0; int subnodes;
u64 nodes = 0; u64 nodes = 0;
movelist_t pseudo; movelist_t movelist;
move_t move; move_t *move, *last;
state_t state; state_t state;
if (depth == 0) movelist.nmoves = 0;
return 1; pos_set_checkers_pinners_blockers(pos);
pseudo.nmoves = 0;
pos->checkers = pos_checkers(pos, pos->turn);
pos_set_pinners_blockers(pos);
state = pos->state; state = pos->state;
pos_gen_pseudomoves(pos, &pseudo); pos_legal(pos, pos_gen_pseudo(pos, &movelist));
while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) { last = movelist.move + movelist.nmoves;
move_do(pos, move); for (move = movelist.move; move < last; ++move) {
subnodes = perft(pos, depth - 1, ply + 1); if (depth == 1) {
if (ply == 1) { nodes++;
char movestr[8]; } else {
printf("%s: %d\n", move_str(movestr, move, 0), subnodes); move_do(pos, *move);
subnodes = perft(pos, depth - 1, ply + 1, output);
if (output && ply == 1) {
char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes);
}
nodes += subnodes;
move_undo(pos, *move);
pos->state = state;
} }
nodes += subnodes;
move_undo(pos, move);
pos->state = state;
} }
if (ply == 1) if (output && ply == 1)
printf("Total: %lu\n", nodes); printf("Total: %lu\n", nodes);
return nodes; return nodes;
} }
/** /**
* perft_new_pinners() - Perform perft on position * perft_test() - Perform perft on position, experiment version.
* @pos: &position to search * @pos: &position to search
* @depth: Wanted depth. * @depth: Wanted depth.
* @ply: perft depth level. * @ply: perft depth level.
@@ -85,34 +87,35 @@ u64 perft(pos_t *pos, int depth, int ply)
* *
* @return: total moves found at @depth level. * @return: total moves found at @depth level.
*/ */
u64 perft_new_pinners(pos_t *pos, int depth, int ply) u64 perft_test(pos_t *pos, int depth, int ply, bool output)
{ {
int subnodes, movetmp = 0; int subnodes;
u64 nodes = 0; u64 nodes = 0;
movelist_t pseudo; movelist_t movelist;
move_t move; move_t *move, *last;
state_t state; state_t state;
if (depth == 0) movelist.nmoves = 0;
return 1;
pseudo.nmoves = 0;
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
state = pos->state;
pos_gen_pseudomoves(pos, &pseudo); pos_legal(pos, pos_gen_pseudo(pos, &movelist));
while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) { last = movelist.move + movelist.nmoves;
move_do(pos, move); for (move = movelist.move; move < last; ++move) {
subnodes = perft_new_pinners(pos, depth - 1, ply + 1); if (depth == 1) {
if (ply == 1) { nodes++;
char movestr[8]; } else {
printf("%s: %d\n", move_str(movestr, move, 0), subnodes); move_do2(pos, *move, &state);
subnodes = perft(pos, depth - 1, ply + 1, output);
if (output && ply == 1) {
char movestr[8];
printf("%s: %d\n", move_str(movestr, *move, 0), subnodes);
}
nodes += subnodes;
move_undo2(pos, *move, &state);
} }
nodes += subnodes;
move_undo(pos, move);
pos->state = state;
} }
if (ply == 1) if (output && ply == 1)
printf("Total: %lu\n", nodes); printf("Total: %lu\n", nodes);
return nodes; return nodes;
} }
@@ -315,24 +318,24 @@ u64 perft_new_pinners(pos_t *pos, int depth, int ply)
* @return: The @pos negamax evaluation. * @return: The @pos negamax evaluation.
*/ */
/*int ab_negamax(pos_t *pos, int alpha, int beta, int depth) /*int ab_negamax(pos_t *pos, int alpha, int beta, int depth)
{ {
move_t *move; move_t *move;
pos_t *newpos; pos_t *newpos;
eval_t best = EVAL_MIN, score; eval_t best = EVAL_MIN, score;
if(depth == 0) { if(depth == 0) {
//return quiesce( alpha, beta ); //return quiesce( alpha, beta );
moves_gen_all_nomoves(pos); moves_gen_all_nomoves(pos);
score = eval(pos) * color; score = eval(pos) * color;
return score; return score;
} }
for ( all moves) { for ( all moves) {
score = -alphaBeta( -beta, -alpha, depthleft - 1 ); score = -alphaBeta( -beta, -alpha, depthleft - 1 );
if( score >= beta ) if( score >= beta )
return beta; // fail hard beta-cutoff return beta; // fail hard beta-cutoff
if( score > alpha ) if( score > alpha )
alpha = score; // alpha acts like max in MiniMax alpha = score; // alpha acts like max in MiniMax
} }
return alpha; return alpha;
} }
*/ */

View File

@@ -19,8 +19,7 @@
//eval_t negamax(pos_t *pos, int depth, int color); //eval_t negamax(pos_t *pos, int depth, int color);
//eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color); //eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color);
u64 perft(pos_t *pos, int depth, int ply); u64 perft(pos_t *pos, int depth, int ply, bool output);
u64 perft2(pos_t *pos, int depth, int ply); u64 perft_test(pos_t *pos, int depth, int ply, bool output);
u64 perft_new_pinners(pos_t *pos, int depth, int ply);
#endif /* SEARCH_H */ #endif /* SEARCH_H */

View File

@@ -29,12 +29,11 @@ struct fentest {
char *fen; char *fen;
} fentest[] = { } fentest[] = {
/* /*
{ __LINE__. { __LINE__, 1,
ATTACK, "",
"checkers: ",
"" ""
}, },
*/ */
/* ***************** TEMP TESTS ABOVE ************************** */ /* ***************** TEMP TESTS ABOVE ************************** */
@@ -413,22 +412,22 @@ struct fentest {
{ __LINE__, 0, NULL, NULL } { __LINE__, 0, NULL, NULL }
}; };
static int cur = -1; static int fentest_cur = -1;
static char *next_fen(uint module) static char *next_fen(uint module)
{ {
cur++; fentest_cur++;
while (fentest[cur].fen && !(fentest[cur].modules & module)) while (fentest[fentest_cur].fen && !(fentest[fentest_cur].modules & module))
cur++; fentest_cur++;
return fentest[cur].fen; return fentest[fentest_cur].fen;
} }
static __unused char* cur_comment() static __unused char* cur_comment()
{ {
return fentest[cur].comment; return fentest[fentest_cur].comment;
} }
static __unused int cur_line() static __unused int cur_line()
{ {
return fentest[cur].line; return fentest[fentest_cur].line;
} }

View File

@@ -47,7 +47,7 @@ int main(int __unused ac, __unused char**av)
pos->checkers = pos_checkers(pos, pos->turn); pos->checkers = pos_checkers(pos, pos->turn);
pos_set_pinners_blockers(pos); pos_set_pinners_blockers(pos);
pos_gen_pseudomoves(pos, &pseudo); pos_gen_pseudo(pos, &pseudo);
savepos = pos_dup(pos); savepos = pos_dup(pos);
state_t state = pos->state; state_t state = pos->state;

View File

@@ -216,7 +216,7 @@ int main(int __unused ac, __unused char**av)
FILE *outfd; FILE *outfd;
char *fen; char *fen;
pos_t *pos, *fishpos = pos_new(); pos_t *pos, *fishpos = pos_new();
movelist_t pseudo, legal, fishmoves; movelist_t pseudo, fishmoves;
//bitboard_t wrong = 0x5088000040, tmp, loop; //bitboard_t wrong = 0x5088000040, tmp, loop;
//bit_for_each64(loop, tmp, ) //bit_for_each64(loop, tmp, )
//printf("fishpos 1=%p\n", fishpos); //printf("fishpos 1=%p\n", fishpos);
@@ -239,9 +239,9 @@ int main(int __unused ac, __unused char**av)
send_stockfish_fen(outfd, fishpos, &fishmoves, fen); send_stockfish_fen(outfd, fishpos, &fishmoves, fen);
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
pos_gen_pseudomoves(pos, &pseudo); pos_gen_pseudo(pos, &pseudo);
//moves_print(&pseudo, 0); //moves_print(&pseudo, 0);
pos_all_legal(pos, &pseudo, &legal); pos_legal(pos, &pseudo);
//moves_print(&legal, 0); //moves_print(&legal, 0);
//printf("Fu "); //printf("Fu ");
@@ -253,7 +253,7 @@ int main(int __unused ac, __unused char**av)
/* sort and print movelists */ /* sort and print movelists */
move_sort_by_sq(&fishmoves); move_sort_by_sq(&fishmoves);
move_sort_by_sq(&legal); move_sort_by_sq(&pseudo);
// printf("\nFs "); // printf("\nFs ");
// moves_print(fishpos, 0); // moves_print(fishpos, 0);
// fflush(stdout); // fflush(stdout);
@@ -262,14 +262,14 @@ int main(int __unused ac, __unused char**av)
// fflush(stdout); // fflush(stdout);
/* compare movelists */ /* compare movelists */
if (!movelists_equal(&fishmoves, &legal)) { if (!movelists_equal(&fishmoves, &pseudo)) {
pos_print(pos); pos_print(pos);
printf("F: "); printf("F: ");
moves_print(&fishmoves, 0); moves_print(&fishmoves, 0);
printf("M: "); printf("M: ");
moves_print(&legal, 0); moves_print(&pseudo, 0);
} else { } else {
printf("[%s]: OK (%d Moves)\n", fen, legal.nmoves); printf("[%s]: OK (%d Moves)\n", fen, pseudo.nmoves);
//moves_print(&fishpos->moves, 0); //moves_print(&fishpos->moves, 0);
} }
//compare_moves(&fishpos->moves, &legal); //compare_moves(&fishpos->moves, &legal);

View File

@@ -16,6 +16,7 @@
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <locale.h> #include <locale.h>
#include <limits.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "fen.h" #include "fen.h"
@@ -105,6 +106,7 @@ static u64 send_stockfish_fen(FILE *desc, pos_t *pos, movelist_t *movelist,
//sprintf(str, "stockfish \"position fen %s\ngo perft depth\n\"", fen); //sprintf(str, "stockfish \"position fen %s\ngo perft depth\n\"", fen);
fprintf(desc, "position fen %s\ngo perft %d\n", fen, depth); fprintf(desc, "position fen %s\ngo perft %d\n", fen, depth);
//fflush(desc); //fflush(desc);
while ((buflen = getline(&buf, &alloc, stdin)) > 0) { while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
buf[--buflen] = 0; buf[--buflen] = 0;
if (buflen == 0) if (buflen == 0)
@@ -222,32 +224,66 @@ static __unused void compare_moves(movelist_t *fish, movelist_t *me)
printf("F(%2d): %s\nM(%2d): %s\n", n1, str1, n2, str2); printf("F(%2d): %s\nM(%2d): %s\n", n1, str1, n2, str2);
} }
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d depth] [-p pertf-modules] -n\n", prg);
return 1;
}
int main(int __unused ac, __unused char**av) int main(int __unused ac, __unused char**av)
{ {
int i = 0, test_line; int i = 0, test_line;
u64 sf_count, my_count; u64 sf_count = 0, my_count;
char *fen; char *fen;
pos_t *pos, *savepos, *fishpos = pos_new(); pos_t *pos;
pos_t *fishpos = pos_new();
movelist_t fishmoves; movelist_t fishmoves;
//move_t move; //move_t move;
FILE *outfd; FILE *outfd = NULL;
s64 ms1 = 0, ms1_total = 0; struct {
s64 ms2 = 0, ms2_total = 0; s64 count, ms;
s64 minlps, maxlps;
int skipped;
} res[2] = {
{ .minlps=LONG_MAX },
{ .minlps=LONG_MAX },
};
s64 ms, lps;
int depth = 6, run = 3; int opt, depth = 6, run = 3;
bool sf_run = true, perft_output = false;
if (ac > 1) while ((opt = getopt(ac, av, "vnd:p:")) != -1) {
depth = atoi(av[1]); switch (opt) {
if (ac > 2) case 'd':
run = atoi(av[2]) & 3; depth = atoi(optarg);
printf("depth = %d run=%d\n", depth, run); break;
case 'p': /* 1 or 2 */
run = atoi(optarg);
break;
case 'n':
sf_run = false;
break;
case 'v':
perft_output = true;
break;
default:
return usage(*av);
}
}
//if (ac > 1)
// depth = atoi(av[1]);
//if (ac > 2)
// run = atoi(av[2]) & 3;
printf("depth = %d run = %x sf = %s\n", depth, run, sf_run? "true": "false");
if (!run) if (!run)
exit(0); exit(0);
setlocale(LC_NUMERIC, ""); setlocale(LC_NUMERIC, "");
setlinebuf(stdout); /* line-buffered stdout */ setlinebuf(stdout); /* line-buffered stdout */
outfd = open_stockfish();
if (sf_run)
outfd = open_stockfish();
bitboard_init(); bitboard_init();
hyperbola_init(); hyperbola_init();
@@ -259,19 +295,32 @@ int main(int __unused ac, __unused char**av)
printf("wrong fen %d: [%s]\n", i, fen); printf("wrong fen %d: [%s]\n", i, fen);
continue; continue;
} }
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth); if (sf_run)
savepos = pos_dup(pos); sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
// savepos = pos_dup(pos);
if (run & 1) { if (run & 1) {
clock_start(&clock); clock_start(&clock);
my_count = perft(pos, depth, 1); my_count = perft(pos, depth, 1, perft_output);
ms1 = clock_elapsed_ms(&clock); ms = clock_elapsed_ms(&clock);
ms1_total += ms1; if (!ms) {
res[0].skipped++;
lps = 0;
} else {
lps = my_count * 1000l / ms;
res[0].ms += ms;
res[0].count += my_count;
if (lps > res[0].maxlps)
res[0].maxlps = lps;
if (lps < res[0].minlps)
res[0].minlps = lps;
}
if (sf_count == my_count) { if (!sf_run || sf_count == my_count) {
printf("pt1 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n", printf("pt1 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
test_line, my_count, ms1, test_line, my_count, ms,
ms1? my_count*1000l/ms1: 0, lps,
fen); fen);
} else { } else {
printf("pt1 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n", printf("pt1 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
@@ -281,14 +330,25 @@ int main(int __unused ac, __unused char**av)
if (run & 2) { if (run & 2) {
clock_start(&clock); clock_start(&clock);
my_count = perft_new_pinners(pos, depth, 1); my_count = perft_test(pos, depth, 1, perft_output);
ms2 = clock_elapsed_ms(&clock); ms = clock_elapsed_ms(&clock);
ms2_total += ms2; if (!ms) {
res[1].skipped++;
lps = 0;
} else {
lps = my_count * 1000l / ms;
res[1].ms += ms;
res[1].count += my_count;
if (lps > res[1].maxlps)
res[1].maxlps = lps;
if (lps < res[1].minlps)
res[1].minlps = lps;
}
if (sf_count == my_count) { if (!sf_run || sf_count == my_count) {
printf("pt2 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n", printf("pt2 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
test_line, my_count, ms2, test_line, my_count, ms,
ms2? my_count*1000l/ms2: 0, lps,
fen); fen);
} else { } else {
printf("pt2 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n", printf("pt2 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
@@ -296,15 +356,23 @@ int main(int __unused ac, __unused char**av)
} }
} }
printf("\n"); printf("\n");
pos_del(savepos); // pos_del(savepos);
pos_del(pos); pos_del(pos);
i++; i++;
/* to run first test only */ /* to run first test only */
// exit(0); // exit(0);
} }
if (run & 1) if (run & 1)
printf("total perft %'ldms\n", ms1_total); printf("total perft %'lums %'lums lps=%'lu min=%'lu max=%'lu (skipped %d)\n",
res[0].count, res[0].ms,
res[0].count * 1000l / res[0].ms,
res[0].minlps, res[0].maxlps,
res[0].skipped);
if (run & 2) if (run & 2)
printf("total perft2 %'ldms\n", ms2_total); printf("total perft2 %'lums %'lums lps=%'lu min=%'lu max=%'lu (skipped %d)\n",
res[1].count, res[1].ms,
res[1].count * 1000l / res[1].ms,
res[1].minlps, res[1].maxlps,
res[1].skipped);
return 0; return 0;
} }