move_do2: save/restore state inside func; perft: add silent option
This commit is contained in:
2
Makefile
2
Makefile
@@ -110,7 +110,7 @@ CFLAGS += -Wmissing-declarations
|
||||
CFLAGS := $(strip $(CFLAGS))
|
||||
|
||||
# development CFLAGS - unused - TODO
|
||||
#DEV_CFLAGS := -O1
|
||||
#DEV_CFLAGS := -Og
|
||||
#DEV_CFLAGS += -g
|
||||
|
||||
# release CFLAGS - unused - TODO
|
||||
|
128
src/move-do.c
128
src/move-do.c
@@ -131,6 +131,95 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state)
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* move_undo() - undo move.
|
||||
* @pos: &pos_t position
|
||||
@@ -186,3 +275,42 @@ pos_t *move_undo(pos_t *pos, const move_t move)
|
||||
pos->turn = us;
|
||||
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;
|
||||
}
|
||||
|
@@ -19,4 +19,7 @@
|
||||
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_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 */
|
||||
|
22
src/search.c
22
src/search.c
@@ -41,7 +41,7 @@
|
||||
*
|
||||
* @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;
|
||||
u64 nodes = 0;
|
||||
@@ -60,8 +60,8 @@ u64 perft(pos_t *pos, int depth, int ply)
|
||||
nodes++;
|
||||
} else {
|
||||
move_do(pos, *move);
|
||||
subnodes = perft(pos, depth - 1, ply + 1);
|
||||
if (ply == 1) {
|
||||
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);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ u64 perft(pos_t *pos, int depth, int ply)
|
||||
}
|
||||
}
|
||||
|
||||
if (ply == 1)
|
||||
if (output && ply == 1)
|
||||
printf("Total: %lu\n", nodes);
|
||||
return nodes;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ u64 perft(pos_t *pos, int depth, int ply)
|
||||
*
|
||||
* @return: total moves found at @depth level.
|
||||
*/
|
||||
u64 perft_test(pos_t *pos, int depth, int ply)
|
||||
u64 perft_test(pos_t *pos, int depth, int ply, bool output)
|
||||
{
|
||||
int subnodes;
|
||||
u64 nodes = 0;
|
||||
@@ -97,7 +97,6 @@ u64 perft_test(pos_t *pos, int depth, int ply)
|
||||
|
||||
movelist.nmoves = 0;
|
||||
pos_set_checkers_pinners_blockers(pos);
|
||||
state = pos->state;
|
||||
|
||||
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
|
||||
last = movelist.move + movelist.nmoves;
|
||||
@@ -105,19 +104,18 @@ u64 perft_test(pos_t *pos, int depth, int ply)
|
||||
if (depth == 1) {
|
||||
nodes++;
|
||||
} else {
|
||||
move_do(pos, *move);
|
||||
subnodes = perft(pos, depth - 1, ply + 1);
|
||||
if (ply == 1) {
|
||||
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_undo(pos, *move);
|
||||
pos->state = state;
|
||||
move_undo2(pos, *move, &state);
|
||||
}
|
||||
}
|
||||
|
||||
if (ply == 1)
|
||||
if (output && ply == 1)
|
||||
printf("Total: %lu\n", nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
//eval_t negamax(pos_t *pos, int depth, 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_test(pos_t *pos, int depth, int ply);
|
||||
u64 perft(pos_t *pos, int depth, int ply, bool output);
|
||||
u64 perft_test(pos_t *pos, int depth, int ply, bool output);
|
||||
|
||||
#endif /* SEARCH_H */
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "chessdefs.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);
|
||||
fprintf(desc, "position fen %s\ngo perft %d\n", fen, depth);
|
||||
//fflush(desc);
|
||||
|
||||
while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
|
||||
buf[--buflen] = 0;
|
||||
if (buflen == 0)
|
||||
@@ -233,17 +235,25 @@ int main(int __unused ac, __unused char**av)
|
||||
int i = 0, test_line;
|
||||
u64 sf_count = 0, my_count;
|
||||
char *fen;
|
||||
pos_t *pos, *savepos, *fishpos = pos_new();
|
||||
pos_t *pos;
|
||||
pos_t *fishpos = pos_new();
|
||||
movelist_t fishmoves;
|
||||
//move_t move;
|
||||
FILE *outfd = NULL;
|
||||
s64 ms1 = 0, ms1_total = 0;
|
||||
s64 ms2 = 0, ms2_total = 0;
|
||||
struct {
|
||||
s64 count, ms;
|
||||
s64 minlps, maxlps;
|
||||
int skipped;
|
||||
} res[2] = {
|
||||
{ .minlps=LONG_MAX },
|
||||
{ .minlps=LONG_MAX },
|
||||
};
|
||||
s64 ms, lps;
|
||||
|
||||
int opt, depth = 6, run = 3;
|
||||
bool sf_run = true;
|
||||
bool sf_run = true, perft_output = false;
|
||||
|
||||
while ((opt = getopt(ac, av, "nd:p:")) != -1) {
|
||||
while ((opt = getopt(ac, av, "vnd:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
depth = atoi(optarg);
|
||||
@@ -254,6 +264,9 @@ int main(int __unused ac, __unused char**av)
|
||||
case 'n':
|
||||
sf_run = false;
|
||||
break;
|
||||
case 'v':
|
||||
perft_output = true;
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
@@ -285,18 +298,29 @@ int main(int __unused ac, __unused char**av)
|
||||
if (sf_run)
|
||||
sf_count = send_stockfish_fen(outfd, fishpos, &fishmoves, fen, depth);
|
||||
|
||||
savepos = pos_dup(pos);
|
||||
// savepos = pos_dup(pos);
|
||||
|
||||
if (run & 1) {
|
||||
clock_start(&clock);
|
||||
my_count = perft(pos, depth, 1);
|
||||
ms1 = clock_elapsed_ms(&clock);
|
||||
ms1_total += ms1;
|
||||
my_count = perft(pos, depth, 1, perft_output);
|
||||
ms = clock_elapsed_ms(&clock);
|
||||
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_run || sf_count == my_count) {
|
||||
printf("pt1 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
|
||||
test_line, my_count, ms1,
|
||||
ms1? my_count*1000l/ms1: 0,
|
||||
test_line, my_count, ms,
|
||||
lps,
|
||||
fen);
|
||||
} else {
|
||||
printf("pt1 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
|
||||
@@ -306,14 +330,25 @@ int main(int __unused ac, __unused char**av)
|
||||
|
||||
if (run & 2) {
|
||||
clock_start(&clock);
|
||||
my_count = perft_test(pos, depth, 1);
|
||||
ms2 = clock_elapsed_ms(&clock);
|
||||
ms2_total += ms2;
|
||||
my_count = perft_test(pos, depth, 1, perft_output);
|
||||
ms = clock_elapsed_ms(&clock);
|
||||
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_run || sf_count == my_count) {
|
||||
printf("pt2 OK : line=%3d perft=%'lu %'ldms lps=%'lu \"%s\"\n",
|
||||
test_line, my_count, ms2,
|
||||
ms2? my_count*1000l/ms2: 0,
|
||||
test_line, my_count, ms,
|
||||
lps,
|
||||
fen);
|
||||
} else {
|
||||
printf("pt2 ERR: line=%3d sf=%'lu me=%'lu \"%s\"\n",
|
||||
@@ -321,15 +356,23 @@ int main(int __unused ac, __unused char**av)
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
pos_del(savepos);
|
||||
// pos_del(savepos);
|
||||
pos_del(pos);
|
||||
i++;
|
||||
/* to run first test only */
|
||||
// exit(0);
|
||||
}
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user