#include <fstream>
#include <iostream>
#include <sstream>
+#include <algorithm>
#include "bitcount.h"
#include "movegen.h"
checkSq[BISHOP] = pos.attacks_from<BISHOP>(ksq);
checkSq[ROOK] = pos.attacks_from<ROOK>(ksq);
checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK];
- checkSq[KING] = EmptyBoardBB;
+ checkSq[KING] = 0;
}
/// or the FEN string, we want the new born Position object do not depend
/// on any external data so we detach state pointer from the source one.
-Position::Position(const Position& pos, int th) {
+void Position::copy(const Position& pos, int th) {
memcpy(this, &pos, sizeof(Position));
threadID = th;
/*
A FEN string defines a particular position using only the ASCII character set.
- A FEN string contains six fields. The separator between fields is a space. The fields are:
+ A FEN string contains six fields separated by a space. The fields are:
- 1) Piece placement (from white's perspective). Each rank is described, starting with rank 8 and ending
- with rank 1; within each rank, the contents of each square are described from file A through file H.
- Following the Standard Algebraic Notation (SAN), each piece is identified by a single letter taken
- from the standard English names. White pieces are designated using upper-case letters ("PNBRQK")
- while Black take lowercase ("pnbrqk"). Blank squares are noted using digits 1 through 8 (the number
- of blank squares), and "/" separate ranks.
+ 1) Piece placement (from white's perspective). Each rank is described, starting
+ with rank 8 and ending with rank 1; within each rank, the contents of each
+ square are described from file A through file H. Following the Standard
+ Algebraic Notation (SAN), each piece is identified by a single letter taken
+ from the standard English names. White pieces are designated using upper-case
+ letters ("PNBRQK") while Black take lowercase ("pnbrqk"). Blank squares are
+ noted using digits 1 through 8 (the number of blank squares), and "/"
+ separates ranks.
2) Active color. "w" means white moves next, "b" means black.
- 3) Castling availability. If neither side can castle, this is "-". Otherwise, this has one or more
- letters: "K" (White can castle kingside), "Q" (White can castle queenside), "k" (Black can castle
- kingside), and/or "q" (Black can castle queenside).
+ 3) Castling availability. If neither side can castle, this is "-". Otherwise,
+ this has one or more letters: "K" (White can castle kingside), "Q" (White
+ can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
+ can castle queenside).
- 4) En passant target square in algebraic notation. If there's no en passant target square, this is "-".
- If a pawn has just made a 2-square move, this is the position "behind" the pawn. This is recorded
- regardless of whether there is a pawn in position to make an en passant capture.
+ 4) En passant target square (in algebraic notation). If there's no en passant
+ target square, this is "-". If a pawn has just made a 2-square move, this
+ is the position "behind" the pawn. This is recorded regardless of whether
+ there is a pawn in position to make an en passant capture.
- 5) Halfmove clock: This is the number of halfmoves since the last pawn advance or capture. This is used
- to determine if a draw can be claimed under the fifty-move rule.
+ 5) Halfmove clock. This is the number of halfmoves since the last pawn advance
+ or capture. This is used to determine if a draw can be claimed under the
+ fifty-move rule.
- 6) Fullmove number: The number of the full move. It starts at 1, and is incremented after Black's move.
+ 6) Fullmove number. The number of the full move. It starts at 1, and is
+ incremented after Black's move.
*/
char col, row, token;
// Convert from fullmove starting from 1 to ply starting from 0,
// handle also common incorrect FEN with fullmove = 0.
- startPosPly = Max(2 * (startPosPly - 1), 0) + int(sideToMove == BLACK);
+ startPosPly = std::max(2 * (startPosPly - 1), 0) + int(sideToMove == BLACK);
st->key = compute_key();
st->pawnKey = compute_pawn_key();
{
sq = make_square(file, rank);
- if (!square_is_empty(sq))
+ if (square_is_empty(sq))
+ emptyCnt++;
+ else
{
- if (emptyCnt)
+ if (emptyCnt > 0)
{
fen << emptyCnt;
emptyCnt = 0;
}
fen << PieceToChar[piece_on(sq)];
}
- else
- emptyCnt++;
}
- if (emptyCnt)
+ if (emptyCnt > 0)
fen << emptyCnt;
if (rank > RANK_1)
fen << (sideToMove == WHITE ? " w " : " b ");
- if (st->castleRights != CASTLES_NONE)
- {
- if (can_castle(WHITE_OO))
- fen << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE_OO))))) : 'K');
+ if (can_castle(WHITE_OO))
+ fen << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE_OO))))) : 'K');
+
+ if (can_castle(WHITE_OOO))
+ fen << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE_OOO))))) : 'Q');
- if (can_castle(WHITE_OOO))
- fen << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE_OOO))))) : 'Q');
+ if (can_castle(BLACK_OO))
+ fen << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK_OO))) : 'k');
- if (can_castle(BLACK_OO))
- fen << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK_OO))) : 'k');
+ if (can_castle(BLACK_OOO))
+ fen << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK_OOO))) : 'q');
- if (can_castle(BLACK_OOO))
- fen << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK_OOO))) : 'q');
- } else
+ if (st->castleRights == CASTLES_NONE)
fen << '-';
- fen << (ep_square() == SQ_NONE ? " -" : " " + square_to_string(ep_square()))
- << " " << st->rule50 << " " << 1 + (startPosPly - int(sideToMove == BLACK)) / 2;
+ fen << (ep_square() == SQ_NONE ? " - " : " " + square_to_string(ep_square()) + " ")
+ << st->rule50 << " " << 1 + (startPosPly - int(sideToMove == BLACK)) / 2;
return fen.str();
}
if (move)
{
Position p(*this, thread());
- string dd = (sideToMove == BLACK ? ".." : "");
- cout << "\nMove is: " << dd << move_to_san(p, move);
+ cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move);
}
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
{
Square sq = make_square(file, rank);
Piece piece = piece_on(sq);
+ char c = (color_of(piece) == BLACK ? '=' : ' ');
if (piece == PIECE_NONE && color_of(sq) == DARK)
piece = PIECE_NONE_DARK_SQ;
- char c = (color_of(piece_on(sq)) == BLACK ? '=' : ' ');
cout << c << PieceToChar[piece] << c << '|';
}
}
/// king) pieces for the given color. Or, when template parameter FindPinned is
/// false, the function return the pieces of the given color candidate for a
/// discovery check against the enemy king.
-
template<bool FindPinned>
Bitboard Position::hidden_checkers() const {
// Pinned pieces protect our king, dicovery checks attack the enemy king
- Bitboard b, result = EmptyBoardBB;
+ Bitboard b, result = 0;
Bitboard pinners = pieces(FindPinned ? flip(sideToMove) : sideToMove);
Square ksq = king_square(FindPinned ? sideToMove : flip(sideToMove));
return result;
}
+// Explicit template instantiations
+template Bitboard Position::hidden_checkers<true>() const;
+template Bitboard Position::hidden_checkers<false>() const;
-/// Position:pinned_pieces() returns a bitboard of all pinned (against the
-/// king) pieces for the side to move.
-
-Bitboard Position::pinned_pieces() const {
-
- return hidden_checkers<true>();
-}
-
-
-/// Position:discovered_check_candidates() returns a bitboard containing all
-/// pieces for the side to move which are candidates for giving a discovered
-/// check.
-
-Bitboard Position::discovered_check_candidates() const {
-
- return hidden_checkers<false>();
-}
-/// Position::attackers_to() computes a bitboard of all pieces which attacks a
+/// Position::attackers_to() computes a bitboard of all pieces which attack a
/// given square. Slider attacks use occ bitboard as occupancy.
Bitboard Position::attackers_to(Square s, Bitboard occ) const {
| (attacks_from<KING>(s) & pieces(KING));
}
+
/// Position::attacks_from() computes a bitboard of all attacks of a given piece
/// put in a given square. Slider attacks use occ bitboard as occupancy.
assert(square_is_ok(s));
Bitboard occ, xray;
- Square f = move_from(m), t = move_to(m);
+ Square from = move_from(m);
+ Square to = move_to(m);
+ Piece piece = piece_on(from);
- assert(!square_is_empty(f));
+ assert(!square_is_empty(from));
- if (bit_is_set(attacks_from(piece_on(f), t), s))
+ // Update occupancy as if the piece is moving
+ occ = occupied_squares();
+ do_move_bb(&occ, make_move_bb(from, to));
+
+ // The piece moved in 'to' attacks the square 's' ?
+ if (bit_is_set(attacks_from(piece, to, occ), s))
return true;
- // Move the piece and scan for X-ray attacks behind it
- occ = occupied_squares();
- do_move_bb(&occ, make_move_bb(f, t));
- xray = ( (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN))
- |(bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN)))
- & pieces(color_of(piece_on(f)));
+ // Scan for possible X-ray attackers behind the moved piece
+ xray = (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN, color_of(piece)))
+ |(bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN, color_of(piece)));
- // If we have attacks we need to verify that are caused by our move
- // and are not already existent ones.
+ // Verify attackers are triggered by our move and not already existing
return xray && (xray ^ (xray & attacks_from<QUEEN>(s)));
}
/// Position::move_is_legal() takes a random move and tests whether the move
-/// is legal. This version is not very fast and should be used only
-/// in non time-critical paths.
+/// is legal. This version is not very fast and should be used only in non
+/// time-critical paths.
bool Position::move_is_legal(const Move m) const {
st->key = key;
// Update checkers bitboard, piece must be already moved
- st->checkersBB = EmptyBoardBB;
+ st->checkersBB = 0;
if (moveIsCheck)
{
// 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 (--slIndex)
- swapList[slIndex-1] = Min(-swapList[slIndex], swapList[slIndex-1]);
+ swapList[slIndex-1] = std::min(-swapList[slIndex], swapList[slIndex-1]);
return swapList[0];
}
// Draw by repetition?
if (!SkipRepetition)
{
- int i = 4, e = Min(st->rule50, st->pliesFromNull);
+ int i = 4, e = std::min(st->rule50, st->pliesFromNull);
if (i <= e)
{
if (debugBitboards)
{
// The intersection of the white and black pieces must be empty
- if ((pieces(WHITE) & pieces(BLACK)) != EmptyBoardBB)
+ if (!(pieces(WHITE) & pieces(BLACK)))
return false;
// The union of the white and black pieces must be equal to all