move-do: use castling flags, other improvements (~12% on perft)
- always set K square and castling flags (remove expensive tests on K and castling flags) - simplify castling rook move
This commit is contained in:
156
src/move-do.c
156
src/move-do.c
@@ -25,6 +25,20 @@
|
|||||||
#include "move-do.h"
|
#include "move-do.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sq_castle - castling rights per square.
|
||||||
|
*
|
||||||
|
* position castling rights mask has to be AND'ed with this array 'from' and 'to'.
|
||||||
|
*/
|
||||||
|
castle_rights_t sq_castle[64] = {
|
||||||
|
[A1] = ~CASTLE_WQ, [B1 ... D1] = ~CASTLE_NONE,
|
||||||
|
[E1] = ~CASTLE_W, [F1 ... G1] = ~CASTLE_NONE,
|
||||||
|
[H1] = ~CASTLE_WK, [A2 ... H7] = ~CASTLE_NONE,
|
||||||
|
[A8] = ~CASTLE_BQ, [B8 ... D8] = ~CASTLE_NONE,
|
||||||
|
[E8] = ~CASTLE_B, [F8 ... G8] = ~CASTLE_NONE,
|
||||||
|
[H8] = ~CASTLE_BK,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* move_do() - do move.
|
* move_do() - do move.
|
||||||
* @pos: &pos_t position
|
* @pos: &pos_t position
|
||||||
@@ -60,9 +74,8 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state)
|
|||||||
|
|
||||||
*state = pos->state; /* save irreversible changes */
|
*state = pos->state; /* save irreversible changes */
|
||||||
|
|
||||||
/* update key: switch turn, reset castling and ep */
|
/* update key: switch turn, reset ep */
|
||||||
key ^= zobrist_turn;
|
key ^= zobrist_turn;
|
||||||
key ^= zobrist_castling[pos->castle];
|
|
||||||
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
|
|
||||||
++pos->clock_50;
|
++pos->clock_50;
|
||||||
@@ -74,80 +87,69 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state)
|
|||||||
|
|
||||||
bug_on(COLOR(piece) != us);
|
bug_on(COLOR(piece) != us);
|
||||||
|
|
||||||
if (is_promotion(move)) {
|
/* special moves: captures, pawn double push, en-passant, castling.
|
||||||
bug_on(sq_rank(to) != sq_rel_rank(RANK_8, us));
|
* All these moves are exclusive (so we use if ... else)
|
||||||
new_piece = MAKE_PIECE(move_promoted(move), us);
|
*/
|
||||||
}
|
if (captured != EMPTY) { /* capture: remove piece */
|
||||||
|
|
||||||
if (captured != EMPTY) {
|
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
|
||||||
key ^= zobrist_pieces[captured][to];
|
key ^= zobrist_pieces[captured][to];
|
||||||
pos_clr_sq(pos, to); /* clear square */
|
pos_clr_sq(pos, to);
|
||||||
} else if (is_castle(move)) { /* handle rook move */
|
} else if (ptype == PAWN) {
|
||||||
square_t rookfrom, rookto;
|
|
||||||
if (to > from) {
|
|
||||||
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;
|
pos->clock_50 = 0;
|
||||||
if (from + up + up == to) { /* if pawn double push, set e.p. */
|
if (from + up + up == to) { /* double push: set e.p. */
|
||||||
square_t ep = from + up;
|
square_t ep = from + up;
|
||||||
|
/* check that opponent can e.p. */
|
||||||
if (bb_pawn_attacks[us][ep] & pos->bb[them][PAWN]) {
|
if (bb_pawn_attacks[us][ep] & pos->bb[them][PAWN]) {
|
||||||
pos->en_passant = ep;
|
pos->en_passant = ep;
|
||||||
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
key ^= zobrist_ep[EP_ZOBRIST_IDX(pos->en_passant)];
|
||||||
}
|
}
|
||||||
} else if (is_enpassant(move)) { /* clear grabbed pawn */
|
} else if (is_enpassant(move)) { /* e.p.: clear grabbed pawn */
|
||||||
square_t grabbed = to - up;
|
square_t grabbed = to - up;
|
||||||
piece_t pc = pos->board[grabbed];
|
piece_t pc = pos->board[grabbed];
|
||||||
key ^= zobrist_pieces[pc][grabbed];
|
key ^= zobrist_pieces[pc][grabbed];
|
||||||
pos_clr_sq(pos, grabbed);
|
pos_clr_sq(pos, grabbed);
|
||||||
}
|
}
|
||||||
|
} else if (is_castle(move)) { /* castling: handle rook move */
|
||||||
|
square_t rookfrom, rookto;
|
||||||
|
if (to > from) { /* o-o */
|
||||||
|
rookfrom = to + 1;
|
||||||
|
rookto = to - 1;
|
||||||
|
} else { /* o-o-o */
|
||||||
|
rookfrom = to - 2;
|
||||||
|
rookto = to + 1;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* common part: captures and non captures
|
||||||
|
* We could improve slightly, as en-passant and double push will make
|
||||||
|
* the following tests.
|
||||||
|
* Improvement could be to add promotion test and king test twice above.
|
||||||
|
* (in capture and after ).
|
||||||
|
*/
|
||||||
|
if (is_promotion(move)) {
|
||||||
|
bug_on(sq_rank(to) != sq_rel_rank(RANK_8, us));
|
||||||
|
new_piece = MAKE_PIECE(move_promoted(move), us);
|
||||||
}
|
}
|
||||||
|
|
||||||
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
|
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
|
||||||
pos_clr_sq(pos, from); /* clear "from" and set "to" */
|
pos_clr_sq(pos, from);
|
||||||
pos_set_sq(pos, to, new_piece);
|
pos_set_sq(pos, to, new_piece);
|
||||||
|
|
||||||
if (ptype == KING)
|
/* update castling flags */
|
||||||
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];
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
pos->castle &= sq_castle[from] & sq_castle[to];
|
||||||
|
key ^= zobrist_castling[pos->castle];
|
||||||
|
|
||||||
|
//if (ptype == KING) {
|
||||||
|
// pos->king[us] = to;
|
||||||
|
//} else
|
||||||
|
/* do this always, cheaper than test on K move */
|
||||||
|
pos->king[us] = ctz64(pos->bb[us][KING]);
|
||||||
|
|
||||||
pos->key = key;
|
pos->key = key;
|
||||||
|
|
||||||
@@ -180,33 +182,43 @@ pos_t *move_undo(pos_t *pos, const move_t move, const state_t *state)
|
|||||||
piece_t piece = pos->board[to];
|
piece_t piece = pos->board[to];
|
||||||
int up = sq_up(them);
|
int up = sq_up(them);
|
||||||
|
|
||||||
|
/* common part: captures and non captures
|
||||||
|
* We could improve slightly, as en-passant and double push will make
|
||||||
|
* the following tests.
|
||||||
|
* Improvement could be to add promotion test and king test twice above.
|
||||||
|
* (in capture and after ).
|
||||||
|
*/
|
||||||
if (is_promotion(move))
|
if (is_promotion(move))
|
||||||
piece = MAKE_PIECE(PAWN, us);
|
piece = MAKE_PIECE(PAWN, us);
|
||||||
|
|
||||||
pos_clr_sq(pos, to); /* always clear "to" ... */
|
pos_clr_sq(pos, to);
|
||||||
pos_set_sq(pos, from, piece); /* ... and set "from" */
|
pos_set_sq(pos, from, piece);
|
||||||
|
|
||||||
if (PIECE(piece) == KING)
|
/* special moves: capture, king (+ castling), en-passant
|
||||||
pos->king[us] = from;
|
*/
|
||||||
|
if (pos->captured != EMPTY) { /* captured: restore piece */
|
||||||
if (pos->captured != EMPTY) {
|
pos_set_sq(pos, to, pos->captured);
|
||||||
pos_set_sq(pos, to, pos->captured); /* restore captured piece */
|
} else if (is_castle(move)) { /* castle: rook move */
|
||||||
} else if (is_castle(move)) { /* make reverse rook move */
|
|
||||||
square_t rookfrom, rookto;
|
square_t rookfrom, rookto;
|
||||||
if (to > from) {
|
if (to > from) { /* o-o */
|
||||||
rookfrom = sq_rel(F1, us);
|
rookfrom = to - 1;
|
||||||
rookto = sq_rel(H1, us);
|
rookto = to + 1;
|
||||||
} else {
|
} else { /* o-o-o */
|
||||||
rookfrom = sq_rel(D1, us);
|
rookfrom = to + 1;
|
||||||
rookto = sq_rel(A1, us);
|
rookto = to - 2;
|
||||||
}
|
}
|
||||||
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
pos_set_sq(pos, rookto, pos->board[rookfrom]);
|
||||||
pos_clr_sq(pos, rookfrom);
|
pos_clr_sq(pos, rookfrom);
|
||||||
} else if (is_enpassant(move)) { /* restore grabbed pawn */
|
} else if (is_enpassant(move)) { /* e.p.: restore grabbed pawn */
|
||||||
square_t grabbed = to + up;
|
square_t grabbed = to + up;
|
||||||
pos_set_sq(pos, grabbed, MAKE_PIECE(PAWN, them));
|
pos_set_sq(pos, grabbed, MAKE_PIECE(PAWN, them));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do this always, cheaper than test on K move */
|
||||||
|
pos->king[us] = ctz64(pos->bb[us][KING]);
|
||||||
|
//if (PIECE(piece) == KING)
|
||||||
|
// pos->king[us] = from;
|
||||||
|
|
||||||
pos->state = *state; /* restore irreversible changes */
|
pos->state = *state; /* restore irreversible changes */
|
||||||
pos->turn = us;
|
pos->turn = us;
|
||||||
return pos;
|
return pos;
|
||||||
@@ -284,7 +296,7 @@ pos_t *move_do_alt(pos_t *pos, const move_t move, state_t *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
|
key ^= zobrist_pieces[piece][from] ^ zobrist_pieces[new_piece][to];
|
||||||
pos_clr_sq(pos, from); /* clear "from" and set "to" */
|
pos_clr_sq(pos, from);
|
||||||
pos_set_sq(pos, to, new_piece);
|
pos_set_sq(pos, to, new_piece);
|
||||||
|
|
||||||
if (ptype == KING)
|
if (ptype == KING)
|
||||||
|
@@ -14,8 +14,11 @@
|
|||||||
#ifndef MOVE_DO_H
|
#ifndef MOVE_DO_H
|
||||||
#define MOVE_DO_H
|
#define MOVE_DO_H
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
|
extern castle_rights_t sq_castle[64]; /* to adjust castling rights */
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user