i++;
// En passant square
- if ( i < fen.length() - 2
+ if ( i <= fen.length() - 2
&& (fen[i] >= 'a' && fen[i] <= 'h')
&& (fen[i+1] == '3' || fen[i+1] == '6'))
st->epSquare = square_from_string(fen.substr(i, 2));
}
-/// Position:pinned_pieces() returns a bitboard of all pinned (against the
-/// king) pieces for the given color.
-Bitboard Position::pinned_pieces(Color c) const {
+/// Position:hidden_checkers<>() 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 pieces of the given color
+/// candidate for a discovery check against the enemy king.
+/// Note that checkersBB bitboard must be already updated.
- Bitboard p;
- Square ksq = king_square(c);
- return hidden_checks<ROOK, true>(c, ksq, p) | hidden_checks<BISHOP, true>(c, ksq, p);
-}
+template<bool FindPinned>
+Bitboard Position::hidden_checkers(Color c) const {
+ Bitboard pinners, result = EmptyBoardBB;
-/// 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.
+ // Pinned pieces protect our king, dicovery checks attack
+ // the enemy king.
+ Square ksq = king_square(FindPinned ? c : opposite_color(c));
-Bitboard Position::discovered_check_candidates(Color c) const {
+ // Pinners are sliders, not checkers, that give check when
+ // candidate pinned is removed.
+ pinners = (rooks_and_queens(FindPinned ? opposite_color(c) : c) & RookPseudoAttacks[ksq])
+ | (bishops_and_queens(FindPinned ? opposite_color(c) : c) & BishopPseudoAttacks[ksq]);
- Bitboard p;
- Square ksq = king_square(opposite_color(c));
- return hidden_checks<ROOK, false>(c, ksq, p) | hidden_checks<BISHOP, false>(c, ksq, p);
-}
+ if (FindPinned && pinners)
+ pinners &= ~st->checkersBB;
+ while (pinners)
+ {
+ Square s = pop_1st_bit(&pinners);
+ Bitboard b = squares_between(s, ksq) & occupied_squares();
-/// 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.
-/// Note that checkersBB bitboard must be already updated.
-template<PieceType Piece, bool FindPinned>
-Bitboard Position::hidden_checks(Color c, Square ksq, Bitboard& pinners) const {
+ assert(b);
- Square s;
- Bitboard sliders, result = EmptyBoardBB;
+ if ( !(b & (b - 1)) // Only one bit set?
+ && (b & pieces_of_color(c))) // Is an our piece?
+ result |= b;
+ }
+ return result;
+}
- 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 & ~st->checkersBB)))
- {
- // King blockers are candidate pinned pieces
- Bitboard candidate_pinned = piece_attacks<Piece>(ksq) & pieces_of_color(c);
-
- // Pinners are sliders, not checkers, that give check when
- // candidate pinned are removed.
- pinners = (FindPinned ? sliders & ~st->checkersBB : sliders);
-
- if (Piece == ROOK)
- pinners &= rook_attacks_bb(ksq, occupied_squares() ^ candidate_pinned);
- else
- pinners &= bishop_attacks_bb(ksq, occupied_squares() ^ candidate_pinned);
-
- // Finally for each pinner find the corresponding pinned piece (if same color of king)
- // or discovery checker (if opposite color) among the candidates.
- Bitboard p = pinners;
- while (p)
- {
- s = pop_1st_bit(&p);
- result |= (squares_between(s, ksq) & candidate_pinned);
- }
- }
- else
- pinners = EmptyBoardBB;
+/// Position:pinned_pieces() returns a bitboard of all pinned (against the
+/// king) pieces for the given color.
- return result;
+Bitboard Position::pinned_pieces(Color c) const {
+
+ return hidden_checkers<true>(c);
}
+/// Position:discovered_check_candidates() returns a bitboard containing all
+/// pieces for the given side which are candidates for giving a discovered
+/// check.
+
+Bitboard Position::discovered_check_candidates(Color c) const {
+
+ return hidden_checkers<false>(c);
+}
+
/// Position::attacks_to() computes a bitboard containing all pieces which
/// attacks a given square. There are two versions of this function: One
/// which finds attackers of both colors, and one which only finds the
return true;
Color us = side_to_move();
- Color them = opposite_color(us);
Square from = move_from(m);
Square ksq = king_square(us);
// after the move is made
if (move_is_ep(m))
{
+ Color them = opposite_color(us);
Square to = move_to(m);
Square capsq = make_square(square_file(to), square_rank(from));
Bitboard b = occupied_squares();
// 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));
+ return !(square_is_attacked(move_to(m), opposite_color(us)));
// 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.
- return ( !bit_is_set(pinned, from)
+ return ( !pinned
+ || !bit_is_set(pinned, from)
|| (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq)));
}
if (bit_is_set(pawn_attacks(them, ksq), to)) // Normal check?
return true;
- if ( bit_is_set(dcCandidates, from) // Discovered check?
+ if ( dcCandidates // Discovered check?
+ && bit_is_set(dcCandidates, from)
&& (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
return true;
}
return false;
+ // Test discovered check and normal check according to piece type
case KNIGHT:
- return bit_is_set(dcCandidates, from) // Discovered check?
- || bit_is_set(piece_attacks<KNIGHT>(ksq), to); // Normal check?
+ return (dcCandidates && bit_is_set(dcCandidates, from))
+ || bit_is_set(piece_attacks<KNIGHT>(ksq), to);
case BISHOP:
- return bit_is_set(dcCandidates, from) // Discovered check?
- || bit_is_set(piece_attacks<BISHOP>(ksq), to); // Normal check?
+ return (dcCandidates && bit_is_set(dcCandidates, from))
+ || ( direction_between_squares(ksq, to) != DIR_NONE
+ && bit_is_set(piece_attacks<BISHOP>(ksq), to));
case ROOK:
- return bit_is_set(dcCandidates, from) // Discovered check?
- || bit_is_set(piece_attacks<ROOK>(ksq), to); // Normal check?
+ return (dcCandidates && bit_is_set(dcCandidates, from))
+ || ( direction_between_squares(ksq, to) != DIR_NONE
+ && bit_is_set(piece_attacks<ROOK>(ksq), to));
case QUEEN:
// Discovered checks are impossible!
assert(!bit_is_set(dcCandidates, from));
- return bit_is_set(piece_attacks<QUEEN>(ksq), to); // Normal check?
+ return ( direction_between_squares(ksq, to) != DIR_NONE
+ && bit_is_set(piece_attacks<QUEEN>(ksq), to));
case KING:
// Discovered check?
inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square from,
Square to, Bitboard dcCandidates) {
- if (Piece != KING && bit_is_set(piece_attacks<Piece>(ksq), to))
+ const bool Bishop = (Piece == QUEEN || Piece == BISHOP);
+ const bool Rook = (Piece == QUEEN || Piece == ROOK);
+ const bool Slider = Bishop || Rook;
+
+ if ( ( (Bishop && bit_is_set(BishopPseudoAttacks[ksq], to))
+ || (Rook && bit_is_set(RookPseudoAttacks[ksq], to)))
+ && bit_is_set(piece_attacks<Piece>(ksq), to)) // slow, try to early skip
+ set_bit(pCheckersBB, to);
+
+ else if ( Piece != KING
+ && !Slider
+ && bit_is_set(piece_attacks<Piece>(ksq), to))
set_bit(pCheckersBB, to);
if (Piece != QUEEN && bit_is_set(dcCandidates, from))
st->capture = type_of_piece_on(to);
if (st->capture)
- do_capture_move(m, st->capture, them, to);
+ do_capture_move(st->capture, them, to);
// Move the piece
clear_bit(&(byColorBB[us]), from);
/// Position::do_capture_move() is a private method used to update captured
/// piece info. It is called from the main Position::do_move function.
-void Position::do_capture_move(Move m, PieceType capture, Color them, Square to) {
+void Position::do_capture_move(PieceType capture, Color them, Square to) {
assert(capture != KING);
st->mgValue -= pst<MidGame>(them, capture, to);
st->egValue -= pst<EndGame>(them, capture, to);
- assert(!move_promotion(m) || capture != PAWN);
-
// Update material
if (capture != PAWN)
npMaterial[them] -= piece_value_midgame(capture);
st->capture = type_of_piece_on(to);
if (st->capture)
- do_capture_move(m, st->capture, them, to);
+ do_capture_move(st->capture, them, to);
// Remove pawn
clear_bit(&(byColorBB[us]), from);
board[to] = EMPTY;
}
- // Finally point out state pointer back to the previous state
+ // Finally point our state pointer back to the previous state
st = st->previous;
assert(is_ok());
/// Position::do_null_move makes() a "null move": It switches the side to move
/// and updates the hash key without executing any move on the board.
-void Position::do_null_move(StateInfo& newSt) {
+void Position::do_null_move(StateInfo& backupSt) {
assert(is_ok());
assert(!is_check());
// Back up the information necessary to undo the null move to the supplied
// StateInfo object. In the case of a null move, the only thing we need to
// remember is the last move made and the en passant square.
- newSt.lastMove = st->lastMove;
- newSt.epSquare = st->epSquare;
- newSt.previous = st->previous;
- st->previous = &newSt;
+ // Note that differently from normal case here backupSt is actually used as
+ // a backup storage not as a new state to be used.
+ backupSt.lastMove = st->lastMove;
+ backupSt.epSquare = st->epSquare;
+ backupSt.previous = st->previous;
+ st->previous = &backupSt;
// Save the current key to the history[] array, in order to be able to
// detect repetition draws.
assert(is_ok());
assert(!is_check());
- // Restore information from the our StateInfo object
+ // Restore information from the our backup StateInfo object
st->lastMove = st->previous->lastMove;
st->epSquare = st->previous->epSquare;
st->previous = st->previous->previous;
// 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);
+ occ ^= (b & (~b + 1));
attackers |= (rook_attacks_bb(to, occ) & rooks_and_queens())
| (bishop_attacks_bb(to, occ) & bishops_and_queens());
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)
+ while (b)
{
- s = pop_1st_bit(&b);
- assert(piece_on(s) == piece_of_color_and_type(c, pt));
+ assert(piece_on(first_1(b)) == piece_of_color_and_type(c, pt));
+ pop_1st_bit(&b);
result += piece_value_midgame(pt);
}
}
}
-/// Position::is_mate() returns true or false depending on whether the
-/// 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() const {
-
- if (is_check())
- {
- MovePicker mp = MovePicker(*this, false, MOVE_NONE, EmptySearchStack, Depth(0));
- return mp.get_next_move() == MOVE_NONE;
- }
- return false;
-}
-
-
/// Position::is_draw() tests whether the position is drawn by material,
/// repetition, or the 50 moves rule. It does not detect stalemates, this
/// must be done by the search.
}
+/// Position::is_mate() returns true or false depending on whether the
+/// side to move is checkmated.
+
+bool Position::is_mate() const {
+
+ MoveStack moves[256];
+
+ return is_check() && !generate_evasions(*this, moves, pinned_pieces(sideToMove));
+}
+
+
/// 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
-/// matter, because it is currently only called from PV nodes, which are rare.
+/// from the current position.
bool Position::has_mate_threat(Color c) {
StateInfo st1, st2;
Color stm = side_to_move();
- // The following lines are useless and silly, but prevents gcc from
- // emitting a stupid warning stating that u1.lastMove and u1.epSquare might
- // be used uninitialized.
- st1.lastMove = st->lastMove;
- st1.epSquare = st->epSquare;
-
if (is_check())
return false;
MoveStack mlist[120];
int count;
bool result = false;
+ Bitboard dc = discovered_check_candidates(sideToMove);
+ Bitboard pinned = pinned_pieces(sideToMove);
- // Generate legal moves
- count = generate_legal_moves(*this, mlist);
+ // Generate pseudo-legal non-capture and capture check moves
+ count = generate_non_capture_checks(*this, mlist, dc);
+ count += generate_captures(*this, mlist + count);
// Loop through the moves, and see if one of them is mate
for (int i = 0; i < count; i++)
{
- do_move(mlist[i].move, st2);
+ Move move = mlist[i].move;
+
+ if (!pl_move_is_legal(move, pinned))
+ continue;
+
+ do_move(move, st2);
if (is_mate())
result = true;
- undo_move(mlist[i].move);
+ undo_move(move);
}
// Undo null move, if necessary
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(Piece p = WP; p <= BK; p++)
+ for(Square s = SQ_A1; s <= SQ_H8; s++)
+ zobrist[color_of_piece(p)][type_of_piece(p)][s] = genrand_int64();
- for (int i = 0; i < 64; i++)
- zobEp[i] = Key(genrand_int64());
+ zobEp[0] = 0ULL;
+ for(int i = 1; i < 64; i++)
+ zobEp[i] = genrand_int64();
- for (int i = 0; i < 16; i++)
- zobCastle[i] = genrand_int64();
+ for(int i = 15; i >= 0; i--)
+ zobCastle[(i&8) | (i&1) | ((i&2) << 1) | ((i&4) >> 1)] = 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);
+ zobMaterial[i][j][k] = (k > 0)? genrand_int64() : 0LL;
for (int i = 0; i < 16; i++)
- zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL);
+ zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = 0ULL;
}