From: Marco Costalba Date: Sun, 26 Oct 2008 20:44:58 +0000 (+0100) Subject: Manual merge X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=74f1efee263aadcceb1df716ebd87776b932238a;hp=d3600c39a745179ed6b094b305d0645e83a1ee86;p=stockfish Manual merge --- diff --git a/src/bitboard.h b/src/bitboard.h index 8c6a7007..1222ddfa 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -7,12 +7,13 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -30,6 +31,10 @@ // platform macros defined below #define AUTO_CONFIGURATION +// Quiet a warning on Intel compiler +#if !defined(__SIZEOF_INT__ ) +#define __SIZEOF_INT__ 0 +#endif // Check for 64 bits for different compilers: Intel, MSVC and gcc #if defined(__x86_64) || defined(_WIN64) || (__SIZEOF_INT__ > 4) @@ -39,7 +44,7 @@ #if !defined(AUTO_CONFIGURATION) || defined(IS_64BIT) //#define USE_COMPACT_ROOK_ATTACKS -//#define USE_32BIT_ATTACKS +//#define USE_32BIT_ATTACKS #define USE_FOLDED_BITSCAN #define BITCOUNT_SWAR_64 @@ -48,7 +53,7 @@ #else -#define USE_32BIT_ATTACKS +#define USE_32BIT_ATTACKS #define USE_FOLDED_BITSCAN #define BITCOUNT_SWAR_32 @@ -93,7 +98,7 @@ const Bitboard FileHBB = 0x8080808080808080ULL; extern const Bitboard FileBB[8]; extern const Bitboard NeighboringFilesBB[8]; -extern const Bitboard ThisAndNeighboringFilesBB[8]; +extern const Bitboard ThisAndNeighboringFilesBB[8]; const Bitboard Rank1BB = 0xFFULL; const Bitboard Rank2BB = 0xFF00ULL; @@ -128,7 +133,7 @@ extern int RAttackIndex[64]; extern Bitboard RAttacks[0x19000]; #endif // defined(USE_COMPACT_ROOK_ATTACKS) -extern const uint64_t BMult[64]; +extern const uint64_t BMult[64]; extern const int BShift[64]; extern Bitboard BMask[64]; extern int BAttackIndex[64]; @@ -143,29 +148,19 @@ extern Bitboard QueenPseudoAttacks[64]; //// Inline functions //// -/// Functions for testing whether a given bit is set in a bitboard, and for +/// Functions for testing whether a given bit is set in a bitboard, and for /// setting and clearing bits. -inline Bitboard set_mask_bb(Square s) { - // return 1ULL << s; - return SetMaskBB[s]; -} - -inline Bitboard clear_mask_bb(Square s) { - // return ~set_mask_bb(s); - return ClearMaskBB[s]; -} - inline Bitboard bit_is_set(Bitboard b, Square s) { - return b & set_mask_bb(s); + return b & SetMaskBB[s]; } inline void set_bit(Bitboard *b, Square s) { - *b |= set_mask_bb(s); + *b |= SetMaskBB[s]; } inline void clear_bit(Bitboard *b, Square s) { - *b &= clear_mask_bb(s); + *b &= ClearMaskBB[s]; } @@ -200,7 +195,7 @@ inline Bitboard neighboring_files_bb(File f) { inline Bitboard neighboring_files_bb(Square s) { return neighboring_files_bb(square_file(s)); } - + /// this_and_neighboring_files_bb takes a file or a square as input, and /// returns a bitboard representing all squares on the given and neighboring @@ -275,9 +270,9 @@ inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) { inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) { Bitboard b = blockers & RMask[s]; - return RAttacks[RAttackIndex[s] + + return RAttacks[RAttackIndex[s] + (unsigned(int(b) * int(RMult[s]) ^ - int(b >> 32) * int(RMult[s] >> 32)) + int(b >> 32) * int(RMult[s] >> 32)) >> RShift[s])]; } @@ -294,9 +289,9 @@ inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) { inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) { Bitboard b = blockers & BMask[s]; - return BAttacks[BAttackIndex[s] + + return BAttacks[BAttackIndex[s] + (unsigned(int(b) * int(BMult[s]) ^ - int(b >> 32) * int(BMult[s] >> 32)) + int(b >> 32) * int(BMult[s] >> 32)) >> BShift[s])]; } @@ -324,9 +319,9 @@ inline Bitboard squares_between(Square s1, Square s2) { } -/// squares_in_front_of takes a color and a square as input, and returns a +/// squares_in_front_of takes a color and a square as input, and returns a /// bitboard representing all squares along the line in front of the square, -/// from the point of view of the given color. For instance, +/// from the point of view of the given color. For instance, /// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares /// e3, e2 and e1 set. @@ -343,8 +338,8 @@ inline Bitboard squares_behind(Color c, Square s) { } -/// passed_pawn_mask takes a color and a square as input, and returns a -/// bitboard mask which can be used to test if a pawn of the given color on +/// passed_pawn_mask takes a color and a square as input, and returns a +/// bitboard mask which can be used to test if a pawn of the given color on /// the given square is a passed pawn. inline Bitboard passed_pawn_mask(Color c, Square s) { @@ -361,7 +356,7 @@ inline Bitboard outpost_mask(Color c, Square s) { } -/// isolated_pawn_mask takes a square as input, and returns a bitboard mask +/// isolated_pawn_mask takes a square as input, and returns a bitboard mask /// which can be used to test whether a pawn on the given square is isolated. inline Bitboard isolated_pawn_mask(Square s) { diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8f3ef1cd..a7e5f2d5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -778,7 +778,7 @@ namespace { while (b) { Square from, to = pop_1st_bit(&b); - if (!(escapeSquares & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) + if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[s]))) { // We have a mate, unless the queen is pinned or there // is an X-ray attack through the queen. @@ -787,8 +787,8 @@ namespace { from = p.piece_list(them, QUEEN, i); if ( bit_is_set(p.piece_attacks(from), to) && !bit_is_set(p.pinned_pieces(them), from) - && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) & p.rooks_and_queens(us)) - && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) & p.rooks_and_queens(us))) + && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us)) + && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us))) ei.mateThreat[them] = make_move(from, to); } diff --git a/src/movegen.cpp b/src/movegen.cpp index 50f8b488..397732b5 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -6,12 +6,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -25,6 +25,9 @@ #include "movegen.h" +// Simple macro to wrap a very common while loop, no facny, no flexibility, +// hardcoded list name 'mlist' and from square 'from'. +#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) //// //// Local definitions @@ -32,89 +35,73 @@ namespace { - struct PawnParams { - Bitboard Rank3BB, Rank8BB; - Rank RANK_8; - SquareDelta DELTA_N, DELTA_NE, DELTA_NW; - Color us, them; - }; - const PawnParams WhitePawnParams = { Rank3BB, Rank8BB, RANK_8, DELTA_N, DELTA_NE, DELTA_NW, WHITE, BLACK }; - const PawnParams BlackPawnParams = { Rank6BB, Rank1BB, RANK_1, DELTA_S, DELTA_SE, DELTA_SW, BLACK, WHITE }; - - int generate_castle_moves(const Position&, MoveStack*, Color); + // Function + MoveStack* generate_castle_moves(const Position&, MoveStack*); + + // Template generate_pawn_captures() with specializations + template + MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist); template - int generate_pawn_captures(const Position&, MoveStack*); + inline MoveStack* generate_pawn_captures(const Position& p, MoveStack* m) { + return do_generate_pawn_captures(p, m); + } + template<> + inline MoveStack* generate_pawn_captures(const Position& p, MoveStack* m) { + return do_generate_pawn_captures(p, m); + } + + // Template generate_pawn_noncaptures() with specializations + template + MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist); template - int generate_pawn_noncaptures(const Position&, MoveStack*); - + inline MoveStack* generate_pawn_noncaptures(const Position& p, MoveStack* m) { + return do_generate_pawn_noncaptures(p, m); + } + template<> + inline MoveStack* generate_pawn_noncaptures(const Position& p, MoveStack* m) { + return do_generate_pawn_noncaptures(p, m); + } + + // Template generate_pawn_blocking_evasions() with specializations + template + MoveStack* do_generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned, + Bitboard blockSquares, MoveStack* mlist); template - int generate_pawn_checks(const Position&, Bitboard, Square, MoveStack*, int); + inline MoveStack* generate_pawn_blocking_evasions(const Position& p, Bitboard np, Bitboard bs, MoveStack* m) { + return do_generate_pawn_blocking_evasions(p, np, bs, m); + } + template<> + inline MoveStack* generate_pawn_blocking_evasions(const Position& p, Bitboard np, Bitboard bs, MoveStack* m) { + return do_generate_pawn_blocking_evasions(p, np, bs, m); + } + + // Template generate_pawn_checks() with specializations + template + MoveStack* do_generate_pawn_checks(const Position&, Bitboard, Square, MoveStack*); template - int generate_pawn_blocking_evasions(const Position&, Bitboard, Bitboard, MoveStack*, int); + inline MoveStack* generate_pawn_checks(const Position& p, Bitboard dc, Square ksq, MoveStack* m) { + return do_generate_pawn_checks(p, dc, ksq, m); + } + template<> + inline MoveStack* generate_pawn_checks(const Position& p, Bitboard dc, Square ksq, MoveStack* m) { + return do_generate_pawn_checks(p, dc, ksq, m); + } + // non-pawn templates template - int generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); + MoveStack* generate_piece_moves(const Position&, MoveStack*, Color us, Bitboard); + template<> + MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target); template - int generate_piece_checks(const Position&, Bitboard, Bitboard, Square, MoveStack*, int); + MoveStack* generate_piece_checks(const Position&, Bitboard, Bitboard, Square, MoveStack*); + MoveStack* generate_piece_checks_king(const Position&, Square, Bitboard, Square, MoveStack*); template - int generate_piece_blocking_evasions(const Position&, Bitboard, Bitboard, MoveStack*, int); - - - /// Templates with specializations are defined here to avoid lookup issues - - template - int generate_piece_checks(const Position& pos, Bitboard target, Bitboard dc, - Square ksq, MoveStack* mlist, int n) { - // Discovered checks - Bitboard b = target & dc; - while (b) - { - Square from = pop_1st_bit(&b); - Bitboard bb = pos.piece_attacks(from) & pos.empty_squares(); - while (bb) - { - Square to = pop_1st_bit(&bb); - mlist[n++].move = make_move(from, to); - } - } - // Direct checks - b = target & ~dc; - Bitboard checkSqs = pos.piece_attacks(ksq) & pos.empty_squares(); - while (b) - { - Square from = pop_1st_bit(&b); - Bitboard bb = pos.piece_attacks(from) & checkSqs; - while (bb) - { - Square to = pop_1st_bit(&bb); - mlist[n++].move = make_move(from, to); - } - } - return n; - } - - - template<> // Special case the King - int generate_piece_checks(const Position& pos, Bitboard, Bitboard dc, - Square ksq, MoveStack* mlist, int n) { - if (bit_is_set(dc, ksq)) - { - Bitboard bb = pos.piece_attacks(ksq) - & pos.empty_squares() - & ~QueenPseudoAttacks[ksq]; - while (bb) - { - Square to = pop_1st_bit(&bb); - mlist[n++].move = make_move(ksq, to); - } - } - return n; - } + MoveStack* generate_piece_blocking_evasions(const Position&, Bitboard, Bitboard, MoveStack*); } @@ -133,96 +120,95 @@ int generate_captures(const Position& pos, MoveStack* mlist) { Color us = pos.side_to_move(); Bitboard target = pos.pieces_of_color(opposite_color(us)); - int n; + MoveStack* mlist_start = mlist; if (us == WHITE) - n = generate_pawn_captures(pos, mlist); + mlist = generate_pawn_captures(pos, mlist); else - n = generate_pawn_captures(pos, mlist); - - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - return n; + mlist = generate_pawn_captures(pos, mlist); + + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + return int(mlist - mlist_start); } -/// generate_noncaptures() generates all pseudo-legal non-captures and +/// generate_noncaptures() generates all pseudo-legal non-captures and /// underpromotions. The return value is the number of moves generated. -int generate_noncaptures(const Position& pos, MoveStack *mlist) { +int generate_noncaptures(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); assert(!pos.is_check()); Color us = pos.side_to_move(); Bitboard target = pos.empty_squares(); - int n; + MoveStack* mlist_start = mlist; if (us == WHITE) - n = generate_pawn_noncaptures(pos, mlist); + mlist = generate_pawn_noncaptures(pos, mlist); else - n = generate_pawn_noncaptures(pos, mlist); - - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - n += generate_piece_moves(pos, mlist+n, us, target); - - n += generate_castle_moves(pos, mlist+n, us); - return n; + mlist = generate_pawn_noncaptures(pos, mlist); + + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_castle_moves(pos, mlist); + return int(mlist - mlist_start); } /// generate_checks() generates all pseudo-legal non-capturing, non-promoting /// checks, except castling moves (will add this later). It returns the -/// number of generated moves. +/// number of generated moves. int generate_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { assert(pos.is_ok()); assert(!pos.is_check()); - int n; Color us = pos.side_to_move(); Square ksq = pos.king_square(opposite_color(us)); + MoveStack* mlist_start = mlist; assert(pos.piece_on(ksq) == king_of_color(opposite_color(us))); dc = pos.discovered_check_candidates(us); // Pawn moves - if (us == WHITE) - n = generate_pawn_checks(pos, dc, ksq, mlist, 0); + if (us == WHITE) + mlist = generate_pawn_checks(pos, dc, ksq, mlist); else - n = generate_pawn_checks(pos, dc, ksq, mlist, 0); + mlist = generate_pawn_checks(pos, dc, ksq, mlist); // Pieces moves Bitboard b = pos.knights(us); if (b) - n = generate_piece_checks(pos, b, dc, ksq, mlist, n); + mlist = generate_piece_checks(pos, b, dc, ksq, mlist); b = pos.bishops(us); if (b) - n = generate_piece_checks(pos, b, dc, ksq, mlist, n); + mlist = generate_piece_checks(pos, b, dc, ksq, mlist); b = pos.rooks(us); if (b) - n = generate_piece_checks(pos, b, dc, ksq, mlist, n); + mlist = generate_piece_checks(pos, b, dc, ksq, mlist); b = pos.queens(us); if (b) - n = generate_piece_checks(pos, b, dc, ksq, mlist, n); + mlist = generate_piece_checks(pos, b, dc, ksq, mlist); // Hopefully we always have a king ;-) - n = generate_piece_checks(pos, b, dc, pos.king_square(us), mlist, n); + mlist = generate_piece_checks_king(pos, pos.king_square(us), dc, ksq, mlist); // TODO: Castling moves! - - return n; + + return int(mlist - mlist_start); } @@ -236,14 +222,14 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); assert(pos.is_check()); + Square from, to; Color us = pos.side_to_move(); Color them = opposite_color(us); Square ksq = pos.king_square(us); - Square from, to; - int n = 0; + MoveStack* mlist_start = mlist; assert(pos.piece_on(ksq) == king_of_color(us)); - + // Generate evasions for king Bitboard b1 = pos.piece_attacks(ksq) & ~pos.pieces_of_color(us); Bitboard b2 = pos.occupied_squares(); @@ -251,20 +237,20 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { while (b1) { - Square to = pop_1st_bit(&b1); + to = pop_1st_bit(&b1); - // Make sure to is not attacked by the other side. This is a bit ugly, + // Make sure 'to' is not attacked by the other side. This is a bit ugly, // because we can't use Position::square_is_attacked. Instead we use // the low-level bishop_attacks_bb and rook_attacks_bb with the bitboard // b2 (the occupied squares with the king removed) in order to test whether // the king will remain in check on the destination square. - if (!( (bishop_attacks_bb(to, b2) & pos.bishops_and_queens(them)) - || (rook_attacks_bb(to, b2) & pos.rooks_and_queens(them)) - || (pos.piece_attacks(to) & pos.knights(them)) - || (pos.pawn_attacks(us, to) & pos.pawns(them)) - || (pos.piece_attacks(to) & pos.kings(them)))) + if (!( (pos.piece_attacks(to) & pos.knights(them)) + || (pos.pawn_attacks(us, to) & pos.pawns(them)) + || (bishop_attacks_bb(to, b2) & pos.bishops_and_queens(them)) + || (rook_attacks_bb(to, b2) & pos.rooks_and_queens(them)) + || (pos.piece_attacks(to) & pos.kings(them)))) - mlist[n++].move = make_move(ksq, to); + (*mlist++).move = make_move(ksq, to); } // Generate evasions for other pieces only if not double check. We use a @@ -290,12 +276,12 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { from = pop_1st_bit(&b1); if (relative_rank(us, checksq) == RANK_8) { - mlist[n++].move = make_promotion_move(from, checksq, QUEEN); - mlist[n++].move = make_promotion_move(from, checksq, ROOK); - mlist[n++].move = make_promotion_move(from, checksq, BISHOP); - mlist[n++].move = make_promotion_move(from, checksq, KNIGHT); + (*mlist++).move = make_promotion_move(from, checksq, QUEEN); + (*mlist++).move = make_promotion_move(from, checksq, ROOK); + (*mlist++).move = make_promotion_move(from, checksq, BISHOP); + (*mlist++).move = make_promotion_move(from, checksq, KNIGHT); } else - mlist[n++].move = make_move(from, checksq); + (*mlist++).move = make_move(from, checksq); } // Pieces captures @@ -306,7 +292,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { while (b1) { from = pop_1st_bit(&b1); - mlist[n++].move = make_move(from, checksq); + (*mlist++).move = make_move(from, checksq); } // Blocking check evasions are possible only if the checking piece is @@ -320,26 +306,26 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { // Pawn moves. Because a blocking evasion can never be a capture, we // only generate pawn pushes. if (us == WHITE) - n = generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist, n); + generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); else - n = generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist, n); + generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); // Pieces moves b1 = pos.knights(us) & not_pinned; if (b1) - n = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist, n); + generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.bishops(us) & not_pinned; if (b1) - n = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist, n); + generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.rooks(us) & not_pinned; if (b1) - n = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist, n); + generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.queens(us) & not_pinned; if (b1) - n = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist, n); + generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); } // Finally, the ugly special case of en passant captures. An en passant @@ -353,7 +339,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { b1 = pos.pawn_attacks(them, to) & pos.pawns(us); assert(b1 != EmptyBoardBB); - + b1 &= not_pinned; while (b1) { @@ -369,12 +355,12 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { clear_bit(&b2, checksq); if (!( (bishop_attacks_bb(ksq, b2) & pos.bishops_and_queens(them)) ||(rook_attacks_bb(ksq, b2) & pos.rooks_and_queens(them)))) - - mlist[n++].move = make_ep_move(from, to); + + (*mlist++).move = make_ep_move(from, to); } } } - return n; + return int(mlist - mlist_start); } @@ -391,32 +377,33 @@ int generate_legal_moves(const Position& pos, MoveStack* mlist) { if (pos.is_check()) return generate_evasions(pos, mlist); - // Generate pseudo-legal moves: + // Generate pseudo-legal moves int n = generate_captures(pos, mlist); n += generate_noncaptures(pos, mlist + n); Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); - // Remove illegal moves from the list: + // Remove illegal moves from the list for (int i = 0; i < n; i++) - if (!pos.move_is_legal(mlist[i].move, pinned)) + if (!pos.pl_move_is_legal(mlist[i].move, pinned)) mlist[i--].move = mlist[--n].move; return n; } -/// generate_move_if_legal() takes a position and a (not necessarily -/// pseudo-legal) move and a pinned pieces bitboard as input, and tests -/// whether the move is legal. If the move is legal, the move itself is -/// returned. If not, the function returns MOVE_NONE. This function must +/// move_is_legal() takes a position and a (not necessarily pseudo-legal) +/// move and a pinned pieces bitboard as input, and tests whether +/// the move is legal. If the move is legal, the move itself is +/// returned. If not, the function returns false. This function must /// only be used when the side to move is not in check. -Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { +bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { assert(pos.is_ok()); assert(!pos.is_check()); assert(move_is_ok(m)); + assert(pinned == pos.pinned_pieces(pos.side_to_move())); Color us = pos.side_to_move(); Color them = opposite_color(us); @@ -426,7 +413,7 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { // If the from square is not occupied by a piece belonging to the side to // move, the move is obviously not legal. if (color_of_piece(pc) != us) - return MOVE_NONE; + return false; Square to = move_to(m); @@ -437,13 +424,13 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { // en passant square. if ( type_of_piece(pc) != PAWN || to != pos.ep_square()) - return MOVE_NONE; + return false; assert(pos.square_is_empty(to)); assert(pos.piece_on(to - pawn_push(us)) == pawn_of_color(them)); - // The move is pseudo-legal. If it is legal, return it. - return (pos.move_is_legal(m) ? m : MOVE_NONE); + // The move is pseudo-legal, check if it is also legal + return pos.pl_move_is_legal(m, pinned); } // Castling moves @@ -453,7 +440,7 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { // the right to castle kingside. if ( type_of_piece(pc) != KING ||!pos.can_castle_kingside(us)) - return MOVE_NONE; + return false; assert(from == pos.king_square(us)); assert(to == pos.initial_kr_square(us)); @@ -477,7 +464,7 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { if (s != from && s != to && !pos.square_is_empty(s)) illegal = true; - return (!illegal ? m : MOVE_NONE); + return !illegal; } if (move_is_long_castle(m)) @@ -486,7 +473,7 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { // the right to castle kingside. if ( type_of_piece(pc) != KING ||!pos.can_castle_queenside(us)) - return MOVE_NONE; + return false; assert(from == pos.king_square(us)); assert(to == pos.initial_qr_square(us)); @@ -511,24 +498,24 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { || pos.piece_on(to + DELTA_W) == queen_of_color(them))) illegal = true; - return (!illegal ? m : MOVE_NONE); + return !illegal; } // Normal moves // The destination square cannot be occupied by a friendly piece if (pos.color_of_piece_on(to) == us) - return MOVE_NONE; + return false; // Proceed according to the type of the moving piece. if (type_of_piece(pc) == PAWN) - { + { // If the destination square is on the 8/1th rank, the move must // be a promotion. if ( ( (square_rank(to) == RANK_8 && us == WHITE) ||(square_rank(to) == RANK_1 && us != WHITE)) && !move_promotion(m)) - return MOVE_NONE; + return false; // Proceed according to the square delta between the source and // destionation squares. @@ -541,14 +528,14 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { // Capture. The destination square must be occupied by an enemy // piece (en passant captures was handled earlier). if (pos.color_of_piece_on(to) != them) - return MOVE_NONE; + return false; break; case DELTA_N: case DELTA_S: // Pawn push. The destination square must be empty. if (!pos.square_is_empty(to)) - return MOVE_NONE; + return false; break; case DELTA_NN: @@ -558,7 +545,7 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { if ( square_rank(to) != RANK_4 || !pos.square_is_empty(to) || !pos.square_is_empty(from + DELTA_N)) - return MOVE_NONE; + return false; break; case DELTA_SS: @@ -568,222 +555,221 @@ Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned) { if ( square_rank(to) != RANK_5 || !pos.square_is_empty(to) || !pos.square_is_empty(from + DELTA_S)) - return MOVE_NONE; + return false; break; default: - return MOVE_NONE; + return false; } - // The move is pseudo-legal. Return it if it is legal. - return (pos.move_is_legal(m) ? m : MOVE_NONE); + // The move is pseudo-legal, check if it is also legal + return pos.pl_move_is_legal(m, pinned); } // Luckly we can handle all the other pieces in one go return ( pos.piece_attacks_square(from, to) - && pos.move_is_legal(m) - && !move_promotion(m) ? m : MOVE_NONE); + && pos.pl_move_is_legal(m, pinned) + && !move_promotion(m)); } namespace { template - int generate_piece_moves(const Position &pos, MoveStack *mlist, - Color side, Bitboard target) { - int n = 0; - for (int i = 0; i < pos.piece_count(side, Piece); i++) + MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { + + Square from; + Bitboard b; + + for (int i = 0, e = pos.piece_count(us, Piece); i < e; i++) { - Square from = pos.piece_list(side, Piece, i); - Bitboard b = pos.piece_attacks(from) & target; - while (b) - { - Square to = pop_1st_bit(&b); - mlist[n++].move = make_move(from, to); - } + from = pos.piece_list(us, Piece, i); + b = pos.piece_attacks(from) & target; + SERIALIZE_MOVES(b); } - return n; + return mlist; } + template<> + MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { + + Bitboard b; + Square from = pos.king_square(us); + + b = pos.piece_attacks(from) & target; + SERIALIZE_MOVES(b); + return mlist; + } template - int generate_piece_blocking_evasions(const Position& pos, Bitboard b, - Bitboard blockSquares, MoveStack* mlist, int n) { + MoveStack* generate_piece_blocking_evasions(const Position& pos, Bitboard b, + Bitboard blockSquares, MoveStack* mlist) { while (b) { Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & blockSquares; - while (bb) - { - Square to = pop_1st_bit(&bb); - mlist[n++].move = make_move(from, to); - } + SERIALIZE_MOVES(bb); } - return n; + return mlist; } - template - int generate_pawn_captures(const Position& pos, MoveStack* mlist) { + template + MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist) { - static const PawnParams PP = (C == WHITE ? WhitePawnParams : BlackPawnParams); - - Bitboard pawns = pos.pawns(PP.us); - Bitboard enemyPieces = pos.pieces_of_color(PP.them); - Square sq; - int n = 0; + Square to; + Bitboard pawns = pos.pawns(Us); + Bitboard enemyPieces = pos.pieces_of_color(Them); // Captures in the a1-h8 (a8-h1 for black) direction - Bitboard b1 = (C == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces; + Bitboard b1 = (Us == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces; // Capturing promotions - Bitboard b2 = b1 & PP.Rank8BB; + Bitboard b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NE, sq, QUEEN); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, QUEEN); } // Capturing non-promotions - b2 = b1 & ~PP.Rank8BB; + b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_move(sq - PP.DELTA_NE, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_NE, to); } // Captures in the h1-a8 (h8-a1 for black) direction - b1 = (C == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces; + b1 = (Us == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces; // Capturing promotions - b2 = b1 & PP.Rank8BB; + b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NW, sq, QUEEN); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, QUEEN); } // Capturing non-promotions - b2 = b1 & ~PP.Rank8BB; + b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_move(sq - PP.DELTA_NW, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_NW, to); } // Non-capturing promotions - b1 = (C == WHITE ? pawns << 8 : pawns >> 8) & pos.empty_squares() & Rank8BB; + b1 = (Us == WHITE ? pawns << 8 : pawns >> 8) & pos.empty_squares() & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_N, sq, QUEEN); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN); } // En passant captures if (pos.ep_square() != SQ_NONE) { - assert(PP.us != WHITE || square_rank(pos.ep_square()) == RANK_6); - assert(PP.us != BLACK || square_rank(pos.ep_square()) == RANK_3); + assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6); + assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3); - b1 = pawns & pos.pawn_attacks(PP.them, pos.ep_square()); + b1 = pawns & pos.pawn_attacks(Them, pos.ep_square()); assert(b1 != EmptyBoardBB); while (b1) { - sq = pop_1st_bit(&b1); - mlist[n++].move = make_ep_move(sq, pos.ep_square()); + to = pop_1st_bit(&b1); + (*mlist++).move = make_ep_move(to, pos.ep_square()); } } - return n; + return mlist; } + template + MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) { - template - int generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) { - - static const PawnParams PP = (C == WHITE ? WhitePawnParams : BlackPawnParams); - - Bitboard pawns = pos.pawns(PP.us); - Bitboard enemyPieces = pos.pieces_of_color(PP.them); + Bitboard pawns = pos.pawns(Us); + Bitboard enemyPieces = pos.pieces_of_color(Them); Bitboard emptySquares = pos.empty_squares(); Bitboard b1, b2; - Square sq; - int n = 0; + Square to; // Underpromotion captures in the a1-h8 (a8-h1 for black) direction - b1 = (C == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces & PP.Rank8BB; + b1 = (Us == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NE, sq, ROOK); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NE, sq, BISHOP); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NE, sq, KNIGHT); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, KNIGHT); } // Underpromotion captures in the h1-a8 (h8-a1 for black) direction - b1 = (C == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces & PP.Rank8BB; + b1 = (Us == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NW, sq, ROOK); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NW, sq, BISHOP); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_NW, sq, KNIGHT); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, KNIGHT); } // Single pawn pushes - b1 = (C == WHITE ? pawns << 8 : pawns >> 8) & emptySquares; - b2 = b1 & PP.Rank8BB; + b1 = (Us == WHITE ? pawns << 8 : pawns >> 8) & emptySquares; + b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_N, sq, ROOK); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_N, sq, BISHOP); - mlist[n++].move = make_promotion_move(sq - PP.DELTA_N, sq, KNIGHT); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT); } - b2 = b1 & ~PP.Rank8BB; + b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_move(sq - PP.DELTA_N, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_N, to); } // Double pawn pushes - b2 = (C == WHITE ? (b1 & PP.Rank3BB) << 8 : (b1 & PP.Rank3BB) >> 8) & emptySquares; + b2 = (Us == WHITE ? (b1 & TRank3BB) << 8 : (b1 & TRank3BB) >> 8) & emptySquares; while (b2) { - sq = pop_1st_bit(&b2); - mlist[n++].move = make_move(sq - PP.DELTA_N - PP.DELTA_N, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to); } - return n; + return mlist; } - template - int generate_pawn_checks(const Position& pos, Bitboard dc, Square ksq, MoveStack* mlist, int n) + template + MoveStack* do_generate_pawn_checks(const Position& pos, Bitboard dc, Square ksq, MoveStack* mlist) { - static const PawnParams PP = (C == WHITE ? WhitePawnParams : BlackPawnParams); - - // Pawn moves which give discovered check. This is possible only if the - // pawn is not on the same file as the enemy king, because we don't + // Pawn moves which give discovered check. This is possible only if the + // pawn is not on the same file as the enemy king, because we don't // generate captures. Bitboard empty = pos.empty_squares(); // Find all friendly pawns not on the enemy king's file - Bitboard b1 = pos.pawns(pos.side_to_move()) & ~file_bb(ksq), b2, b3; + Bitboard b1 = pos.pawns(Us) & ~file_bb(ksq), b2, b3; // Discovered checks, single pawn pushes - b2 = b3 = (C == WHITE ? (b1 & dc) << 8 : (b1 & dc) >> 8) & ~PP.Rank8BB & empty; + b2 = b3 = (Us == WHITE ? (b1 & dc) << 8 : (b1 & dc) >> 8) & ~TRank8BB & empty; while (b3) { Square to = pop_1st_bit(&b3); - mlist[n++].move = make_move(to - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N, to); } // Discovered checks, double pawn pushes - b3 = (C == WHITE ? (b2 & PP.Rank3BB) << 8 : (b2 & PP.Rank3BB) >> 8) & empty; + b3 = (Us == WHITE ? (b2 & TRank3BB) << 8 : (b2 & TRank3BB) >> 8) & empty; while (b3) { Square to = pop_1st_bit(&b3); - mlist[n++].move = make_move(to - PP.DELTA_N - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to); } // Direct checks. These are possible only for pawns on neighboring files @@ -792,81 +778,115 @@ namespace { b1 &= (~dc & neighboring_files_bb(ksq)); // FIXME why ~dc ?? // Direct checks, single pawn pushes - b2 = (C == WHITE ? b1 << 8 : b1 >> 8) & empty; - b3 = b2 & pos.pawn_attacks(PP.them, ksq); + b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & empty; + b3 = b2 & pos.pawn_attacks(Them, ksq); while (b3) { Square to = pop_1st_bit(&b3); - mlist[n++].move = make_move(to - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N, to); } // Direct checks, double pawn pushes - b3 = (C == WHITE ? (b2 & PP.Rank3BB) << 8 : (b2 & PP.Rank3BB) >> 8) + b3 = (Us == WHITE ? (b2 & TRank3BB) << 8 : (b2 & TRank3BB) >> 8) & empty - & pos.pawn_attacks(PP.them, ksq); + & pos.pawn_attacks(Them, ksq); while (b3) { Square to = pop_1st_bit(&b3); - mlist[n++].move = make_move(to - PP.DELTA_N - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to); + } + return mlist; + } + + template + MoveStack* generate_piece_checks(const Position& pos, Bitboard target, Bitboard dc, + Square ksq, MoveStack* mlist) { + // Discovered checks + Bitboard b = target & dc; + while (b) + { + Square from = pop_1st_bit(&b); + Bitboard bb = pos.piece_attacks(from) & pos.empty_squares(); + SERIALIZE_MOVES(bb); + } + // Direct checks + b = target & ~dc; + Bitboard checkSqs = pos.piece_attacks(ksq) & pos.empty_squares(); + while (b) + { + Square from = pop_1st_bit(&b); + Bitboard bb = pos.piece_attacks(from) & checkSqs; + SERIALIZE_MOVES(bb); } - return n; + return mlist; } + MoveStack* generate_piece_checks_king(const Position& pos, Square from, Bitboard dc, + Square ksq, MoveStack* mlist) { + if (bit_is_set(dc, from)) + { + Bitboard b = pos.piece_attacks(from) + & pos.empty_squares() + & ~QueenPseudoAttacks[ksq]; + SERIALIZE_MOVES(b); + } + return mlist; + } - template - int generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned, - Bitboard blockSquares, MoveStack* mlist, int n) { - static const PawnParams PP = (C == WHITE ? WhitePawnParams : BlackPawnParams); + template + MoveStack* do_generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned, + Bitboard blockSquares, MoveStack* mlist) { + Square to; // Find non-pinned pawns - Bitboard b1 = pos.pawns(PP.us) & not_pinned; + Bitboard b1 = pos.pawns(Us) & not_pinned; // Single pawn pushes. We don't have to AND with empty squares here, // because the blocking squares will always be empty. - Bitboard b2 = (C == WHITE ? b1 << 8 : b1 >> 8) & blockSquares; + Bitboard b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & blockSquares; while (b2) { - Square to = pop_1st_bit(&b2); + to = pop_1st_bit(&b2); assert(pos.piece_on(to) == EMPTY); - if (square_rank(to) == PP.RANK_8) + if (square_rank(to) == TRANK_8) { - mlist[n++].move = make_promotion_move(to - PP.DELTA_N, to, QUEEN); - mlist[n++].move = make_promotion_move(to - PP.DELTA_N, to, ROOK); - mlist[n++].move = make_promotion_move(to - PP.DELTA_N, to, BISHOP); - mlist[n++].move = make_promotion_move(to - PP.DELTA_N, to, KNIGHT); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT); } else - mlist[n++].move = make_move(to - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N, to); } // Double pawn pushes - b2 = (C == WHITE ? b1 << 8 : b1 >> 8) & pos.empty_squares() & PP.Rank3BB; - b2 = (C == WHITE ? b2 << 8 : b2 >> 8) & blockSquares;; + b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & pos.empty_squares() & TRank3BB; + b2 = (Us == WHITE ? b2 << 8 : b2 >> 8) & blockSquares;; while (b2) { - Square to = pop_1st_bit(&b2); + to = pop_1st_bit(&b2); assert(pos.piece_on(to) == EMPTY); - assert(PP.us != WHITE || square_rank(to) == RANK_4); - assert(PP.us != BLACK || square_rank(to) == RANK_5); + assert(Us != WHITE || square_rank(to) == RANK_4); + assert(Us != BLACK || square_rank(to) == RANK_5); - mlist[n++].move = make_move(to - PP.DELTA_N - PP.DELTA_N, to); + (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to); } - return n; + return mlist; } - int generate_castle_moves(const Position &pos, MoveStack *mlist, Color us) { + MoveStack* generate_castle_moves(const Position& pos, MoveStack* mlist) { - int n = 0; + Color us = pos.side_to_move(); if (pos.can_castle(us)) { Color them = opposite_color(us); - Square ksq = pos.king_square(us); + Square ksq = pos.king_square(us); assert(pos.piece_on(ksq) == king_of_color(us)); @@ -890,7 +910,7 @@ namespace { illegal = true; if (!illegal) - mlist[n++].move = make_castle_move(ksq, rsq); + (*mlist++).move = make_castle_move(ksq, rsq); } if (pos.can_castle_queenside(us)) @@ -899,7 +919,7 @@ namespace { Square c1 = relative_square(us, SQ_C1); Square d1 = relative_square(us, SQ_D1); Square s; - bool illegal = false; + bool illegal = false; assert(pos.piece_on(rsq) == rook_of_color(us)); @@ -916,11 +936,12 @@ namespace { && ( pos.piece_on(relative_square(us, SQ_A1)) == rook_of_color(them) || pos.piece_on(relative_square(us, SQ_A1)) == queen_of_color(them))) illegal = true; - + if (!illegal) - mlist[n++].move = make_castle_move(ksq, rsq); + (*mlist++).move = make_castle_move(ksq, rsq); } } - return n; + return mlist; } + } diff --git a/src/movegen.h b/src/movegen.h index 94f778ff..034dd389 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -7,12 +7,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -37,6 +37,7 @@ extern int generate_noncaptures(const Position &pos, MoveStack *mlist); extern int generate_checks(const Position &pos, MoveStack *mlist, Bitboard dc); extern int generate_evasions(const Position &pos, MoveStack *mlist); extern int generate_legal_moves(const Position &pos, MoveStack *mlist); -extern Move generate_move_if_legal(const Position &pos, Move m, Bitboard pinned); +extern bool move_is_legal(const Position &pos, const Move m, Bitboard pinned); + #endif // !defined(MOVEGEN_H_INCLUDED) diff --git a/src/movepick.cpp b/src/movepick.cpp index e1f8e4e7..187a3c51 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -7,12 +7,13 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -39,7 +40,7 @@ namespace { /// Variables - MovePicker::MovegenPhase PhaseTable[32]; + MovePicker::MovegenPhase PhaseTable[32]; int MainSearchPhaseIndex; int EvasionsPhaseIndex; int QsearchWithChecksPhaseIndex; @@ -62,7 +63,7 @@ namespace { /// move ordering is at the current node. MovePicker::MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, - Move k1, Move k2, Depth d) : pos(p) { + Move k1, Move k2, Depth d) : pos(p) { pvNode = pvnode; ttMove = ttm; mateKiller = (mk == ttm)? MOVE_NONE : mk; @@ -116,7 +117,7 @@ Move MovePicker::get_next_move() { if (ttMove != MOVE_NONE) { assert(move_is_ok(ttMove)); - if (generate_move_if_legal(pos, ttMove, pinned) != MOVE_NONE) + if (move_is_legal(pos, ttMove, pinned)) return ttMove; } break; @@ -125,12 +126,12 @@ Move MovePicker::get_next_move() { if (mateKiller != MOVE_NONE) { assert(move_is_ok(mateKiller)); - if (generate_move_if_legal(pos, mateKiller, pinned) != MOVE_NONE) + if (move_is_legal(pos, mateKiller, pinned)) return mateKiller; - } - break; + } + break; - case PH_GOOD_CAPTURES: + case PH_GOOD_CAPTURES: numOfMoves = generate_captures(pos, moves); score_captures(); movesPicked = 0; @@ -147,13 +148,13 @@ Move MovePicker::get_next_move() { break; case PH_EVASIONS: - assert(pos.is_check()); + assert(pos.is_check()); numOfMoves = generate_evasions(pos, moves); score_evasions(); movesPicked = 0; break; - case PH_QCAPTURES: + case PH_QCAPTURES: numOfMoves = generate_captures(pos, moves); score_qcaptures(); movesPicked = 0; @@ -172,9 +173,6 @@ Move MovePicker::get_next_move() { return MOVE_NONE; } } - assert(false); - - return MOVE_NONE; } @@ -183,62 +181,78 @@ Move MovePicker::get_next_move() { Move MovePicker::get_next_move(Lock &lock) { - lock_grab(&lock); - if (finished) - { - lock_release(&lock); - return MOVE_NONE; - } - Move m = get_next_move(); - if (m == MOVE_NONE) - finished = true; - - lock_release(&lock); - return m; + lock_grab(&lock); + if (finished) + { + lock_release(&lock); + return MOVE_NONE; + } + Move m = get_next_move(); + if (m == MOVE_NONE) + finished = true; + + lock_release(&lock); + return m; } + /// MovePicker::score_captures(), MovePicker::score_noncaptures(), /// MovePicker::score_evasions() and MovePicker::score_qcaptures() assign a /// numerical move ordering score to each move in a move list. The moves /// with highest scores will be picked first by pick_move_from_list(). void MovePicker::score_captures() { - // Winning and equal captures in the main search are ordered by MVV. + // Winning and equal captures in the main search are ordered by MVV/LVA. // Suprisingly, this appears to perform slightly better than SEE based // move ordering. The reason is probably that in a position with a winning // capture, capturing a more valuable (but sufficiently defended) piece // first usually doesn't hurt. The opponent will have to recapture, and // the hanging piece will still be hanging (except in the unusual cases - // where it is possible to recapture with the hanging piece). Exchanging + // where it is possible to recapture with the hanging piece). Exchanging // big pieces before capturing a hanging piece probably helps to reduce // the subtree size. + Move m; + int seeValue; + for (int i = 0; i < numOfMoves; i++) { - Move m = moves[i].move; - moves[i].score = pos.see(m); - if (moves[i].score >= 0) - moves[i].score = move_promotion(m) ? QueenValueMidgame - : pos.midgame_value_of_piece_on(move_to(m)); + m = moves[i].move; + seeValue = pos.see(m); + if (seeValue >= 0) + { + if (move_promotion(m)) + moves[i].score = QueenValueMidgame; + else + moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) + -int(pos.type_of_piece_on(move_from(m))); + } else + moves[i].score = seeValue; } } void MovePicker::score_noncaptures() { + // First score by history, when no history is available then use + // piece/square tables values. This seems to be better then a + // random choice when we don't have an history for any move. + Move m; + int hs; for (int i = 0; i < numOfMoves; i++) { - Move m = moves[i].move; + m = moves[i].move; + if (m == killer1) - moves[i].score = HistoryMax + 2; + hs = HistoryMax + 2; else if (m == killer2) - moves[i].score = HistoryMax + 1; + hs = HistoryMax + 1; else - moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m); + hs = H.move_ordering_score(pos.piece_on(move_from(m)), m); // Ensure moves in history are always sorted as first - if (moves[i].score > 0) - moves[i].score += 1000; + if (hs > 0) + hs += 1000; - moves[i].score += pos.mg_pst_delta(moves[i].move); + moves[i].score = hs + pos.mg_pst_delta(m); } } @@ -251,11 +265,9 @@ void MovePicker::score_evasions() { moves[i].score = 2*HistoryMax; else if (!pos.square_is_empty(move_to(m))) { - moves[i].score = pos.see(m); - if (moves[i].score >= 0) - moves[i].score += HistoryMax; - } - else + int seeScore = pos.see(m); + moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore; + } else moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m); } // FIXME try psqt also here @@ -263,12 +275,15 @@ void MovePicker::score_evasions() { void MovePicker::score_qcaptures() { - // Use MVV ordering + // Use MVV/LVA ordering for (int i = 0; i < numOfMoves; i++) { Move m = moves[i].move; - moves[i].score = move_promotion(m) ? QueenValueMidgame - : pos.midgame_value_of_piece_on(move_to(m)); + if (move_promotion(m)) + moves[i].score = QueenValueMidgame; + else + moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) + -int(pos.type_of_piece_on(move_from(m))); } } @@ -304,10 +319,10 @@ Move MovePicker::pick_move_from_list() { Move move; switch (PhaseTable[phaseIndex]) { - case PH_GOOD_CAPTURES: assert(!pos.is_check()); assert(movesPicked >= 0); + while (movesPicked < numOfMoves) { int bestScore = -10000000; @@ -320,20 +335,20 @@ Move MovePicker::pick_move_from_list() { assert(numOfBadCaptures < 63); badCaptures[numOfBadCaptures++] = moves[i]; moves[i--] = moves[--numOfMoves]; - } - else if (moves[i].score > bestScore) - { - bestIndex = i; - bestScore = moves[i].score; - } + } + else if (moves[i].score > bestScore) + { + bestIndex = i; + bestScore = moves[i].score; + } } if (bestIndex != -1) // Found a good capture { - move = moves[bestIndex].move; + move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; if ( move != ttMove && move != mateKiller - && pos.move_is_legal(move, pinned)) + && pos.pl_move_is_legal(move, pinned)) return move; } } @@ -342,41 +357,43 @@ Move MovePicker::pick_move_from_list() { case PH_NONCAPTURES: assert(!pos.is_check()); assert(movesPicked >= 0); + while (movesPicked < numOfMoves) { // If this is a PV node or we have only picked a few moves, scan // the entire move list for the best move. If many moves have already // been searched and it is not a PV node, we are probably failing low // anyway, so we just pick the first move from the list. - bestIndex = (movesPicked < 12 || pvNode ? find_best_index() : movesPicked); + bestIndex = (pvNode || movesPicked < 12) ? find_best_index() : movesPicked; if (bestIndex != -1) { - move = moves[bestIndex].move; + move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; if ( move != ttMove && move != mateKiller - && pos.move_is_legal(move, pinned)) + && pos.pl_move_is_legal(move, pinned)) return move; - } - } - break; + } + } + break; case PH_EVASIONS: assert(pos.is_check()); assert(movesPicked >= 0); + while (movesPicked < numOfMoves) { bestIndex = find_best_index(); if (bestIndex != -1) { - move = moves[bestIndex].move; + move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; return move; } - } - break; + } + break; case PH_BAD_CAPTURES: assert(!pos.is_check()); @@ -388,7 +405,7 @@ Move MovePicker::pick_move_from_list() { move = badCaptures[badCapturesPicked++].move; if ( move != ttMove && move != mateKiller - && pos.move_is_legal(move, pinned)) + && pos.pl_move_is_legal(move, pinned)) return move; } break; @@ -398,14 +415,15 @@ Move MovePicker::pick_move_from_list() { assert(movesPicked >= 0); while (movesPicked < numOfMoves) { - // FIXME makes sens to score qcaps? bestIndex = (movesPicked < 4 ? find_best_index() : movesPicked); if (bestIndex != -1) { - move = moves[bestIndex].move; + move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; - if (move != ttMove && pos.move_is_legal(move, pinned)) + // Remember to change the line below if we decide to hash the qsearch! + // Maybe also postpone the legality check until after futility pruning? + if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned)) return move; } } @@ -418,8 +436,9 @@ Move MovePicker::pick_move_from_list() { // move here? FIXME while (movesPicked < numOfMoves) { - move = moves[movesPicked++].move; - if (move != ttMove && pos.move_is_legal(move, pinned)) + move = moves[movesPicked++].move; + // Remember to change the line below if we decide to hash the qsearch! + if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned)) return move; } break; @@ -442,7 +461,7 @@ MovePicker::MovegenPhase MovePicker::current_move_type() const { /// MovePicker::init_phase_table() initializes the PhaseTable[], /// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex -/// and QsearchWithoutChecksPhaseIndex variables. It is only called once +/// and QsearchWithoutChecksPhaseIndex variables. It is only called once /// during program startup, and never again while the program is running. void MovePicker::init_phase_table() { diff --git a/src/movepick.h b/src/movepick.h index a835346d..66518ac7 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -7,12 +7,16 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +<<<<<<< HEAD:src/movepick.h + +======= +>>>>>>> d3600c39a745179ed6b094b305d0645e83a1ee86:src/movepick.h Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -77,7 +81,7 @@ private: void score_qcaptures(); Move pick_move_from_list(); int find_best_index(); - + const Position& pos; Move ttMove, mateKiller, killer1, killer2; Bitboard pinned, dc; @@ -101,6 +105,7 @@ private: /// a single reply to check. inline int MovePicker::number_of_moves() const { + return numOfMoves; } diff --git a/src/position.cpp b/src/position.cpp index ff93e532..5e092483 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -235,7 +235,7 @@ const std::string Position::to_fen() const { fen += (char)skip + '0'; skip = 0; } - fen += pieceLetters[piece_on(sq)]; + fen += pieceLetters[piece_on(sq)]; } if (skip > 0) fen += (char)skip + '0'; @@ -292,77 +292,70 @@ void Position::print() const { /// Position::copy() creates a copy of the input position. void Position::copy(const Position &pos) { + memcpy(this, &pos, sizeof(Position)); } /// Position:pinned_pieces() returns a bitboard of all pinned (against the /// king) pieces for the given color. - Bitboard Position::pinned_pieces(Color c) const { - Bitboard b1, b2, pinned, pinners, sliders; - Square ksq = king_square(c), s; - Color them = opposite_color(c); - - pinned = EmptyBoardBB; - b1 = occupied_squares(); - - sliders = rooks_and_queens(them) & ~checkers(); - if(sliders & RookPseudoAttacks[ksq]) { - b2 = piece_attacks(ksq) & pieces_of_color(c); - pinners = rook_attacks_bb(ksq, b1 ^ b2) & sliders; - while(pinners) { - s = pop_1st_bit(&pinners); - pinned |= (squares_between(s, ksq) & b2); - } - } - - sliders = bishops_and_queens(them) & ~checkers(); - if(sliders & BishopPseudoAttacks[ksq]) { - b2 = piece_attacks(ksq) & pieces_of_color(c); - pinners = bishop_attacks_bb(ksq, b1 ^ b2) & sliders; - while(pinners) { - s = pop_1st_bit(&pinners); - pinned |= (squares_between(s, ksq) & b2); - } - } - return pinned; + Square ksq = king_square(c); + return hidden_checks(c, ksq) | hidden_checks(c, ksq); } + /// Position:discovered_check_candidates() returns a bitboard containing all /// pieces for the given side which are candidates for giving a discovered /// check. The code is almost the same as the function for finding pinned /// pieces. Bitboard Position::discovered_check_candidates(Color c) const { - Bitboard b1, b2, dc, checkers, sliders; - Square ksq = king_square(opposite_color(c)), s; - - dc = EmptyBoardBB; - b1 = occupied_squares(); - - sliders = rooks_and_queens(c); - if(sliders & RookPseudoAttacks[ksq]) { - b2 = piece_attacks(ksq) & pieces_of_color(c); - checkers = rook_attacks_bb(ksq, b1 ^ b2) & sliders; - while(checkers) { - s = pop_1st_bit(&checkers); - dc |= (squares_between(s, ksq) & b2); - } - } - sliders = bishops_and_queens(c); - if(sliders & BishopPseudoAttacks[ksq]) { - b2 = piece_attacks(ksq) & pieces_of_color(c); - checkers = bishop_attacks_bb(ksq, b1 ^ b2) & sliders; - while(checkers) { - s = pop_1st_bit(&checkers); - dc |= (squares_between(s, ksq) & b2); - } - } + Square ksq = king_square(opposite_color(c)); + return hidden_checks(c, ksq) | hidden_checks(c, ksq); +} + + +/// Position:hidden_checks<>() returns a bitboard of all pinned (against the +/// king) pieces for the given color and for the given pinner type. Or, when +/// template parameter FindPinned is false, the pinned pieces of opposite color +/// that are, indeed, the pieces candidate for a discovery check. +template +Bitboard Position::hidden_checks(Color c, Square ksq) const { + + Square s; + Bitboard sliders, result = EmptyBoardBB; + + if (Piece == ROOK) // Resolved at compile time + sliders = rooks_and_queens(FindPinned ? opposite_color(c) : c) & RookPseudoAttacks[ksq]; + else + sliders = bishops_and_queens(FindPinned ? opposite_color(c) : c) & BishopPseudoAttacks[ksq]; + + if (sliders && (!FindPinned || (sliders & ~checkersBB))) + { + // King blockers are candidate pinned pieces + Bitboard candidate_pinned = piece_attacks(ksq) & pieces_of_color(c); + + // Pinners are sliders, not checkers, that give check when + // candidate pinned are removed. + Bitboard pinners = (FindPinned ? sliders & ~checkersBB : sliders); + + if (Piece == ROOK) + pinners &= rook_attacks_bb(ksq, occupied_squares() ^ candidate_pinned); + else + pinners &= bishop_attacks_bb(ksq, occupied_squares() ^ candidate_pinned); - return dc; + // Finally for each pinner find the corresponding pinned piece (if same color of king) + // or discovery checker (if opposite color) among the candidates. + while (pinners) + { + s = pop_1st_bit(&pinners); + result |= (squares_between(s, ksq) & candidate_pinned); + } + } + return result; } @@ -370,12 +363,12 @@ Bitboard Position::discovered_check_candidates(Color c) const { /// given square. bool Position::square_is_attacked(Square s, Color c) const { - return - (pawn_attacks(opposite_color(c), s) & pawns(c)) || - (piece_attacks(s) & knights(c)) || - (piece_attacks(s) & kings(c)) || - (piece_attacks(s) & rooks_and_queens(c)) || - (piece_attacks(s) & bishops_and_queens(c)); + + return (pawn_attacks(opposite_color(c), s) & pawns(c)) + || (piece_attacks(s) & knights(c)) + || (piece_attacks(s) & kings(c)) + || (piece_attacks(s) & rooks_and_queens(c)) + || (piece_attacks(s) & bishops_and_queens(c)); } @@ -385,16 +378,17 @@ bool Position::square_is_attacked(Square s, Color c) const { /// attackers for one side. Bitboard Position::attacks_to(Square s) const { - return - (pawn_attacks(BLACK, s) & pawns(WHITE)) | - (pawn_attacks(WHITE, s) & pawns(BLACK)) | - (piece_attacks(s) & pieces_of_type(KNIGHT)) | - (piece_attacks(s) & rooks_and_queens()) | - (piece_attacks(s) & bishops_and_queens()) | - (piece_attacks(s) & pieces_of_type(KING)); + + return (pawn_attacks(BLACK, s) & pawns(WHITE)) + | (pawn_attacks(WHITE, s) & pawns(BLACK)) + | (piece_attacks(s) & pieces_of_type(KNIGHT)) + | (piece_attacks(s) & rooks_and_queens()) + | (piece_attacks(s) & bishops_and_queens()) + | (piece_attacks(s) & pieces_of_type(KING)); } Bitboard Position::attacks_to(Square s, Color c) const { + return attacks_to(s) & pieces_of_color(c); } @@ -403,20 +397,48 @@ Bitboard Position::attacks_to(Square s, Color c) const { /// attacks square t. bool Position::piece_attacks_square(Square f, Square t) const { + assert(square_is_ok(f)); assert(square_is_ok(t)); - switch(piece_on(f)) { - case WP: return pawn_attacks_square(WHITE, f, t); - case BP: return pawn_attacks_square(BLACK, f, t); + switch (piece_on(f)) + { + case WP: return pawn_attacks_square(WHITE, f, t); + case BP: return pawn_attacks_square(BLACK, f, t); case WN: case BN: return piece_attacks_square(f, t); case WB: case BB: return piece_attacks_square(f, t); case WR: case BR: return piece_attacks_square(f, t); case WQ: case BQ: return piece_attacks_square(f, t); case WK: case BK: return piece_attacks_square(f, t); - default: return false; } + return false; +} + + +/// Position::move_attacks_square() tests whether a move from the current +/// position attacks a given square. Only attacks by the moving piece are +/// considered; the function does not handle X-ray attacks. + +bool Position::move_attacks_square(Move m, Square s) const { + + assert(move_is_ok(m)); + assert(square_is_ok(s)); + + Square f = move_from(m), t = move_to(m); + assert(square_is_occupied(f)); + + switch (piece_on(f)) + { + case WP: return pawn_attacks_square(WHITE, t, s); + case BP: return pawn_attacks_square(BLACK, t, s); + case WN: case BN: return piece_attacks_square(t, s); + case WB: case BB: return piece_attacks_square(t, s); + case WR: case BR: return piece_attacks_square(t, s); + case WQ: case BQ: return piece_attacks_square(t, s); + case WK: case BK: return piece_attacks_square(t, s); + default: assert(false); + } return false; } @@ -428,23 +450,24 @@ bool Position::piece_attacks_square(Square f, Square t) const { /// played, like in non-bitboard versions of Glaurung. void Position::find_checkers() { - checkersBB = attacks_to(king_square(side_to_move()), - opposite_color(side_to_move())); + + checkersBB = attacks_to(king_square(side_to_move()),opposite_color(side_to_move())); } -/// Position::move_is_legal() tests whether a pseudo-legal move is legal. +/// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal. /// There are two versions of this function: One which takes only a /// move as input, and one which takes a move and a bitboard of pinned -/// pieces. The latter function is faster, and should always be preferred +/// pieces. The latter function is faster, and should always be preferred /// when a pinned piece bitboard has already been computed. -bool Position::move_is_legal(Move m) const { - return move_is_legal(m, pinned_pieces(side_to_move())); +bool Position::pl_move_is_legal(Move m) const { + + return pl_move_is_legal(m, pinned_pieces(side_to_move())); } +bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { -bool Position::move_is_legal(Move m, Bitboard pinned) const { Color us, them; Square ksq, from; @@ -454,14 +477,15 @@ bool Position::move_is_legal(Move m, Bitboard pinned) const { // If we're in check, all pseudo-legal moves are legal, because our // check evasion generator only generates true legal moves. - if(is_check()) return true; + if (is_check()) + return true; // Castling moves are checked for legality during move generation. - if(move_is_castle(m)) return true; + if (move_is_castle(m)) + return true; us = side_to_move(); them = opposite_color(us); - from = move_from(m); ksq = king_square(us); @@ -470,33 +494,36 @@ bool Position::move_is_legal(Move m, Bitboard pinned) const { // En passant captures are a tricky special case. Because they are // rather uncommon, we do it simply by testing whether the king is attacked - // after the move is made: - if(move_is_ep(m)) { - Square to = move_to(m); - Square capsq = make_square(square_file(to), square_rank(from)); - Bitboard b = occupied_squares(); - - assert(to == ep_square()); - assert(piece_on(from) == pawn_of_color(us)); - assert(piece_on(capsq) == pawn_of_color(them)); - assert(piece_on(to) == EMPTY); - - clear_bit(&b, from); clear_bit(&b, capsq); set_bit(&b, to); - return - (!(rook_attacks_bb(ksq, b) & rooks_and_queens(them)) && - !(bishop_attacks_bb(ksq, b) & bishops_and_queens(them))); + // after the move is made + if (move_is_ep(m)) + { + Square to = move_to(m); + Square capsq = make_square(square_file(to), square_rank(from)); + Bitboard b = occupied_squares(); + + assert(to == ep_square()); + assert(piece_on(from) == pawn_of_color(us)); + assert(piece_on(capsq) == pawn_of_color(them)); + assert(piece_on(to) == EMPTY); + + clear_bit(&b, from); + clear_bit(&b, capsq); + set_bit(&b, to); + + return !(rook_attacks_bb(ksq, b) & rooks_and_queens(them)) + && !(bishop_attacks_bb(ksq, b) & bishops_and_queens(them)); } // If the moving piece is a king, check whether the destination // square is attacked by the opponent. - if(from == ksq) return !(square_is_attacked(move_to(m), them)); + if (from == ksq) + return !(square_is_attacked(move_to(m), them)); // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. - if(!bit_is_set(pinned, from)) return true; - if(direction_between_squares(from, ksq) == - direction_between_squares(move_to(m), ksq)) - return true; + if ( !bit_is_set(pinned, from) + || (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq))) + return true; return false; } @@ -509,138 +536,126 @@ bool Position::move_is_legal(Move m, Bitboard pinned) const { /// when a discovered check candidates bitboard has already been computed. bool Position::move_is_check(Move m) const { + Bitboard dc = discovered_check_candidates(side_to_move()); return move_is_check(m, dc); } - bool Position::move_is_check(Move m, Bitboard dcCandidates) const { + Color us, them; Square ksq, from, to; assert(is_ok()); assert(move_is_ok(m)); - assert(dcCandidates == - discovered_check_candidates(side_to_move())); + assert(dcCandidates == discovered_check_candidates(side_to_move())); us = side_to_move(); them = opposite_color(us); - from = move_from(m); to = move_to(m); ksq = king_square(them); + assert(color_of_piece_on(from) == us); assert(piece_on(ksq) == king_of_color(them)); - // Proceed according to the type of the moving piece: - switch(type_of_piece_on(from)) { + // Proceed according to the type of the moving piece + switch (type_of_piece_on(from)) + { case PAWN: - // Normal check? - if(bit_is_set(pawn_attacks(them, ksq), to)) - return true; - // Discovered check? - else if(bit_is_set(dcCandidates, from) && - direction_between_squares(from, ksq) != - direction_between_squares(to, ksq)) - return true; - // Promotion with check? - else if(move_promotion(m)) { - Bitboard b = occupied_squares(); - clear_bit(&b, from); - switch(move_promotion(m)) { - case KNIGHT: - return piece_attacks_square(to, ksq); - case BISHOP: - return bit_is_set(bishop_attacks_bb(to, b), ksq); - case ROOK: - return bit_is_set(rook_attacks_bb(to, b), ksq); - case QUEEN: - return bit_is_set(queen_attacks_bb(to, b), ksq); - default: - assert(false); - } - } - // En passant capture with check? We have already handled the case - // of direct checks and ordinary discovered check, the only case we - // need to handle is the unusual case of a discovered check through the - // captured pawn. - else if(move_is_ep(m)) { - Square capsq = make_square(square_file(to), square_rank(from)); - Bitboard b = occupied_squares(); + if (bit_is_set(pawn_attacks(them, ksq), to)) // Normal check? + return true; - clear_bit(&b, from); clear_bit(&b, capsq); set_bit(&b, to); - return - ((rook_attacks_bb(ksq, b) & rooks_and_queens(us)) || - (bishop_attacks_bb(ksq, b) & bishops_and_queens(us))); - } - return false; + if ( bit_is_set(dcCandidates, from) // Discovered check? + && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq))) + return true; + + if (move_promotion(m)) // Promotion with check? + { + Bitboard b = occupied_squares(); + clear_bit(&b, from); + + switch (move_promotion(m)) + { + case KNIGHT: + return bit_is_set(piece_attacks(to), ksq); + case BISHOP: + return bit_is_set(bishop_attacks_bb(to, b), ksq); + case ROOK: + return bit_is_set(rook_attacks_bb(to, b), ksq); + case QUEEN: + return bit_is_set(queen_attacks_bb(to, b), ksq); + default: + assert(false); + } + } + // En passant capture with check? We have already handled the case + // of direct checks and ordinary discovered check, the only case we + // need to handle is the unusual case of a discovered check through the + // captured pawn. + else if (move_is_ep(m)) + { + Square capsq = make_square(square_file(to), square_rank(from)); + Bitboard b = occupied_squares(); + clear_bit(&b, from); + clear_bit(&b, capsq); + set_bit(&b, to); + return (rook_attacks_bb(ksq, b) & rooks_and_queens(us)) + ||(bishop_attacks_bb(ksq, b) & bishops_and_queens(us)); + } + return false; case KNIGHT: - // Discovered check? - if(bit_is_set(dcCandidates, from)) - return true; - // Normal check? - else - return bit_is_set(piece_attacks(ksq), to); + return bit_is_set(dcCandidates, from) // Discovered check? + || bit_is_set(piece_attacks(ksq), to); // Normal check? case BISHOP: - // Discovered check? - if(bit_is_set(dcCandidates, from)) - return true; - // Normal check? - else - return bit_is_set(piece_attacks(ksq), to); + return bit_is_set(dcCandidates, from) // Discovered check? + || bit_is_set(piece_attacks(ksq), to); // Normal check? case ROOK: - // Discovered check? - if(bit_is_set(dcCandidates, from)) - return true; - // Normal check? - else - return bit_is_set(piece_attacks(ksq), to); + return bit_is_set(dcCandidates, from) // Discovered check? + || bit_is_set(piece_attacks(ksq), to); // Normal check? case QUEEN: - // Discovered checks are impossible! - assert(!bit_is_set(dcCandidates, from)); - // Normal check? - return bit_is_set(piece_attacks(ksq), to); + // Discovered checks are impossible! + assert(!bit_is_set(dcCandidates, from)); + return bit_is_set(piece_attacks(ksq), to); // Normal check? case KING: - // Discovered check? - if(bit_is_set(dcCandidates, from) && - direction_between_squares(from, ksq) != - direction_between_squares(to, ksq)) - return true; - // Castling with check? - if(move_is_castle(m)) { - Square kfrom, kto, rfrom, rto; - Bitboard b = occupied_squares(); + // Discovered check? + if ( bit_is_set(dcCandidates, from) + && (direction_between_squares(from, ksq) != direction_between_squares(to, ksq))) + return true; - kfrom = from; - rfrom = to; - if(rfrom > kfrom) { - kto = relative_square(us, SQ_G1); - rto = relative_square(us, SQ_F1); - } - else { - kto = relative_square(us, SQ_C1); - rto = relative_square(us, SQ_D1); - } - - clear_bit(&b, kfrom); clear_bit(&b, rfrom); - set_bit(&b, rto); set_bit(&b, kto); - - return bit_is_set(rook_attacks_bb(rto, b), ksq); - } + // Castling with check? + if (move_is_castle(m)) + { + Square kfrom, kto, rfrom, rto; + Bitboard b = occupied_squares(); + kfrom = from; + rfrom = to; - return false; + if (rfrom > kfrom) + { + kto = relative_square(us, SQ_G1); + rto = relative_square(us, SQ_F1); + } else { + kto = relative_square(us, SQ_C1); + rto = relative_square(us, SQ_D1); + } + clear_bit(&b, kfrom); + clear_bit(&b, rfrom); + set_bit(&b, rto); + set_bit(&b, kto); + return bit_is_set(rook_attacks_bb(rto, b), ksq); + } + return false; default: - assert(false); - return false; + assert(false); } - assert(false); return false; } @@ -650,48 +665,21 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const { /// position is a capture. bool Position::move_is_capture(Move m) const { - return - color_of_piece_on(move_to(m)) == opposite_color(side_to_move()) - || move_is_ep(m); -} - -/// Position::move_attacks_square() tests whether a move from the current -/// position attacks a given square. Only attacks by the moving piece are -/// considered; the function does not handle X-ray attacks. - -bool Position::move_attacks_square(Move m, Square s) const { - assert(move_is_ok(m)); - assert(square_is_ok(s)); - - Square f = move_from(m), t = move_to(m); - - assert(square_is_occupied(f)); - - switch(piece_on(f)) { - case WP: return pawn_attacks_square(WHITE, t, s); - case BP: return pawn_attacks_square(BLACK, t, s); - case WN: case BN: return piece_attacks_square(t, s); - case WB: case BB: return piece_attacks_square(t, s); - case WR: case BR: return piece_attacks_square(t, s); - case WQ: case BQ: return piece_attacks_square(t, s); - case WK: case BK: return piece_attacks_square(t, s); - default: assert(false); - } - - return false; + return color_of_piece_on(move_to(m)) == opposite_color(side_to_move()) + || move_is_ep(m); } - -/// Position::backup() is called when making a move. All information +/// Position::backup() is called when making a move. All information /// necessary to restore the position when the move is later unmade -/// is saved to an UndoInfo object. The function Position::restore +/// is saved to an UndoInfo object. The function Position::restore /// does the reverse operation: When one does a backup followed by /// a restore with the same UndoInfo object, the position is restored /// to the state before backup was called. -void Position::backup(UndoInfo &u) const { +void Position::backup(UndoInfo& u) const { + u.castleRights = castleRights; u.epSquare = epSquare; u.checkersBB = checkersBB; @@ -709,7 +697,8 @@ void Position::backup(UndoInfo &u) const { /// Position::restore() is called when unmaking a move. It copies back /// the information backed up during a previous call to Position::backup. -void Position::restore(const UndoInfo &u) { +void Position::restore(const UndoInfo& u) { + castleRights = u.castleRights; epSquare = u.epSquare; checkersBB = u.checkersBB; @@ -718,6 +707,7 @@ void Position::restore(const UndoInfo &u) { materialKey = u.materialKey; rule50 = u.rule50; lastMove = u.lastMove; + // u.capture is restored in undo_move() mgValue = u.mgValue; egValue = u.egValue; } @@ -732,91 +722,88 @@ void Position::restore(const UndoInfo &u) { /// the discovered check candidates makes it easier to update the checkersBB /// member variable in the position object. -void Position::do_move(Move m, UndoInfo &u) { +void Position::do_move(Move m, UndoInfo& u) { + do_move(m, u, discovered_check_candidates(side_to_move())); } -void Position::do_move(Move m, UndoInfo &u, Bitboard dcCandidates) { +void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { + assert(is_ok()); assert(move_is_ok(m)); // Back up the necessary information to our UndoInfo object (except the - // captured piece, which is taken care of later: + // captured piece, which is taken care of later. backup(u); // Save the current key to the history[] array, in order to be able to - // detect repetition draws: + // detect repetition draws. history[gamePly] = key; - // Increment the 50 moves rule draw counter. Resetting it to zero in the + // Increment the 50 moves rule draw counter. Resetting it to zero in the // case of non-reversible moves is taken care of later. rule50++; - if(move_is_castle(m)) - do_castle_move(m); - else if(move_promotion(m)) - do_promotion_move(m, u); - else if(move_is_ep(m)) - do_ep_move(m); - else { - Color us, them; - Square from, to; - PieceType piece, capture; - - us = side_to_move(); - them = opposite_color(us); - - from = move_from(m); - to = move_to(m); + if (move_is_castle(m)) + do_castle_move(m); + else if (move_promotion(m)) + do_promotion_move(m, u); + else if (move_is_ep(m)) + do_ep_move(m); + else + { + Color us = side_to_move(); + Color them = opposite_color(us); + Square from = move_from(m); + Square to = move_to(m); assert(color_of_piece_on(from) == us); assert(color_of_piece_on(to) == them || piece_on(to) == EMPTY); - piece = type_of_piece_on(from); - capture = type_of_piece_on(to); + PieceType piece = type_of_piece_on(from); + PieceType capture = type_of_piece_on(to); - if(capture) { - assert(capture != KING); + if (capture) + { + assert(capture != KING); - // Remove captured piece: - clear_bit(&(byColorBB[them]), to); - clear_bit(&(byTypeBB[capture]), to); + // Remove captured piece + clear_bit(&(byColorBB[them]), to); + clear_bit(&(byTypeBB[capture]), to); - // Update hash key: - key ^= zobrist[them][capture][to]; + // Update hash key + key ^= zobrist[them][capture][to]; - // If the captured piece was a pawn, update pawn hash key: - if(capture == PAWN) - pawnKey ^= zobrist[them][PAWN][to]; + // If the captured piece was a pawn, update pawn hash key + if (capture == PAWN) + pawnKey ^= zobrist[them][PAWN][to]; - // Update incremental scores: - mgValue -= mg_pst(them, capture, to); - egValue -= eg_pst(them, capture, to); + // Update incremental scores + mgValue -= mg_pst(them, capture, to); + egValue -= eg_pst(them, capture, to); - // Update material: - if(capture != PAWN) - npMaterial[them] -= piece_value_midgame(capture); + // Update material + if (capture != PAWN) + npMaterial[them] -= piece_value_midgame(capture); - // Update material hash key: - materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]]; + // Update material hash key + materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]]; - // Update piece count: - pieceCount[them][capture]--; + // Update piece count + pieceCount[them][capture]--; - // Update piece list: - pieceList[them][capture][index[to]] = - pieceList[them][capture][pieceCount[them][capture]]; - index[pieceList[them][capture][index[to]]] = index[to]; + // Update piece list + pieceList[them][capture][index[to]] = pieceList[them][capture][pieceCount[them][capture]]; + index[pieceList[them][capture][index[to]]] = index[to]; - // Remember the captured piece, in order to be able to undo the move - // correctly: - u.capture = capture; + // Remember the captured piece, in order to be able to undo the move correctly + u.capture = capture; - // Reset rule 50 counter: - rule50 = 0; + // Reset rule 50 counter + rule50 = 0; } - // Move the piece: + // Move the piece clear_bit(&(byColorBB[us]), from); clear_bit(&(byTypeBB[piece]), from); clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares @@ -826,103 +813,105 @@ void Position::do_move(Move m, UndoInfo &u, Bitboard dcCandidates) { board[to] = board[from]; board[from] = EMPTY; - // Update hash key: + // Update hash key key ^= zobrist[us][piece][from] ^ zobrist[us][piece][to]; - // Update incremental scores: + // Update incremental scores mgValue -= mg_pst(us, piece, from); mgValue += mg_pst(us, piece, to); egValue -= eg_pst(us, piece, from); egValue += eg_pst(us, piece, to); - // If the moving piece was a king, update the king square: - if(piece == KING) - kingSquare[us] = to; + // If the moving piece was a king, update the king square + if (piece == KING) + kingSquare[us] = to; // If the move was a double pawn push, set the en passant square. // This code is a bit ugly right now, and should be cleaned up later. // FIXME - if(epSquare != SQ_NONE) { - key ^= zobEp[epSquare]; - epSquare = SQ_NONE; + if (epSquare != SQ_NONE) + { + key ^= zobEp[epSquare]; + epSquare = SQ_NONE; } - if(piece == PAWN) { - if(abs(int(to) - int(from)) == 16) { - if((us == WHITE && (pawn_attacks(WHITE, from + DELTA_N) & - pawns(BLACK))) || - (us == BLACK && (pawn_attacks(BLACK, from + DELTA_S) & - pawns(WHITE)))) { - epSquare = Square((int(from) + int(to)) / 2); - key ^= zobEp[epSquare]; + if (piece == PAWN) + { + if (abs(int(to) - int(from)) == 16) + { + if( ( us == WHITE + && (pawn_attacks(WHITE, from + DELTA_N) & pawns(BLACK))) + || ( us == BLACK + && (pawn_attacks(BLACK, from + DELTA_S) & pawns(WHITE)))) + { + epSquare = Square((int(from) + int(to)) / 2); + key ^= zobEp[epSquare]; + } } - } - // Reset rule 50 draw counter. - rule50 = 0; - // Update pawn hash key: - pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; - } + // Reset rule 50 draw counter + rule50 = 0; - // Update piece lists: + // Update pawn hash key + pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; + } + // Update piece lists pieceList[us][piece][index[from]] = to; index[to] = index[from]; - // Update castle rights: + // Update castle rights key ^= zobCastle[castleRights]; castleRights &= castleRightsMask[from]; castleRights &= castleRightsMask[to]; key ^= zobCastle[castleRights]; - // Update checkers bitboard: + // Update checkers bitboard checkersBB = EmptyBoardBB; Square ksq = king_square(them); - - switch(piece) { - + switch (piece) + { case PAWN: - if(bit_is_set(pawn_attacks(them, ksq), to)) - set_bit(&checkersBB, to); - if(bit_is_set(dcCandidates, from)) - checkersBB |= - ((piece_attacks(ksq) & rooks_and_queens(us)) | - (piece_attacks(ksq) & bishops_and_queens(us))); - break; + if (bit_is_set(pawn_attacks(them, ksq), to)) + set_bit(&checkersBB, to); + + if (bit_is_set(dcCandidates, from)) + checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) + |(piece_attacks(ksq) & bishops_and_queens(us))); + break; case KNIGHT: - if(bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - if(bit_is_set(dcCandidates, from)) - checkersBB |= - ((piece_attacks(ksq) & rooks_and_queens(us)) | - (piece_attacks(ksq) & bishops_and_queens(us))); - break; + if (bit_is_set(piece_attacks(ksq), to)) + set_bit(&checkersBB, to); + + if (bit_is_set(dcCandidates, from)) + checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) + |(piece_attacks(ksq) & bishops_and_queens(us))); + break; case BISHOP: - if(bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - if(bit_is_set(dcCandidates, from)) - checkersBB |= - (piece_attacks(ksq) & rooks_and_queens(us)); - break; + if (bit_is_set(piece_attacks(ksq), to)) + set_bit(&checkersBB, to); + + if (bit_is_set(dcCandidates, from)) + checkersBB |= (piece_attacks(ksq) & rooks_and_queens(us)); + break; case ROOK: - if(bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - if(bit_is_set(dcCandidates, from)) - checkersBB |= - (piece_attacks(ksq) & bishops_and_queens(us)); - break; + if (bit_is_set(piece_attacks(ksq), to)) + set_bit(&checkersBB, to); + + if (bit_is_set(dcCandidates, from)) + checkersBB |= (piece_attacks(ksq) & bishops_and_queens(us)); + break; case QUEEN: - if(bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - break; + if (bit_is_set(piece_attacks(ksq), to)) + set_bit(&checkersBB, to); + break; case KING: - if(bit_is_set(dcCandidates, from)) - checkersBB |= - ((piece_attacks(ksq) & rooks_and_queens(us)) | - (piece_attacks(ksq) & bishops_and_queens(us))); - break; + if (bit_is_set(dcCandidates, from)) + checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) + |(piece_attacks(ksq) & bishops_and_queens(us))); + break; default: assert(false); @@ -948,34 +937,33 @@ void Position::do_move(Move m, UndoInfo &u, Bitboard dcCandidates) { /// instance white short castling in a non-Chess960 game is encoded as e1h1. void Position::do_castle_move(Move m) { - Color us, them; - Square kfrom, kto, rfrom, rto; assert(is_ok()); assert(move_is_ok(m)); assert(move_is_castle(m)); - us = side_to_move(); - them = opposite_color(us); + Color us = side_to_move(); + Color them = opposite_color(us); - // Find source squares for king and rook: - kfrom = move_from(m); - rfrom = move_to(m); // HACK: See comment at beginning of function. + // Find source squares for king and rook + Square kfrom = move_from(m); + Square rfrom = move_to(m); // HACK: See comment at beginning of function + Square kto, rto; assert(piece_on(kfrom) == king_of_color(us)); assert(piece_on(rfrom) == rook_of_color(us)); - // Find destination squares for king and rook: - if(rfrom > kfrom) { // O-O - kto = relative_square(us, SQ_G1); - rto = relative_square(us, SQ_F1); - } - else { // O-O-O - kto = relative_square(us, SQ_C1); - rto = relative_square(us, SQ_D1); + // Find destination squares for king and rook + if (rfrom > kfrom) // O-O + { + kto = relative_square(us, SQ_G1); + rto = relative_square(us, SQ_F1); + } else { // O-O-O + kto = relative_square(us, SQ_C1); + rto = relative_square(us, SQ_D1); } - // Remove pieces from source squares: + // Remove pieces from source squares clear_bit(&(byColorBB[us]), kfrom); clear_bit(&(byTypeBB[KING]), kfrom); clear_bit(&(byTypeBB[0]), kfrom); // HACK: byTypeBB[0] == occupied squares @@ -983,7 +971,7 @@ void Position::do_castle_move(Move m) { clear_bit(&(byTypeBB[ROOK]), rfrom); clear_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied squares - // Put pieces on destination squares: + // Put pieces on destination squares set_bit(&(byColorBB[us]), kto); set_bit(&(byTypeBB[KING]), kto); set_bit(&(byTypeBB[0]), kto); // HACK: byTypeBB[0] == occupied squares @@ -991,22 +979,22 @@ void Position::do_castle_move(Move m) { set_bit(&(byTypeBB[ROOK]), rto); set_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares - // Update board array: + // Update board array board[kfrom] = board[rfrom] = EMPTY; board[kto] = king_of_color(us); board[rto] = rook_of_color(us); - // Update king square: + // Update king square kingSquare[us] = kto; - // Update piece lists: + // Update piece lists pieceList[us][KING][index[kfrom]] = kto; pieceList[us][ROOK][index[rfrom]] = rto; int tmp = index[rfrom]; index[kto] = index[kfrom]; index[rto] = tmp; - // Update incremental scores: + // Update incremental scores mgValue -= mg_pst(us, KING, kfrom); mgValue += mg_pst(us, KING, kto); egValue -= eg_pst(us, KING, kfrom); @@ -1016,35 +1004,37 @@ void Position::do_castle_move(Move m) { egValue -= eg_pst(us, ROOK, rfrom); egValue += eg_pst(us, ROOK, rto); - // Update hash key: + // Update hash key key ^= zobrist[us][KING][kfrom] ^ zobrist[us][KING][kto]; key ^= zobrist[us][ROOK][rfrom] ^ zobrist[us][ROOK][rto]; - // Clear en passant square: - if(epSquare != SQ_NONE) { - key ^= zobEp[epSquare]; - epSquare = SQ_NONE; + // Clear en passant square + if(epSquare != SQ_NONE) + { + key ^= zobEp[epSquare]; + epSquare = SQ_NONE; } - // Update castling rights: + // Update castling rights key ^= zobCastle[castleRights]; castleRights &= castleRightsMask[kfrom]; key ^= zobCastle[castleRights]; - // Reset rule 50 counter: + // Reset rule 50 counter rule50 = 0; - // Update checkers BB: + // Update checkers BB checkersBB = attacks_to(king_square(them), us); } /// Position::do_promotion_move() is a private method used to make a promotion -/// move. It is called from the main Position::do_move function. The +/// move. It is called from the main Position::do_move function. The /// UndoInfo object, which has been initialized in Position::do_move, is /// used to store the captured piece (if any). void Position::do_promotion_move(Move m, UndoInfo &u) { + Color us, them; Square from, to; PieceType capture, promotion; @@ -1055,7 +1045,6 @@ void Position::do_promotion_move(Move m, UndoInfo &u) { us = side_to_move(); them = opposite_color(us); - from = move_from(m); to = move_to(m); @@ -1065,48 +1054,47 @@ void Position::do_promotion_move(Move m, UndoInfo &u) { capture = type_of_piece_on(to); - if(capture) { + if (capture) + { assert(capture != KING); - // Remove captured piece: + // Remove captured piece clear_bit(&(byColorBB[them]), to); clear_bit(&(byTypeBB[capture]), to); - // Update hash key: + // Update hash key key ^= zobrist[them][capture][to]; - // Update incremental scores: + // Update incremental scores mgValue -= mg_pst(them, capture, to); egValue -= eg_pst(them, capture, to); - // Update material. Because our move is a promotion, we know that the + // Update material. Because our move is a promotion, we know that the // captured piece is not a pawn. assert(capture != PAWN); npMaterial[them] -= piece_value_midgame(capture); - // Update material hash key: + // Update material hash key materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]]; - // Update piece count: + // Update piece count pieceCount[them][capture]--; - // Update piece list: - pieceList[them][capture][index[to]] = - pieceList[them][capture][pieceCount[them][capture]]; + // Update piece list + pieceList[them][capture][index[to]] = pieceList[them][capture][pieceCount[them][capture]]; index[pieceList[them][capture][index[to]]] = index[to]; - // Remember the captured piece, in order to be able to undo the move - // correctly: + // Remember the captured piece, in order to be able to undo the move correctly u.capture = capture; } - // Remove pawn: + // Remove pawn clear_bit(&(byColorBB[us]), from); clear_bit(&(byTypeBB[PAWN]), from); clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares board[from] = EMPTY; - // Insert promoted piece: + // Insert promoted piece promotion = move_promotion(m); assert(promotion >= KNIGHT && promotion <= QUEEN); set_bit(&(byColorBB[us]), to); @@ -1114,61 +1102,62 @@ void Position::do_promotion_move(Move m, UndoInfo &u) { set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares board[to] = piece_of_color_and_type(us, promotion); - // Update hash key: + // Update hash key key ^= zobrist[us][PAWN][from] ^ zobrist[us][promotion][to]; - // Update pawn hash key: + // Update pawn hash key pawnKey ^= zobrist[us][PAWN][from]; - // Update material key: + // Update material key materialKey ^= zobMaterial[us][PAWN][pieceCount[us][PAWN]]; materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]+1]; - // Update piece counts: + // Update piece counts pieceCount[us][PAWN]--; pieceCount[us][promotion]++; - // Update piece lists: - pieceList[us][PAWN][index[from]] = - pieceList[us][PAWN][pieceCount[us][PAWN]]; + // Update piece lists + pieceList[us][PAWN][index[from]] = pieceList[us][PAWN][pieceCount[us][PAWN]]; index[pieceList[us][PAWN][index[from]]] = index[from]; pieceList[us][promotion][pieceCount[us][promotion] - 1] = to; index[to] = pieceCount[us][promotion] - 1; - // Update incremental scores: + // Update incremental scores mgValue -= mg_pst(us, PAWN, from); mgValue += mg_pst(us, promotion, to); egValue -= eg_pst(us, PAWN, from); egValue += eg_pst(us, promotion, to); - // Update material: + // Update material npMaterial[us] += piece_value_midgame(promotion); - // Clear the en passant square: - if(epSquare != SQ_NONE) { - key ^= zobEp[epSquare]; - epSquare = SQ_NONE; + // Clear the en passant square + if (epSquare != SQ_NONE) + { + key ^= zobEp[epSquare]; + epSquare = SQ_NONE; } - // Update castle rights: + // Update castle rights key ^= zobCastle[castleRights]; castleRights &= castleRightsMask[to]; key ^= zobCastle[castleRights]; - // Reset rule 50 counter: + // Reset rule 50 counter rule50 = 0; - // Update checkers BB: + // Update checkers BB checkersBB = attacks_to(king_square(them), us); } /// Position::do_ep_move() is a private method used to make an en passant -/// capture. It is called from the main Position::do_move function. Because +/// capture. It is called from the main Position::do_move function. Because /// the captured piece is always a pawn, we don't need to pass an UndoInfo /// object in which to store the captured piece. void Position::do_ep_move(Move m) { + Color us, them; Square from, to, capsq; @@ -1178,8 +1167,6 @@ void Position::do_ep_move(Move m) { us = side_to_move(); them = opposite_color(us); - - // Find from, to and capture squares: from = move_from(m); to = move_to(m); capsq = (us == WHITE)? (to - DELTA_N) : (to - DELTA_S); @@ -1190,47 +1177,46 @@ void Position::do_ep_move(Move m) { assert(piece_on(from) == pawn_of_color(us)); assert(piece_on(capsq) == pawn_of_color(them)); - // Remove captured piece: + // Remove captured piece clear_bit(&(byColorBB[them]), capsq); clear_bit(&(byTypeBB[PAWN]), capsq); clear_bit(&(byTypeBB[0]), capsq); // HACK: byTypeBB[0] == occupied squares board[capsq] = EMPTY; - // Remove moving piece from source square: + // Remove moving piece from source square clear_bit(&(byColorBB[us]), from); clear_bit(&(byTypeBB[PAWN]), from); clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares - // Put moving piece on destination square: + // Put moving piece on destination square set_bit(&(byColorBB[us]), to); set_bit(&(byTypeBB[PAWN]), to); set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares board[to] = board[from]; board[from] = EMPTY; - // Update material hash key: + // Update material hash key materialKey ^= zobMaterial[them][PAWN][pieceCount[them][PAWN]]; - // Update piece count: + // Update piece count pieceCount[them][PAWN]--; - // Update piece list: + // Update piece list pieceList[us][PAWN][index[from]] = to; index[to] = index[from]; - pieceList[them][PAWN][index[capsq]] = - pieceList[them][PAWN][pieceCount[them][PAWN]]; + pieceList[them][PAWN][index[capsq]] = pieceList[them][PAWN][pieceCount[them][PAWN]]; index[pieceList[them][PAWN][index[capsq]]] = index[capsq]; - // Update hash key: + // Update hash key key ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; key ^= zobrist[them][PAWN][capsq]; key ^= zobEp[epSquare]; - // Update pawn hash key: + // Update pawn hash key pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; pawnKey ^= zobrist[them][PAWN][capsq]; - // Update incremental scores: + // Update incremental scores mgValue -= mg_pst(them, PAWN, capsq); mgValue -= mg_pst(us, PAWN, from); mgValue += mg_pst(us, PAWN, to); @@ -1238,13 +1224,13 @@ void Position::do_ep_move(Move m) { egValue -= eg_pst(us, PAWN, from); egValue += eg_pst(us, PAWN, to); - // Reset en passant square: + // Reset en passant square epSquare = SQ_NONE; - // Reset rule 50 counter: + // Reset rule 50 counter rule50 = 0; - // Update checkers BB: + // Update checkers BB checkersBB = attacks_to(king_square(them), us); } @@ -1255,6 +1241,7 @@ void Position::do_ep_move(Move m) { /// object as the earlier call to Position::do_move. void Position::undo_move(Move m, const UndoInfo &u) { + assert(is_ok()); assert(move_is_ok(m)); @@ -1262,72 +1249,73 @@ void Position::undo_move(Move m, const UndoInfo &u) { sideToMove = opposite_color(sideToMove); // Restore information from our UndoInfo object (except the captured piece, - // which is taken care of later): + // which is taken care of later) restore(u); - if(move_is_castle(m)) - undo_castle_move(m); - else if(move_promotion(m)) - undo_promotion_move(m, u); - else if(move_is_ep(m)) - undo_ep_move(m); - else { - Color us, them; - Square from, to; - PieceType piece, capture; - - us = side_to_move(); - them = opposite_color(us); - - from = move_from(m); - to = move_to(m); - - assert(piece_on(from) == EMPTY); - assert(color_of_piece_on(to) == us); - - // Put the piece back at the source square: - piece = type_of_piece_on(to); - set_bit(&(byColorBB[us]), from); - set_bit(&(byTypeBB[piece]), from); - set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares - board[from] = piece_of_color_and_type(us, piece); - - // Clear the destination square - clear_bit(&(byColorBB[us]), to); - clear_bit(&(byTypeBB[piece]), to); - clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares - - // If the moving piece was a king, update the king square: - if(piece == KING) - kingSquare[us] = from; - - // Update piece list: - pieceList[us][piece][index[to]] = from; - index[from] = index[to]; - - capture = u.capture; - - if(capture) { - assert(capture != KING); - // Replace the captured piece: - set_bit(&(byColorBB[them]), to); - set_bit(&(byTypeBB[capture]), to); - set_bit(&(byTypeBB[0]), to); - board[to] = piece_of_color_and_type(them, capture); + if (move_is_castle(m)) + undo_castle_move(m); + else if (move_promotion(m)) + undo_promotion_move(m, u); + else if (move_is_ep(m)) + undo_ep_move(m); + else + { + Color us, them; + Square from, to; + PieceType piece, capture; - // Update material: - if(capture != PAWN) - npMaterial[them] += piece_value_midgame(capture); + us = side_to_move(); + them = opposite_color(us); + from = move_from(m); + to = move_to(m); - // Update piece list: - pieceList[them][capture][pieceCount[them][capture]] = to; - index[to] = pieceCount[them][capture]; + assert(piece_on(from) == EMPTY); + assert(color_of_piece_on(to) == us); - // Update piece count: - pieceCount[them][capture]++; - } - else - board[to] = EMPTY; + // Put the piece back at the source square + piece = type_of_piece_on(to); + set_bit(&(byColorBB[us]), from); + set_bit(&(byTypeBB[piece]), from); + set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares + board[from] = piece_of_color_and_type(us, piece); + + // Clear the destination square + clear_bit(&(byColorBB[us]), to); + clear_bit(&(byTypeBB[piece]), to); + clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares + + // If the moving piece was a king, update the king square + if (piece == KING) + kingSquare[us] = from; + + // Update piece list + pieceList[us][piece][index[to]] = from; + index[from] = index[to]; + + capture = u.capture; + + if (capture) + { + assert(capture != KING); + + // Replace the captured piece + set_bit(&(byColorBB[them]), to); + set_bit(&(byTypeBB[capture]), to); + set_bit(&(byTypeBB[0]), to); + board[to] = piece_of_color_and_type(them, capture); + + // Update material + if (capture != PAWN) + npMaterial[them] += piece_value_midgame(capture); + + // Update piece list + pieceList[them][capture][pieceCount[them][capture]] = to; + index[to] = pieceCount[them][capture]; + + // Update piece count + pieceCount[them][capture]++; + } else + board[to] = EMPTY; } assert(is_ok()); @@ -1335,13 +1323,11 @@ void Position::undo_move(Move m, const UndoInfo &u) { /// Position::undo_castle_move() is a private method used to unmake a castling -/// move. It is called from the main Position::undo_move function. Note that +/// move. It is called from the main Position::undo_move function. Note that /// castling moves are encoded as "king captures friendly rook" moves, for /// instance white short castling in a non-Chess960 game is encoded as e1h1. void Position::undo_castle_move(Move m) { - Color us, them; - Square kfrom, kto, rfrom, rto; assert(move_is_ok(m)); assert(move_is_castle(m)); @@ -1349,27 +1335,27 @@ void Position::undo_castle_move(Move m) { // When we have arrived here, some work has already been done by // Position::undo_move. In particular, the side to move has been switched, // so the code below is correct. - us = side_to_move(); - them = opposite_color(us); + Color us = side_to_move(); - // Find source squares for king and rook: - kfrom = move_from(m); - rfrom = move_to(m); // HACK: See comment at beginning of function. + // Find source squares for king and rook + Square kfrom = move_from(m); + Square rfrom = move_to(m); // HACK: See comment at beginning of function + Square kto, rto; - // Find destination squares for king and rook: - if(rfrom > kfrom) { // O-O - kto = relative_square(us, SQ_G1); - rto = relative_square(us, SQ_F1); - } - else { // O-O-O - kto = relative_square(us, SQ_C1); - rto = relative_square(us, SQ_D1); + // Find destination squares for king and rook + if (rfrom > kfrom) // O-O + { + kto = relative_square(us, SQ_G1); + rto = relative_square(us, SQ_F1); + } else { // O-O-O + kto = relative_square(us, SQ_C1); + rto = relative_square(us, SQ_D1); } assert(piece_on(kto) == king_of_color(us)); assert(piece_on(rto) == rook_of_color(us)); - // Remove pieces from destination squares: + // Remove pieces from destination squares clear_bit(&(byColorBB[us]), kto); clear_bit(&(byTypeBB[KING]), kto); clear_bit(&(byTypeBB[0]), kto); // HACK: byTypeBB[0] == occupied squares @@ -1377,7 +1363,7 @@ void Position::undo_castle_move(Move m) { clear_bit(&(byTypeBB[ROOK]), rto); clear_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares - // Put pieces on source squares: + // Put pieces on source squares set_bit(&(byColorBB[us]), kfrom); set_bit(&(byTypeBB[KING]), kfrom); set_bit(&(byTypeBB[0]), kfrom); // HACK: byTypeBB[0] == occupied squares @@ -1385,15 +1371,15 @@ void Position::undo_castle_move(Move m) { set_bit(&(byTypeBB[ROOK]), rfrom); set_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied squares - // Update board: + // Update board board[rto] = board[kto] = EMPTY; board[rfrom] = rook_of_color(us); board[kfrom] = king_of_color(us); - // Update king square: + // Update king square kingSquare[us] = kfrom; - // Update piece lists: + // Update piece lists pieceList[us][KING][index[kto]] = kfrom; pieceList[us][ROOK][index[rto]] = rfrom; int tmp = index[rto]; // Necessary because we may have rto == kfrom in FRC. @@ -1403,11 +1389,12 @@ void Position::undo_castle_move(Move m) { /// Position::undo_promotion_move() is a private method used to unmake a -/// promotion move. It is called from the main Position::do_move -/// function. The UndoInfo object, which has been initialized in +/// promotion move. It is called from the main Position::do_move +/// function. The UndoInfo object, which has been initialized in /// Position::do_move, is used to put back the captured piece (if any). void Position::undo_promotion_move(Move m, const UndoInfo &u) { + Color us, them; Square from, to; PieceType capture, promotion; @@ -1420,14 +1407,13 @@ void Position::undo_promotion_move(Move m, const UndoInfo &u) { // so the code below is correct. us = side_to_move(); them = opposite_color(us); - from = move_from(m); to = move_to(m); assert(relative_rank(us, to) == RANK_8); assert(piece_on(from) == EMPTY); - // Remove promoted piece: + // Remove promoted piece promotion = move_promotion(m); assert(piece_on(to)==piece_of_color_and_type(us, promotion)); assert(promotion >= KNIGHT && promotion <= QUEEN); @@ -1435,75 +1421,72 @@ void Position::undo_promotion_move(Move m, const UndoInfo &u) { clear_bit(&(byTypeBB[promotion]), to); clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares - // Insert pawn at source square: + // Insert pawn at source square set_bit(&(byColorBB[us]), from); set_bit(&(byTypeBB[PAWN]), from); set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares board[from] = pawn_of_color(us); - // Update material: + // Update material npMaterial[us] -= piece_value_midgame(promotion); - // Update piece list: + // Update piece list pieceList[us][PAWN][pieceCount[us][PAWN]] = from; index[from] = pieceCount[us][PAWN]; pieceList[us][promotion][index[to]] = pieceList[us][promotion][pieceCount[us][promotion] - 1]; index[pieceList[us][promotion][index[to]]] = index[to]; - // Update piece counts: + // Update piece counts pieceCount[us][promotion]--; pieceCount[us][PAWN]++; capture = u.capture; - if(capture) { - assert(capture != KING); - // Insert captured piece: - set_bit(&(byColorBB[them]), to); - set_bit(&(byTypeBB[capture]), to); - set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares - board[to] = piece_of_color_and_type(them, capture); + if (capture) + { + assert(capture != KING); - // Update material. Because the move is a promotion move, we know - // that the captured piece cannot be a pawn. - assert(capture != PAWN); - npMaterial[them] += piece_value_midgame(capture); + // Insert captured piece: + set_bit(&(byColorBB[them]), to); + set_bit(&(byTypeBB[capture]), to); + set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares + board[to] = piece_of_color_and_type(them, capture); - // Update piece list: - pieceList[them][capture][pieceCount[them][capture]] = to; - index[to] = pieceCount[them][capture]; + // Update material. Because the move is a promotion move, we know + // that the captured piece cannot be a pawn. + assert(capture != PAWN); + npMaterial[them] += piece_value_midgame(capture); - // Update piece count: - pieceCount[them][capture]++; - } - else - board[to] = EMPTY; + // Update piece list + pieceList[them][capture][pieceCount[them][capture]] = to; + index[to] = pieceCount[them][capture]; + + // Update piece count + pieceCount[them][capture]++; + } else + board[to] = EMPTY; } /// Position::undo_ep_move() is a private method used to unmake an en passant -/// capture. It is called from the main Position::undo_move function. Because +/// capture. It is called from the main Position::undo_move function. Because /// the captured piece is always a pawn, we don't need to pass an UndoInfo /// object from which to retrieve the captured piece. void Position::undo_ep_move(Move m) { - Color us, them; - Square from, to, capsq; assert(move_is_ok(m)); assert(move_is_ep(m)); // When we have arrived here, some work has already been done by - // Position::undo_move. In particular, the side to move has been switched, + // Position::undo_move. In particular, the side to move has been switched, // so the code below is correct. - us = side_to_move(); - them = opposite_color(us); - - // Find from, to and captures squares: - from = move_from(m); - to = move_to(m); - capsq = (us == WHITE)? (to - DELTA_N) : (to - DELTA_S); + Color us = side_to_move(); + Color them = opposite_color(us); + Square from = move_from(m); + Square to = move_to(m); + Square capsq = (us == WHITE)? (to - DELTA_N) : (to - DELTA_S); assert(to == ep_square()); assert(relative_rank(us, to) == RANK_6); @@ -1511,19 +1494,19 @@ void Position::undo_ep_move(Move m) { assert(piece_on(from) == EMPTY); assert(piece_on(capsq) == EMPTY); - // Replace captured piece: + // Replace captured piece set_bit(&(byColorBB[them]), capsq); set_bit(&(byTypeBB[PAWN]), capsq); set_bit(&(byTypeBB[0]), capsq); board[capsq] = pawn_of_color(them); - // Remove moving piece from destination square: + // Remove moving piece from destination square clear_bit(&(byColorBB[us]), to); clear_bit(&(byTypeBB[PAWN]), to); clear_bit(&(byTypeBB[0]), to); board[to] = EMPTY; - // Replace moving piece at source square: + // Replace moving piece at source square set_bit(&(byColorBB[us]), from); set_bit(&(byTypeBB[PAWN]), from); set_bit(&(byTypeBB[0]), from); @@ -1544,6 +1527,7 @@ void Position::undo_ep_move(Move m) { /// and updates the hash key without executing any move on the board. void Position::do_null_move(UndoInfo &u) { + assert(is_ok()); assert(!is_check()); @@ -1554,13 +1538,14 @@ void Position::do_null_move(UndoInfo &u) { u.epSquare = epSquare; // Save the current key to the history[] array, in order to be able to - // detect repetition draws: + // detect repetition draws. history[gamePly] = key; - // Update the necessary information. + // Update the necessary information sideToMove = opposite_color(sideToMove); - if(epSquare != SQ_NONE) - key ^= zobEp[epSquare]; + if (epSquare != SQ_NONE) + key ^= zobEp[epSquare]; + epSquare = SQ_NONE; rule50++; gamePly++; @@ -1576,14 +1561,15 @@ void Position::do_null_move(UndoInfo &u) { /// Position::undo_null_move() unmakes a "null move". void Position::undo_null_move(const UndoInfo &u) { + assert(is_ok()); assert(!is_check()); // Restore information from the supplied UndoInfo object: lastMove = u.lastMove; epSquare = u.epSquare; - if(epSquare != SQ_NONE) - key ^= zobEp[epSquare]; + if (epSquare != SQ_NONE) + key ^= zobEp[epSquare]; // Update the necessary information. sideToMove = opposite_color(sideToMove); @@ -1604,48 +1590,54 @@ void Position::undo_null_move(const UndoInfo &u) { /// 'from' and a 'to' square. The function does not yet understand promotions /// or en passant captures. +int Position::see(Move m) const { + + assert(move_is_ok(m)); + return see(move_from(m), move_to(m)); +} + int Position::see(Square from, Square to) const { - // Approximate material values, with pawn = 1: + + // Approximate material values, with pawn = 1 static const int seeValues[18] = { 0, 1, 3, 3, 5, 10, 100, 0, 0, 1, 3, 3, 5, 10, 100, 0, 0, 0 }; - Color us, them; - Piece piece, capture; + Bitboard attackers, occ, b; assert(square_is_ok(from)); assert(square_is_ok(to)); - // Initialize colors: - us = color_of_piece_on(from); - them = opposite_color(us); + // Initialize colors + Color us = color_of_piece_on(from); + Color them = opposite_color(us); - // Initialize pieces: - piece = piece_on(from); - capture = piece_on(to); + // Initialize pieces + Piece piece = piece_on(from); + Piece capture = piece_on(to); // Find all attackers to the destination square, with the moving piece - // removed, but possibly an X-ray attacker added behind it: + // removed, but possibly an X-ray attacker added behind it. occ = occupied_squares(); clear_bit(&occ, from); - attackers = - (rook_attacks_bb(to, occ) & rooks_and_queens()) | - (bishop_attacks_bb(to, occ) & bishops_and_queens()) | - (piece_attacks(to) & knights()) | - (piece_attacks(to) & kings()) | - (pawn_attacks(WHITE, to) & pawns(BLACK)) | - (pawn_attacks(BLACK, to) & pawns(WHITE)); - attackers &= occ; - - // If the opponent has no attackers, we are finished: - if((attackers & pieces_of_color(them)) == EmptyBoardBB) - return seeValues[capture]; + attackers = (rook_attacks_bb(to, occ) & rooks_and_queens()) + | (bishop_attacks_bb(to, occ) & bishops_and_queens()) + | (piece_attacks(to) & knights()) + | (piece_attacks(to) & kings()) + | (pawn_attacks(WHITE, to) & pawns(BLACK)) + | (pawn_attacks(BLACK, to) & pawns(WHITE)); + + // If the opponent has no attackers, we are finished + if ((attackers & pieces_of_color(them)) == EmptyBoardBB) + return seeValues[capture]; + + attackers &= occ; // Remove the moving piece // The destination square is defended, which makes things rather more - // difficult to compute. We proceed by building up a "swap list" containing + // difficult to compute. We proceed by building up a "swap list" containing // the material gain or loss at each stop in a sequence of captures to the - // destianation square, where the sides alternately capture, and always - // capture with the least valuable piece. After each capture, we look for + // destination square, where the sides alternately capture, and always + // capture with the least valuable piece. After each capture, we look for // new X-ray attacks from behind the capturing piece. int lastCapturingPieceValue = seeValues[piece]; int swapList[32], n = 1; @@ -1655,50 +1647,46 @@ int Position::see(Square from, Square to) const { swapList[0] = seeValues[capture]; do { - // Locate the least valuable attacker for the side to move. The loop - // below looks like it is potentially infinite, but it isn't. We know - // that the side to move still has at least one attacker left. - for(pt = PAWN; !(attackers&pieces_of_color_and_type(c, pt)); pt++) - assert(pt < KING); - - // Remove the attacker we just found from the 'attackers' bitboard, - // and scan for new X-ray attacks behind the attacker: - b = attackers & pieces_of_color_and_type(c, pt); - occ ^= (b & -b); - attackers |= - (rook_attacks_bb(to, occ) & rooks_and_queens()) | - (bishop_attacks_bb(to, occ) & bishops_and_queens()); - attackers &= occ; - - // Add the new entry to the swap list: - assert(n < 32); - swapList[n] = -swapList[n - 1] + lastCapturingPieceValue; - n++; - - // Remember the value of the capturing piece, and change the side to move - // before beginning the next iteration: - lastCapturingPieceValue = seeValues[pt]; - c = opposite_color(c); - - // Stop after a king capture: - if(pt == KING && (attackers & pieces_of_color(c))) { + // Locate the least valuable attacker for the side to move. The loop + // below looks like it is potentially infinite, but it isn't. We know + // that the side to move still has at least one attacker left. + for (pt = PAWN; !(attackers & pieces_of_color_and_type(c, pt)); pt++) + assert(pt < KING); + + // Remove the attacker we just found from the 'attackers' bitboard, + // and scan for new X-ray attacks behind the attacker. + b = attackers & pieces_of_color_and_type(c, pt); + occ ^= (b & -b); + attackers |= (rook_attacks_bb(to, occ) & rooks_and_queens()) + | (bishop_attacks_bb(to, occ) & bishops_and_queens()); + + attackers &= occ; + + // Add the new entry to the swap list assert(n < 32); - swapList[n++] = 100; - break; - } - } while(attackers & pieces_of_color(c)); + swapList[n] = -swapList[n - 1] + lastCapturingPieceValue; + n++; - // Having built the swap list, we negamax through it to find the best - // achievable score from the point of view of the side to move: - while(--n) swapList[n-1] = Min(-swapList[n], swapList[n-1]); + // Remember the value of the capturing piece, and change the side to move + // before beginning the next iteration + lastCapturingPieceValue = seeValues[pt]; + c = opposite_color(c); - return swapList[0]; -} + // Stop after a king capture + if (pt == KING && (attackers & pieces_of_color(c))) + { + assert(n < 32); + swapList[n++] = 100; + break; + } + } while (attackers & pieces_of_color(c)); + // Having built the swap list, we negamax through it to find the best + // achievable score from the point of view of the side to move + while (--n) + swapList[n-1] = Min(-swapList[n], swapList[n-1]); -int Position::see(Move m) const { - assert(move_is_ok(m)); - return see(move_from(m), move_to(m)); + return swapList[0]; } @@ -1706,21 +1694,22 @@ int Position::see(Move m) const { /// empty board, white to move, and no castling rights. void Position::clear() { - int i, j; - for(i = 0; i < 64; i++) { - board[i] = EMPTY; - index[i] = 0; + for (int i = 0; i < 64; i++) + { + board[i] = EMPTY; + index[i] = 0; } - for(i = 0; i < 2; i++) - byColorBB[i] = EmptyBoardBB; + for (int i = 0; i < 2; i++) + byColorBB[i] = EmptyBoardBB; - for(i = 0; i < 7; i++) { - byTypeBB[i] = EmptyBoardBB; - pieceCount[0][i] = pieceCount[1][i] = 0; - for(j = 0; j < 8; j++) - pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE; + for (int i = 0; i < 7; i++) + { + byTypeBB[i] = EmptyBoardBB; + pieceCount[0][i] = pieceCount[1][i] = 0; + for (int j = 0; j < 8; j++) + pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE; } checkersBB = EmptyBoardBB; @@ -1745,6 +1734,7 @@ void Position::clear() { /// handles draws by the 50 move rule correctly. void Position::reset_game_ply() { + gamePly = 0; } @@ -1753,6 +1743,7 @@ void Position::reset_game_ply() { /// updating the board array, bitboards, and piece counts. void Position::put_piece(Piece p, Square s) { + Color c = color_of_piece(p); PieceType pt = type_of_piece(p); @@ -1766,8 +1757,8 @@ void Position::put_piece(Piece p, Square s) { pieceCount[c][pt]++; - if(pt == KING) - kingSquare[c] = s; + if (pt == KING) + kingSquare[c] = s; } @@ -1775,6 +1766,7 @@ void Position::put_piece(Piece p, Square s) { /// Used when setting castling rights during parsing of FEN strings. void Position::allow_oo(Color c) { + castleRights |= (1 + int(c)); } @@ -1783,27 +1775,30 @@ void Position::allow_oo(Color c) { /// Used when setting castling rights during parsing of FEN strings. void Position::allow_ooo(Color c) { + castleRights |= (4 + 4*int(c)); } -/// Position::compute_key() computes the hash key of the position. The hash +/// Position::compute_key() computes the hash key of the position. The hash /// key is usually updated incrementally as moves are made and unmade, the /// compute_key() function is only used when a new position is set up, and /// to verify the correctness of the hash key when running in debug mode. Key Position::compute_key() const { + Key result = Key(0ULL); - for(Square s = SQ_A1; s <= SQ_H8; s++) - if(square_is_occupied(s)) - result ^= - zobrist[color_of_piece_on(s)][type_of_piece_on(s)][s]; + for (Square s = SQ_A1; s <= SQ_H8; s++) + if (square_is_occupied(s)) + result ^= zobrist[color_of_piece_on(s)][type_of_piece_on(s)][s]; + + if (ep_square() != SQ_NONE) + result ^= zobEp[ep_square()]; - if(ep_square() != SQ_NONE) - result ^= zobEp[ep_square()]; result ^= zobCastle[castleRights]; - if(side_to_move() == BLACK) result ^= zobSideToMove; + if (side_to_move() == BLACK) + result ^= zobSideToMove; return result; } @@ -1816,16 +1811,19 @@ Key Position::compute_key() const { /// debug mode. Key Position::compute_pawn_key() const { + Key result = Key(0ULL); Bitboard b; Square s; - for(Color c = WHITE; c <= BLACK; c++) { - b = pawns(c); - while(b) { - s = pop_1st_bit(&b); - result ^= zobrist[c][PAWN][s]; - } + for (Color c = WHITE; c <= BLACK; c++) + { + b = pawns(c); + while(b) + { + s = pop_1st_bit(&b); + result ^= zobrist[c][PAWN][s]; + } } return result; } @@ -1838,13 +1836,15 @@ Key Position::compute_pawn_key() const { /// debug mode. Key Position::compute_material_key() const { + Key result = Key(0ULL); - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= QUEEN; pt++) { - int count = piece_count(c, pt); - for(int i = 0; i <= count; i++) - result ^= zobMaterial[c][pt][i]; - } + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= QUEEN; pt++) + { + int count = piece_count(c, pt); + for (int i = 0; i <= count; i++) + result ^= zobMaterial[c][pt][i]; + } return result; } @@ -1856,40 +1856,44 @@ Key Position::compute_material_key() const { /// and undo_move when the program is running in debug mode. Value Position::compute_mg_value() const { + Value result = Value(0); Bitboard b; Square s; - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= KING; pt++) { - b = pieces_of_color_and_type(c, pt); - while(b) { - s = pop_1st_bit(&b); - assert(piece_on(s) == piece_of_color_and_type(c, pt)); - result += mg_pst(c, pt, s); + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= KING; pt++) + { + b = pieces_of_color_and_type(c, pt); + while(b) + { + s = pop_1st_bit(&b); + assert(piece_on(s) == piece_of_color_and_type(c, pt)); + result += mg_pst(c, pt, s); + } } - } - result += (side_to_move() == WHITE)? - (TempoValueMidgame / 2) : -(TempoValueMidgame / 2); + result += (side_to_move() == WHITE)? TempoValueMidgame / 2 : -TempoValueMidgame / 2; return result; } Value Position::compute_eg_value() const { + Value result = Value(0); Bitboard b; Square s; - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= KING; pt++) { - b = pieces_of_color_and_type(c, pt); - while(b) { - s = pop_1st_bit(&b); - assert(piece_on(s) == piece_of_color_and_type(c, pt)); - result += eg_pst(c, pt, s); - } + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= KING; pt++) + { + b = pieces_of_color_and_type(c, pt); + while(b) + { + s = pop_1st_bit(&b); + assert(piece_on(s) == piece_of_color_and_type(c, pt)); + result += eg_pst(c, pt, s); + } } - result += (side_to_move() == WHITE)? - (TempoValueEndgame / 2) : -(TempoValueEndgame / 2); + result += (side_to_move() == WHITE)? TempoValueEndgame / 2 : -TempoValueEndgame / 2; return result; } @@ -1900,33 +1904,37 @@ Value Position::compute_eg_value() const { /// initializing a new Position object. Value Position::compute_non_pawn_material(Color c) const { + Value result = Value(0); Square s; - for(PieceType pt = KNIGHT; pt <= QUEEN; pt++) { - Bitboard b = pieces_of_color_and_type(c, pt); - while(b) { - s = pop_1st_bit(&b); - assert(piece_on(s) == piece_of_color_and_type(c, pt)); - result += piece_value_midgame(pt); - } + for (PieceType pt = KNIGHT; pt <= QUEEN; pt++) + { + Bitboard b = pieces_of_color_and_type(c, pt); + while(b) + { + s = pop_1st_bit(&b); + assert(piece_on(s) == piece_of_color_and_type(c, pt)); + result += piece_value_midgame(pt); + } } return result; } /// Position::is_mate() returns true or false depending on whether the -/// side to move is checkmated. Note that this function is currently very +/// side to move is checkmated. Note that this function is currently very /// slow, and shouldn't be used frequently inside the search. bool Position::is_mate() { - if(is_check()) { - MovePicker mp = MovePicker(*this, false, MOVE_NONE, MOVE_NONE, MOVE_NONE, - MOVE_NONE, Depth(0)); - return mp.get_next_move() == MOVE_NONE; + + if (is_check()) + { + MovePicker mp = MovePicker(*this, false, MOVE_NONE, MOVE_NONE, + MOVE_NONE, MOVE_NONE, Depth(0)); + return mp.get_next_move() == MOVE_NONE; } - else - return false; + return false; } @@ -1935,30 +1943,31 @@ bool Position::is_mate() { /// must be done by the search. bool Position::is_draw() const { + // Draw by material? - if(!pawns() && - non_pawn_material(WHITE) + non_pawn_material(BLACK) - <= BishopValueMidgame) - return true; + if ( !pawns() + && (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMidgame)) + return true; // Draw by the 50 moves rule? - if(rule50 > 100 || (rule50 == 100 && !is_check())) - return true; + if (rule50 > 100 || (rule50 == 100 && !is_check())) + return true; // Draw by repetition? - for(int i = 2; i < Min(gamePly, rule50); i += 2) - if(history[gamePly - i] == key) - return true; + for (int i = 2; i < Min(gamePly, rule50); i += 2) + if (history[gamePly - i] == key) + return true; return false; } /// Position::has_mate_threat() tests whether a given color has a mate in one -/// from the current position. This function is quite slow, but it doesn't +/// from the current position. This function is quite slow, but it doesn't /// matter, because it is currently only called from PV nodes, which are rare. bool Position::has_mate_threat(Color c) { + UndoInfo u1, u2; Color stm = side_to_move(); @@ -1968,11 +1977,12 @@ bool Position::has_mate_threat(Color c) { u1.lastMove = lastMove; u1.epSquare = epSquare; - if(is_check()) - return false; + if (is_check()) + return false; // If the input color is not equal to the side to move, do a null move - if(c != stm) do_null_move(u1); + if (c != stm) + do_null_move(u1); MoveStack mlist[120]; int count; @@ -1981,15 +1991,19 @@ bool Position::has_mate_threat(Color c) { // Generate legal moves count = generate_legal_moves(*this, mlist); - // Loop through the moves, and see if one of them is mate. - for(int i = 0; i < count; i++) { - do_move(mlist[i].move, u2); - if(is_mate()) result = true; - undo_move(mlist[i].move, u2); + // Loop through the moves, and see if one of them is mate + for (int i = 0; i < count; i++) + { + do_move(mlist[i].move, u2); + if (is_mate()) + result = true; + + undo_move(mlist[i].move, u2); } // Undo null move, if necessary - if(c != stm) undo_null_move(u1); + if (c != stm) + undo_null_move(u1); return result; } @@ -2000,26 +2014,26 @@ bool Position::has_mate_threat(Color c) { void Position::init_zobrist() { - for(int i = 0; i < 2; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 64; k++) - zobrist[i][j][k] = Key(genrand_int64()); + for (int i = 0; i < 2; i++) + for (int j = 0; j < 8; j++) + for (int k = 0; k < 64; k++) + zobrist[i][j][k] = Key(genrand_int64()); - for(int i = 0; i < 64; i++) - zobEp[i] = Key(genrand_int64()); + for (int i = 0; i < 64; i++) + zobEp[i] = Key(genrand_int64()); - for(int i = 0; i < 16; i++) - zobCastle[i] = genrand_int64(); + for (int i = 0; i < 16; i++) + zobCastle[i] = genrand_int64(); zobSideToMove = genrand_int64(); - for(int i = 0; i < 2; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 16; k++) - zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL); + for (int i = 0; i < 2; i++) + for (int j = 0; j < 8; j++) + for (int k = 0; k < 16; k++) + zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL); - for(int i = 0; i < 16; i++) - zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL); + for (int i = 0; i < 16; i++) + zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL); } @@ -2031,19 +2045,22 @@ void Position::init_zobrist() { /// and changing the sign of the corresponding white scores. void Position::init_piece_square_tables() { + int r = get_option_value_int("Randomness"), i; - for(Square s = SQ_A1; s <= SQ_H8; s++) { - for(Piece p = WP; p <= WK; p++) { - i = (r == 0)? 0 : (genrand_int32() % (r*2) - r); - MgPieceSquareTable[p][s] = Value(MgPST[p][s] + i); - EgPieceSquareTable[p][s] = Value(EgPST[p][s] + i); - } - } - for(Square s = SQ_A1; s <= SQ_H8; s++) - for(Piece p = BP; p <= BK; p++) { - MgPieceSquareTable[p][s] = -MgPieceSquareTable[p-8][flip_square(s)]; - EgPieceSquareTable[p][s] = -EgPieceSquareTable[p-8][flip_square(s)]; - } + for (Square s = SQ_A1; s <= SQ_H8; s++) + for (Piece p = WP; p <= WK; p++) + { + i = (r == 0)? 0 : (genrand_int32() % (r*2) - r); + MgPieceSquareTable[p][s] = Value(MgPST[p][s] + i); + EgPieceSquareTable[p][s] = Value(EgPST[p][s] + i); + } + + for (Square s = SQ_A1; s <= SQ_H8; s++) + for (Piece p = BP; p <= BK; p++) + { + MgPieceSquareTable[p][s] = -MgPieceSquareTable[p-8][flip_square(s)]; + EgPieceSquareTable[p][s] = -EgPieceSquareTable[p-8][flip_square(s)]; + } } @@ -2052,40 +2069,42 @@ void Position::init_piece_square_tables() { /// especially for finding evaluation symmetry bugs. void Position::flipped_copy(const Position &pos) { + assert(pos.is_ok()); clear(); // Board - for(Square s = SQ_A1; s <= SQ_H8; s++) - if(!pos.square_is_empty(s)) - put_piece(Piece(int(pos.piece_on(s)) ^ 8), flip_square(s)); + for (Square s = SQ_A1; s <= SQ_H8; s++) + if (!pos.square_is_empty(s)) + put_piece(Piece(int(pos.piece_on(s)) ^ 8), flip_square(s)); // Side to move sideToMove = opposite_color(pos.side_to_move()); // Castling rights - if(pos.can_castle_kingside(WHITE)) allow_oo(BLACK); - if(pos.can_castle_queenside(WHITE)) allow_ooo(BLACK); - if(pos.can_castle_kingside(BLACK)) allow_oo(WHITE); - if(pos.can_castle_queenside(BLACK)) allow_ooo(WHITE); + if (pos.can_castle_kingside(WHITE)) allow_oo(BLACK); + if (pos.can_castle_queenside(WHITE)) allow_ooo(BLACK); + if (pos.can_castle_kingside(BLACK)) allow_oo(WHITE); + if (pos.can_castle_queenside(BLACK)) allow_ooo(WHITE); - initialKFile = pos.initialKFile; + initialKFile = pos.initialKFile; initialKRFile = pos.initialKRFile; initialQRFile = pos.initialQRFile; - for(Square sq = SQ_A1; sq <= SQ_H8; sq++) - castleRightsMask[sq] = ALL_CASTLES; - castleRightsMask[make_square(initialKFile, RANK_1)] ^= (WHITE_OO|WHITE_OOO); - castleRightsMask[make_square(initialKFile, RANK_8)] ^= (BLACK_OO|BLACK_OOO); - castleRightsMask[make_square(initialKRFile, RANK_1)] ^= WHITE_OO; - castleRightsMask[make_square(initialKRFile, RANK_8)] ^= BLACK_OO; - castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO; - castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; + for (Square sq = SQ_A1; sq <= SQ_H8; sq++) + castleRightsMask[sq] = ALL_CASTLES; + + castleRightsMask[make_square(initialKFile, RANK_1)] ^= (WHITE_OO | WHITE_OOO); + castleRightsMask[make_square(initialKFile, RANK_8)] ^= (BLACK_OO | BLACK_OOO); + castleRightsMask[make_square(initialKRFile, RANK_1)] ^= WHITE_OO; + castleRightsMask[make_square(initialKRFile, RANK_8)] ^= BLACK_OO; + castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO; + castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; // En passant square - if(pos.epSquare != SQ_NONE) - epSquare = flip_square(pos.epSquare); + if (pos.epSquare != SQ_NONE) + epSquare = flip_square(pos.epSquare); // Checkers find_checkers(); @@ -2128,133 +2147,143 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) *failedStep = 1; // Side to move OK? - if(!color_is_ok(side_to_move())) - return false; + if (!color_is_ok(side_to_move())) + return false; // Are the king squares in the position correct? if (failedStep) (*failedStep)++; - if(piece_on(king_square(WHITE)) != WK) - return false; + if (piece_on(king_square(WHITE)) != WK) + return false; if (failedStep) (*failedStep)++; - if(piece_on(king_square(BLACK)) != BK) - return false; + if (piece_on(king_square(BLACK)) != BK) + return false; // Castle files OK? if (failedStep) (*failedStep)++; - if(!file_is_ok(initialKRFile)) - return false; - if(!file_is_ok(initialQRFile)) - return false; + if (!file_is_ok(initialKRFile)) + return false; + + if (!file_is_ok(initialQRFile)) + return false; // Do both sides have exactly one king? if (failedStep) (*failedStep)++; - if(debugKingCount) { - int kingCount[2] = {0, 0}; - for(Square s = SQ_A1; s <= SQ_H8; s++) - if(type_of_piece_on(s) == KING) - kingCount[color_of_piece_on(s)]++; - if(kingCount[0] != 1 || kingCount[1] != 1) - return false; + if (debugKingCount) + { + int kingCount[2] = {0, 0}; + for (Square s = SQ_A1; s <= SQ_H8; s++) + if (type_of_piece_on(s) == KING) + kingCount[color_of_piece_on(s)]++; + + if(kingCount[0] != 1 || kingCount[1] != 1) + return false; } // Can the side to move capture the opponent's king? if (failedStep) (*failedStep)++; - if(debugKingCapture) { - Color us = side_to_move(); - Color them = opposite_color(us); - Square ksq = king_square(them); - if(square_is_attacked(ksq, us)) - return false; + if (debugKingCapture) + { + Color us = side_to_move(); + Color them = opposite_color(us); + Square ksq = king_square(them); + if (square_is_attacked(ksq, us)) + return false; } // Is there more than 2 checkers? if (failedStep) (*failedStep)++; - if(debugCheckerCount && count_1s(checkersBB) > 2) - return false; + if (debugCheckerCount && count_1s(checkersBB) > 2) + return false; // Bitboards OK? if (failedStep) (*failedStep)++; - if(debugBitboards) { - // The intersection of the white and black pieces must be empty: - if((pieces_of_color(WHITE) & pieces_of_color(BLACK)) - != EmptyBoardBB) - return false; - - // The union of the white and black pieces must be equal to all - // occupied squares: - if((pieces_of_color(WHITE) | pieces_of_color(BLACK)) - != occupied_squares()) - return false; + if (debugBitboards) + { + // The intersection of the white and black pieces must be empty + if ((pieces_of_color(WHITE) & pieces_of_color(BLACK)) != EmptyBoardBB) + return false; - // Separate piece type bitboards must have empty intersections: - for(PieceType p1 = PAWN; p1 <= KING; p1++) - for(PieceType p2 = PAWN; p2 <= KING; p2++) - if(p1 != p2 && (pieces_of_type(p1) & pieces_of_type(p2))) + // The union of the white and black pieces must be equal to all + // occupied squares + if ((pieces_of_color(WHITE) | pieces_of_color(BLACK)) != occupied_squares()) return false; + + // Separate piece type bitboards must have empty intersections + for (PieceType p1 = PAWN; p1 <= KING; p1++) + for (PieceType p2 = PAWN; p2 <= KING; p2++) + if (p1 != p2 && (pieces_of_type(p1) & pieces_of_type(p2))) + return false; } // En passant square OK? if (failedStep) (*failedStep)++; - if(ep_square() != SQ_NONE) { - // The en passant square must be on rank 6, from the point of view of the - // side to move. - if(relative_rank(side_to_move(), ep_square()) != RANK_6) - return false; + if (ep_square() != SQ_NONE) + { + // The en passant square must be on rank 6, from the point of view of the + // side to move. + if (relative_rank(side_to_move(), ep_square()) != RANK_6) + return false; } // Hash key OK? if (failedStep) (*failedStep)++; - if(debugKey && key != compute_key()) - return false; + if (debugKey && key != compute_key()) + return false; // Pawn hash key OK? if (failedStep) (*failedStep)++; - if(debugPawnKey && pawnKey != compute_pawn_key()) - return false; + if (debugPawnKey && pawnKey != compute_pawn_key()) + return false; // Material hash key OK? if (failedStep) (*failedStep)++; - if(debugMaterialKey && materialKey != compute_material_key()) - return false; + if (debugMaterialKey && materialKey != compute_material_key()) + return false; // Incremental eval OK? if (failedStep) (*failedStep)++; - if(debugIncrementalEval) { - if(mgValue != compute_mg_value()) - return false; - if(egValue != compute_eg_value()) - return false; + if (debugIncrementalEval) + { + if (mgValue != compute_mg_value()) + return false; + + if (egValue != compute_eg_value()) + return false; } // Non-pawn material OK? if (failedStep) (*failedStep)++; - if(debugNonPawnMaterial) { - if(npMaterial[WHITE] != compute_non_pawn_material(WHITE)) - return false; - if(npMaterial[BLACK] != compute_non_pawn_material(BLACK)) - return false; + if (debugNonPawnMaterial) + { + if(npMaterial[WHITE] != compute_non_pawn_material(WHITE)) + return false; + + if(npMaterial[BLACK] != compute_non_pawn_material(BLACK)) + return false; } // Piece counts OK? if (failedStep) (*failedStep)++; - if(debugPieceCounts) - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= KING; pt++) - if(pieceCount[c][pt] != count_1s(pieces_of_color_and_type(c, pt))) - return false; + if (debugPieceCounts) + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= KING; pt++) + if (pieceCount[c][pt] != count_1s(pieces_of_color_and_type(c, pt))) + return false; if (failedStep) (*failedStep)++; - if(debugPieceList) { - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= KING; pt++) - for(int i = 0; i < pieceCount[c][pt]; i++) { - if(piece_on(piece_list(c, pt, i)) != - piece_of_color_and_type(c, pt)) - return false; - if(index[piece_list(c, pt, i)] != i) - return false; - } + if (debugPieceList) + { + for(Color c = WHITE; c <= BLACK; c++) + for(PieceType pt = PAWN; pt <= KING; pt++) + for(int i = 0; i < pieceCount[c][pt]; i++) + { + if (piece_on(piece_list(c, pt, i)) != piece_of_color_and_type(c, pt)) + return false; + + if (index[piece_list(c, pt, i)] != i) + return false; + } } if (failedStep) *failedStep = 0; return true; diff --git a/src/position.h b/src/position.h index 48f40dac..a47098a8 100644 --- a/src/position.h +++ b/src/position.h @@ -7,12 +7,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -25,8 +25,8 @@ #if defined(_MSC_VER) // Forcing value to bool 'true' or 'false' (performance warning) -#pragma warning(disable: 4800) - +#pragma warning(disable: 4800) + #endif //// @@ -48,7 +48,7 @@ //// /// FEN string for the initial position: -const std::string StartPosition = +const std::string StartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; /// Maximum number of plies per game (220 should be enough, because the @@ -64,9 +64,9 @@ const int MaxGameLength = 220; /// Castle rights, encoded as bit fields: enum CastleRights { - NO_CASTLES = 0, + NO_CASTLES = 0, WHITE_OO = 1, - BLACK_OO = 2, + BLACK_OO = 2, WHITE_OOO = 4, BLACK_OOO = 8, ALL_CASTLES = 15 @@ -92,7 +92,7 @@ struct UndoInfo { /// The position data structure. A position consists of the following data: -/// +/// /// * For each piece type, a bitboard representing the squares occupied /// by pieces of that type. /// * For each color, a bitboard representing the squares occupiecd by @@ -217,8 +217,8 @@ public: bool piece_attacks_square(Square f, Square t) const; // Dispatch at run-time // Properties of moves - bool move_is_legal(Move m) const; - bool move_is_legal(Move m, Bitboard pinned) const; + bool pl_move_is_legal(Move m) const; + bool pl_move_is_legal(Move m, Bitboard pinned) const; bool move_is_check(Move m) const; bool move_is_check(Move m, Bitboard dcCandidates) const; bool move_is_capture(Move m) const; @@ -281,7 +281,7 @@ public: // Reset the gamePly variable to 0 void reset_game_ply(); - + // Position consistency check, for debugging bool is_ok(int* failedStep = NULL) const; @@ -305,6 +305,9 @@ private: void undo_ep_move(Move m); void find_checkers(); + template + Bitboard hidden_checks(Color c, Square ksq) const; + // Computing hash keys from scratch (for initialization and debugging) Key compute_key() const; Key compute_pawn_key() const; @@ -326,7 +329,7 @@ private: // Piece counts int pieceCount[2][8]; // [color][pieceType] - + // Piece lists Square pieceList[2][8][16]; // [color][pieceType][index] int index[64]; @@ -553,7 +556,7 @@ inline Bitboard Position::checkers() const { } inline bool Position::is_check() const { - return checkers() != EmptyBoardBB; + return checkersBB != EmptyBoardBB; } inline bool Position::pawn_attacks_square(Color c, Square f, Square t) const { @@ -588,7 +591,7 @@ inline bool Position::file_is_half_open(Color c, File f) const { inline bool Position::square_is_weak(Square s, Color c) const { return !(pawns(c) & outpost_mask(opposite_color(c), s)); } - + inline Key Position::get_key() const { return key; } @@ -639,7 +642,7 @@ inline Phase Position::game_phase() const { static const Value EndgameLimit = 4 * RookValueMidgame - Value(325); Value npm = non_pawn_material(WHITE) + non_pawn_material(BLACK); - + if (npm >= MidgameLimit) return PHASE_MIDGAME; else if(npm <= EndgameLimit) @@ -684,7 +687,7 @@ inline int Position::rule_50_counter() const { inline bool Position::opposite_colored_bishops() const { return piece_count(WHITE, BISHOP) == 1 - && piece_count(BLACK, BISHOP) == 1 + && piece_count(BLACK, BISHOP) == 1 && square_color(piece_list(WHITE, BISHOP, 0)) != square_color(piece_list(BLACK, BISHOP, 0)); } @@ -692,6 +695,6 @@ inline bool Position::has_pawn_on_7th(Color c) const { return pawns(c) & relative_rank_bb(c, RANK_7); } - + #endif // !defined(POSITION_H_INCLUDED) diff --git a/src/san.cpp b/src/san.cpp index df169977..01c87395 100644 --- a/src/san.cpp +++ b/src/san.cpp @@ -161,14 +161,14 @@ Move move_from_san(Position &pos, const std::string &movestr) { if(movestr == "O-O-O") { Move m; while((m = mp.get_next_move()) != MOVE_NONE) - if(move_is_long_castle(m) && pos.move_is_legal(m)) + if(move_is_long_castle(m) && pos.pl_move_is_legal(m)) return m; return MOVE_NONE; } else if(movestr == "O-O") { Move m; while((m = mp.get_next_move()) != MOVE_NONE) - if(move_is_short_castle(m) && pos.move_is_legal(m)) + if(move_is_short_castle(m) && pos.pl_move_is_legal(m)) return m; return MOVE_NONE; } @@ -358,7 +358,7 @@ namespace { n = 0; while((mv = mp.get_next_move()) != MOVE_NONE) if(move_to(mv) == to && pos.piece_on(move_from(mv)) == pc - && pos.move_is_legal(mv)) + && pos.pl_move_is_legal(mv)) moveList[n++] = mv; if(n == 1) return AMBIGUITY_NONE; diff --git a/src/search.cpp b/src/search.cpp index c5d6e36b..f2904184 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -931,6 +931,7 @@ namespace { { assert(move_is_ok(move)); + bool fewMoves = (depth <= OnePly && mp.number_of_moves() < 4); bool singleReply = (pos.is_check() && mp.number_of_moves() == 1); bool moveIsCheck = pos.move_is_check(move, dcCandidates); bool moveIsCapture = pos.move_is_capture(move); @@ -942,7 +943,7 @@ namespace { PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move)); // Decide the new search depth - Depth ext = extension(pos, move, true, moveIsCheck, singleReply, mateThreat); + Depth ext = extension(pos, move, true, moveIsCheck, singleReply || fewMoves, mateThreat); Depth newDepth = depth - OnePly + ext; // Make and search the move @@ -1996,26 +1997,35 @@ namespace { Depth extension(const Position &pos, Move m, bool pvNode, bool check, bool singleReply, bool mateThreat) { + Depth result = Depth(0); - if(check) - result += CheckExtension[pvNode]; - if(singleReply) - result += SingleReplyExtension[pvNode]; - if(pos.move_is_pawn_push_to_7th(m)) - result += PawnPushTo7thExtension[pvNode]; - if(pos.move_is_passed_pawn_push(m)) - result += PassedPawnExtension[pvNode]; - if(mateThreat) - result += MateThreatExtension[pvNode]; - if(pos.midgame_value_of_piece_on(move_to(m)) >= RookValueMidgame - && (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) - - pos.midgame_value_of_piece_on(move_to(m)) == Value(0)) - && !move_promotion(m)) - result += PawnEndgameExtension[pvNode]; - if(pvNode && pos.move_is_capture(m) - && pos.type_of_piece_on(move_to(m)) != PAWN && pos.see(m) >= 0) - result += OnePly/2; + if (check) + result += CheckExtension[pvNode]; + + if (singleReply) + result += SingleReplyExtension[pvNode]; + + if (pos.move_is_pawn_push_to_7th(m)) + result += PawnPushTo7thExtension[pvNode]; + + if (pos.move_is_passed_pawn_push(m)) + result += PassedPawnExtension[pvNode]; + + if (mateThreat) + result += MateThreatExtension[pvNode]; + + if ( pos.midgame_value_of_piece_on(move_to(m)) >= RookValueMidgame + && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) + - pos.midgame_value_of_piece_on(move_to(m)) == Value(0)) + && !move_promotion(m)) + result += PawnEndgameExtension[pvNode]; + + if ( pvNode + && pos.move_is_capture(m) + && pos.type_of_piece_on(move_to(m)) != PAWN + && pos.see(m) >= 0) + result += OnePly/2; return Min(result, OnePly); }