diff --git a/src/board.c b/src/board.c index 8acfc4d..96b5c8a 100644 --- a/src/board.c +++ b/src/board.c @@ -14,7 +14,8 @@ #include #include -#include "brlib.h" +#include + #include "board.h" #include "bitboard.h" diff --git a/src/move-do.c b/src/move-do.c index cc4c333..53a16f6 100644 --- a/src/move-do.c +++ b/src/move-do.c @@ -47,13 +47,175 @@ * * @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) { -//# ifdef DEBUG_MOVE_DO -// move_print(move, M_PR_NL | M_PR_LONG); -//# endif - //*state = pos->state; /* save irreversible changes */ + 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); + hkey_t key = pos->key; + *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->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); + key ^= zobrist_pieces[captured][to]; + 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); + } + key ^= zobrist_pieces[pos->board[rookfrom]][rookto] ^ + zobrist_pieces[pos->board[rookfrom]][rookfrom]; + 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. */ + square_t ep = from + up;; + if (bb_pawn_attacks[us][ep] & pos->bb[them][PAWN]) { + pos->en_passant = ep; + key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)]; + } + } else if (is_enpassant(move)) { /* clear grabbed pawn */ + square_t grabbed = to - up; + key ^= zobrist_pieces[pos->board[grabbed]][grabbed]; + pos_clr_sq(pos, grabbed); + } + } + + 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); + + 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)) { + 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); + } + + /* update castling rights key */ + key ^= zobrist_castling[pos->castle]; + + pos->key = key; + + zobrist_verify(pos); + + return pos; +} + +/** + * move_undo() - undo move. + * @pos: &pos_t position + * @move: move to undo + * @state: &state_t address where irreversible changes were saved + * + * @move is applied to @pos: + * - bitboards and board are updated + * - previous information is restored: + * - castling + * - en-passant + * - captured piece (excl. en-passant) + * - move count + * - 50-moves rule count + * + * @return: pos. + */ +pos_t *move_undo(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; +} + +/** + * move_{do,undo}_alt - alternative move_do/move_undo (to experiment) + */ +pos_t *move_do_alt(pos_t *pos, const move_t move) //, state_t *state) +{ color_t us = pos->turn, them = OPPONENT(us); square_t from = move_from(move), to = move_to(move); piece_t piece = pos->board[from]; @@ -100,13 +262,15 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state) zobrist_pieces[pos->board[rookfrom]][rookfrom]; pos_set_sq(pos, rookto, pos->board[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. */ pos->clock_50 = 0; if (is_dpush(move)) { /* if pawn double push, set e.p. */ - pos->en_passant = from + up; - /* update ep key */ - key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)]; + square_t ep = from + up;; + if (bb_pawn_attacks[us][ep] & pos->bb[them][PAWN]) { + pos->en_passant = ep; + key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)]; + } } else if (is_enpassant(move)) { /* clear grabbed pawn */ square_t grabbed = to - up; key ^= zobrist_pieces[pos->board[grabbed]][grabbed]; @@ -151,139 +315,12 @@ pos_t *move_do(pos_t *pos, const move_t move) //, state_t *state) pos->key = key; - bug_on(zobrist_verify(pos) == false); + zobrist_verify(pos); 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); - hkey_t key = pos->key; - - *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->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); - key ^= zobrist_pieces[captured][to]; - 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); - } - key ^= zobrist_pieces[pos->board[rookfrom]][rookto]; - key ^= zobrist_pieces[pos->board[rookfrom]][rookfrom]; - 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; - /* update key */ - key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)]; - } else if (is_enpassant(move)) { /* clear grabbed pawn */ - square_t grabbed = to - up; - key ^= zobrist_pieces[pos->board[grabbed]][grabbed]; - pos_clr_sq(pos, grabbed); - } - } - - 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); - - 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)) { - 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); - } - - /* update castle key */ - key ^= zobrist_castling[pos->castle]; - - pos->key = key; - - bug_on(zobrist_verify(pos) == false); - - return pos; -} - -/** - * move_undo() - undo move. - * @pos: &pos_t position - * @move: move to undo - * @state: &state_t address where irreversible changes were saved - * - * @move is applied to @pos: - * - bitboards and board are updated - * - previous information is restored: - * - castling - * - en-passant - * - captured piece (excl. en-passant) - * - move count - * - 50-moves rule count - * - * @return: pos. - */ -pos_t *move_undo(pos_t *pos, const move_t move) +pos_t *move_undo_alt(pos_t *pos, const move_t move) { color_t them = pos->turn, us = OPPONENT(them); square_t from = move_from(move), to = move_to(move); @@ -321,42 +358,3 @@ 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; -} diff --git a/src/move-do.h b/src/move-do.h index fb2dbce..1bfe032 100644 --- a/src/move-do.h +++ b/src/move-do.h @@ -16,10 +16,10 @@ #include "position.h" -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_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); +pos_t *move_do_alt(pos_t *pos, const move_t move);//, state_t *state); +pos_t *move_undo_alt(pos_t *pos, const move_t move);//, const state_t *state); #endif /* MOVE_DO_H */ diff --git a/src/search.c b/src/search.c index 9fd90cf..9cdd0f7 100644 --- a/src/search.c +++ b/src/search.c @@ -51,7 +51,6 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) 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; @@ -59,7 +58,7 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) if (depth == 1) { nodes++; } else { - move_do(pos, *move); + move_do(pos, *move, &state); if (depth == 2) { movelist_t movelist2; pos_set_checkers_pinners_blockers(pos); @@ -72,8 +71,7 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) printf("%s: %d\n", move_str(movestr, *move, 0), subnodes); } nodes += subnodes; - move_undo(pos, *move); - pos->state = state; + move_undo(pos, *move, &state); } } @@ -83,7 +81,7 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) } /** - * perft_test() - Perform perft on position, experiment version. + * perft_alt() - Perform perft on position, experimental version. * @pos: &position to search * @depth: Wanted depth. * @ply: perft depth level. @@ -93,7 +91,7 @@ u64 perft(pos_t *pos, int depth, int ply, bool output) * * @return: total moves found at @depth level. */ -u64 perft_test(pos_t *pos, int depth, int ply, bool output) +u64 perft_alt(pos_t *pos, int depth, int ply, bool output) { int subnodes; u64 nodes = 0; @@ -103,6 +101,7 @@ u64 perft_test(pos_t *pos, int depth, int ply, bool output) 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; @@ -110,20 +109,21 @@ u64 perft_test(pos_t *pos, int depth, int ply, bool output) if (depth == 1) { nodes++; } else { - move_do2(pos, *move, &state); + move_do_alt(pos, *move); 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); + subnodes = perft_alt(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); + move_undo_alt(pos, *move); + pos->state = state; } } diff --git a/src/search.h b/src/search.h index a2d1531..e6019e4 100644 --- a/src/search.h +++ b/src/search.h @@ -20,6 +20,6 @@ //eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color); u64 perft(pos_t *pos, int depth, int ply, bool output); -u64 perft_test(pos_t *pos, int depth, int ply, bool output); +u64 perft_alt(pos_t *pos, int depth, int ply, bool output); #endif /* SEARCH_H */ diff --git a/test/movedo-test.c b/test/movedo-test.c index bc534ff..25fa11a 100644 --- a/test/movedo-test.c +++ b/test/movedo-test.c @@ -29,8 +29,8 @@ int main(int __unused ac, __unused char**av) int i = 0, test_line; char *fen, movebuf[8];; pos_t *pos, *savepos; - movelist_t pseudo; - move_t move; + movelist_t movelist; + move_t *move, *last; init_all(); @@ -41,39 +41,39 @@ int main(int __unused ac, __unused char**av) continue; } - pos->checkers = pos_checkers(pos, pos->turn); - pos_set_pinners_blockers(pos); - - pos_gen_pseudo(pos, &pseudo); + movelist.nmoves = 0; + pos_set_checkers_pinners_blockers(pos); + pos_legal(pos, pos_gen_pseudo(pos, &movelist)); + last = movelist.move + movelist.nmoves; savepos = pos_dup(pos); state_t state = pos->state; - int tmp = 0, j = 0; - while ((move = pos_next_legal(pos, &pseudo, &tmp)) != MOVE_NONE) { + int j = 0; + for (move = movelist.move; move < last; ++move) { //pos_print(pos); //printf("i=%d j=%d turn=%d move=[%s]\n", i, j, pos->turn, // move_str(movebuf, move, 0)); //move_p - move_do(pos, move); + move_do(pos, *move, &state); //pos_print(pos); //fflush(stdout); if (!pos_ok(pos, false)) { - printf("*** fen %d move %d [%s] invalid position after move_do\n", - test_line, j, movebuf); + printf("*** fen %d [%s] move %d [%s] invalid position after move_do\n", + test_line, fen, j, move_str(movebuf, *move, 0)); exit(0); } //printf("%d/%d move_do check ok\n", i, j); - move_undo(pos, move); + move_undo(pos, *move, &state); pos->state = state; if (!pos_ok(pos, false)) { - printf("*** fen %d move %d [%s] invalid position after move_undo\n", - test_line, j, movebuf); + printf("*** fen %d [%s] move %d [%s] invalid position after move_undo\n", + test_line, fen, j, movebuf); exit(0); } if (pos_cmp(pos, savepos) != true) { - printf("*** fen %d move %d [%s] position differ after move_{do,undo}\n", - test_line, j, movebuf); + printf("*** fen %d [%s] move %d [%s] position differ after move_{do,undo}\n", + test_line, fen, j, movebuf); exit(0); } //fflush(stdout); diff --git a/test/perft-test.c b/test/perft-test.c index 85334ee..87cfbe9 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -374,7 +374,7 @@ int main(int ac, char**av) if (run & 2) { clock_start(&clock); - my_count = perft_test(pos, depth, 1, perft_output); + my_count = perft_alt(pos, depth, 1, perft_output); ms = clock_elapsed_ms(&clock); if (!ms) { res[1].skipped++;