const Value PieceValueMidgame[17] = {
VALUE_ZERO,
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
- RookValueMidgame, QueenValueMidgame, VALUE_ZERO,
- VALUE_ZERO, VALUE_ZERO,
+ RookValueMidgame, QueenValueMidgame,
+ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame
};
const Value PieceValueEndgame[17] = {
VALUE_ZERO,
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
- RookValueEndgame, QueenValueEndgame, VALUE_ZERO,
- VALUE_ZERO, VALUE_ZERO,
+ RookValueEndgame, QueenValueEndgame,
+ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame
};
startState = *st;
st = &startState;
- st->previous = NULL; // as a safe guard
+ st->previous = NULL; // As a safe guard
}
6) Fullmove number: The number of the full move. It starts at 1, and is incremented after Black's move.
*/
- char token;
- int hmc, fmn;
+ char col, row, token;
size_t p;
Square sq = SQ_A8;
std::istringstream ss(fen);
clear();
ss >> std::noskipws;
- // 1. Piece placement field
+ // 1. Piece placement
while ((ss >> token) && !isspace(token))
{
- if ((p = PieceToChar.find(token)) != string::npos)
+ if (token == '/')
+ sq -= Square(16); // Jump back of 2 rows
+
+ else if (isdigit(token))
+ sq += Square(token - '0'); // Skip the given number of files
+
+ else if ((p = PieceToChar.find(token)) != string::npos)
{
put_piece(Piece(p), sq);
sq++;
}
- else if (isdigit(token))
- sq += Square(token - '0'); // Skip the given number of files
- else if (token == '/')
- sq -= SQ_A3; // Jump back of 2 rows
- else
- goto incorrect_fen;
}
// 2. Active color
- if (!(ss >> token) || (token != 'w' && token != 'b'))
- goto incorrect_fen;
-
+ ss >> token;
sideToMove = (token == 'w' ? WHITE : BLACK);
-
- if (!(ss >> token) || !isspace(token))
- goto incorrect_fen;
+ ss >> token;
// 3. Castling availability
while ((ss >> token) && !isspace(token))
- if (!set_castling_rights(token))
- goto incorrect_fen;
+ set_castling_rights(token);
- // 4. En passant square
- char col, row;
+ // 4. En passant square. Ignore if no pawn capture is possible
if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
&& ((ss >> row) && (row == '3' || row == '6')))
{
- st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1);
-
- // Ignore if no capture is possible
+ st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
Color them = opposite_color(sideToMove);
+
if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
st->epSquare = SQ_NONE;
}
- // 5. Halfmove clock
- if (ss >> std::skipws >> hmc)
- st->rule50 = hmc;
-
- // 6. Fullmove number
- if (ss >> fmn)
- startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK);
+ // 5-6. Halfmove clock and fullmove number
+ ss >> std::skipws >> st->rule50 >> fullMoves;
// Various initialisations
- 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;
-
chess960 = isChess960;
find_checkers();
st->value = compute_value();
st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
- return;
+}
+
+
+/// Position::set_castle() is an helper function used to set
+/// correct castling related flags.
-incorrect_fen:
- cout << "Error in FEN string: " << fen << endl;
+void Position::set_castle(int f, Square ksq, Square rsq) {
+
+ st->castleRights |= f;
+ castleRightsMask[ksq] ^= f;
+ castleRightsMask[rsq] ^= f;
+ castleRookSquare[f] = rsq;
}
/// associated with the castling right, the traditional castling tag will be replaced
/// by the file letter of the involved rook as for the Shredder-FEN.
-bool Position::set_castling_rights(char token) {
+void Position::set_castling_rights(char token) {
+
+ Color c = islower(token) ? BLACK : WHITE;
- Color c = token >= 'a' ? BLACK : WHITE;
- Square sqA = (c == WHITE ? SQ_A1 : SQ_A8);
- Square sqH = (c == WHITE ? SQ_H1 : SQ_H8);
- Piece rook = (c == WHITE ? WR : BR);
+ Square sqA = relative_square(c, SQ_A1);
+ Square sqH = relative_square(c, SQ_H1);
+ Square rsq, ksq = king_square(c);
- initialKFile = square_file(king_square(c));
- token = char(toupper(token));
+ token = toupper(token);
if (token == 'K')
- {
- for (Square sq = sqH; sq >= sqA; sq--)
- if (piece_on(sq) == rook)
- {
- set_castle_kingside(c);
- initialKRFile = square_file(sq);
- break;
- }
- }
+ for (rsq = sqH; piece_on(rsq) != make_piece(c, ROOK); rsq--) {}
+
else if (token == 'Q')
- {
- for (Square sq = sqA; sq <= sqH; sq++)
- if (piece_on(sq) == rook)
- {
- set_castle_queenside(c);
- initialQRFile = square_file(sq);
- break;
- }
- }
+ for (rsq = sqA; piece_on(rsq) != make_piece(c, ROOK); rsq++) {}
+
else if (token >= 'A' && token <= 'H')
- {
- File rookFile = File(token - 'A') + FILE_A;
- if (rookFile < initialKFile)
- {
- set_castle_queenside(c);
- initialQRFile = rookFile;
- }
- else
- {
- set_castle_kingside(c);
- initialKRFile = rookFile;
- }
- }
- else
- return token == '-';
+ rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
- return true;
+ else return;
+
+ if (square_file(rsq) < square_file(ksq))
+ set_castle(WHITE_OOO << c, ksq, rsq);
+ else
+ set_castle(WHITE_OO << c, ksq, rsq);
}
{
sq = make_square(file, rank);
- if (square_is_occupied(sq))
+ if (!square_is_empty(sq))
{
if (emptyCnt != '0')
{
if (st->castleRights != CASTLES_NONE)
{
- if (can_castle_kingside(WHITE))
- fen += chess960 ? char(toupper(file_to_char(initialKRFile))) : 'K';
+ if (can_castle(WHITE_OO))
+ fen += chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OO))))) : 'K';
- if (can_castle_queenside(WHITE))
- fen += chess960 ? char(toupper(file_to_char(initialQRFile))) : 'Q';
+ if (can_castle(WHITE_OOO))
+ fen += chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OOO))))) : 'Q';
- if (can_castle_kingside(BLACK))
- fen += chess960 ? file_to_char(initialKRFile) : 'k';
+ if (can_castle(BLACK_OO))
+ fen += chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OO))) : 'k';
- if (can_castle_queenside(BLACK))
- fen += chess960 ? file_to_char(initialQRFile) : 'q';
+ if (can_castle(BLACK_OOO))
+ fen += chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OOO))) : 'q';
} else
fen += '-';
Bitboard Position::hidden_checkers(Color c) const {
Bitboard result = EmptyBoardBB;
- Bitboard pinners = pieces_of_color(FindPinned ? opposite_color(c) : c);
+ Bitboard pinners = pieces(FindPinned ? opposite_color(c) : c);
// Pinned pieces protect our king, dicovery checks attack
// the enemy king.
assert(b);
if ( !(b & (b - 1)) // Only one bit set?
- && (b & pieces_of_color(c))) // Is an our piece?
+ && (b & pieces(c))) // Is an our piece?
result |= b;
}
return result;
Bitboard occ, xray;
Square f = move_from(m), t = move_to(m);
- assert(square_is_occupied(f));
+ assert(!square_is_empty(f));
if (bit_is_set(attacks_from(piece_on(f), t), s))
return true;
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_of_color(piece_color(piece_on(f)));
+ & pieces(piece_color(piece_on(f)));
// If we have attacks we need to verify that are caused by our move
// and are not already existent ones.
void Position::find_checkers() {
Color us = side_to_move();
- st->checkersBB = attackers_to(king_square(us)) & pieces_of_color(opposite_color(us));
+ st->checkersBB = attackers_to(king_square(us)) & pieces(opposite_color(us));
}
// square is attacked by the opponent. Castling moves are checked
// for legality during move generation.
if (piece_type(piece_on(from)) == KING)
- return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us)));
+ return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces(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.
}
-/// Position::move_is_pl_slow() takes a position and a move and tests whether
-/// the move is pseudo legal. This version is not very fast and should be used
+/// Position::move_is_pl_slow() takes a move and tests whether the move
+/// is pseudo legal. This version is not very fast and should be used
/// only in non time-critical paths.
bool Position::move_is_pl_slow(const Move m) const {
}
-/// Fast version of Position::move_is_pl() that takes a position a move and a
-/// bitboard of pinned pieces as input, and tests whether the move is pseudo legal.
+/// Fast version of Position::move_is_pl() that takes a move and a bitboard
+/// of pinned pieces as input, and tests whether the move is pseudo legal.
bool Position::move_is_pl(const Move m) const {
{
Bitboard b = occupied_squares();
clear_bit(&b, from);
- if (attackers_to(move_to(m), b) & pieces_of_color(opposite_color(us)))
+ if (attackers_to(move_to(m), b) & pieces(opposite_color(us)))
return false;
}
else
StateInfo newSt;
+ // Update the number of full moves after black's move
+ if (sideToMove == BLACK)
+ fullMoves++;
+
do_move(m, newSt);
// Reset "game ply" in case we made a non-reversible move.
if (st->rule50 == 0)
st->gamePly = 0;
- // Update the number of plies played from the starting position
- startPosPlyCounter++;
-
// Our StateInfo newSt is about going out of scope so copy
// its content before it disappears.
detach();
st->pawnKey ^= zobrist[us][PAWN][to];
// Partially revert and update incremental scores
- st->value -= pst(us, PAWN, to);
- st->value += pst(us, promotion, to);
+ st->value -= pst(make_piece(us, PAWN), to);
+ st->value += pst(make_piece(us, promotion), to);
// Update material
st->npMaterial[us] += PieceValueMidgame[promotion];
if (moveIsCheck)
{
if (ep | pm)
- st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
+ st->checkersBB = attackers_to(king_square(them)) & pieces(us);
else
{
// Direct checks
key ^= zobrist[them][capture][capsq];
// Update incremental scores
- st->value -= pst(them, capture, capsq);
+ st->value -= pst(make_piece(them, capture), capsq);
// Update piece count
pieceCount[them][capture]--;
st->rule50 = 0;
// Update checkers BB
- st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us);
+ st->checkersBB = attackers_to(king_square(them)) & pieces(us);
// Finish
sideToMove = opposite_color(sideToMove);
// If the opponent has no attackers we are finished
stm = opposite_color(piece_color(piece_on(from)));
- stmAttackers = attackers & pieces_of_color(stm);
+ stmAttackers = attackers & pieces(stm);
if (!stmAttackers)
return PieceValueMidgame[capturedType];
// move before beginning the next iteration.
capturedType = pt;
stm = opposite_color(stm);
- stmAttackers = attackers & pieces_of_color(stm);
+ stmAttackers = attackers & pieces(stm);
// Stop before processing a king capture
if (capturedType == KING && stmAttackers)
st = &startState;
memset(st, 0, sizeof(StateInfo));
st->epSquare = SQ_NONE;
- startPosPlyCounter = 0;
- nodes = 0;
memset(byColorBB, 0, sizeof(Bitboard) * 2);
memset(byTypeBB, 0, sizeof(Bitboard) * 8);
memset(pieceCount, 0, sizeof(int) * 2 * 8);
memset(index, 0, sizeof(int) * 64);
- for (int i = 0; i < 64; i++)
- board[i] = PIECE_NONE;
-
for (int i = 0; i < 8; i++)
for (int j = 0; j < 16; j++)
pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE;
for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
+ {
+ board[sq] = PIECE_NONE;
castleRightsMask[sq] = ALL_CASTLES;
-
+ }
sideToMove = WHITE;
- initialKFile = FILE_E;
- initialKRFile = FILE_H;
- initialQRFile = FILE_A;
+ fullMoves = 1;
+ nodes = 0;
}
index[s] = pieceCount[c][pt]++;
pieceList[c][pt][index[s]] = s;
- set_bit(&(byTypeBB[pt]), s);
- set_bit(&(byColorBB[c]), s);
- set_bit(&(byTypeBB[0]), s); // HACK: byTypeBB[0] contains all occupied squares.
+ set_bit(&byTypeBB[pt], s);
+ set_bit(&byColorBB[c], s);
+ set_bit(&byTypeBB[0], s); // HACK: byTypeBB[0] contains all occupied squares.
}
Key result = zobCastle[st->castleRights];
for (Square s = SQ_A1; s <= SQ_H8; s++)
- if (square_is_occupied(s))
+ if (!square_is_empty(s))
result ^= zobrist[piece_color(piece_on(s))][piece_type(piece_on(s))][s];
if (ep_square() != SQ_NONE)
Key Position::compute_material_key() const {
- int count;
Key result = 0;
for (Color c = WHITE; c <= BLACK; c++)
for (PieceType pt = PAWN; pt <= QUEEN; pt++)
- {
- count = piece_count(c, pt);
- for (int i = 0; i < count; i++)
+ for (int i = 0, cnt = piece_count(c, pt); i < cnt; i++)
result ^= zobrist[c][pt][i];
- }
+
return result;
}
{
b = pieces(pt, c);
while (b)
- result += pst(c, pt, pop_1st_bit(&b));
+ result += pst(make_piece(c, pt), pop_1st_bit(&b));
}
result += (side_to_move() == WHITE ? TempoValue / 2 : -TempoValue / 2);
sideToMove = opposite_color(pos.side_to_move());
// Castling rights
- if (pos.can_castle_kingside(WHITE)) set_castle_kingside(BLACK);
- if (pos.can_castle_queenside(WHITE)) set_castle_queenside(BLACK);
- if (pos.can_castle_kingside(BLACK)) set_castle_kingside(WHITE);
- if (pos.can_castle_queenside(BLACK)) set_castle_queenside(WHITE);
-
- initialKFile = pos.initialKFile;
- initialKRFile = pos.initialKRFile;
- initialQRFile = pos.initialQRFile;
-
- 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;
+ if (pos.can_castle(WHITE_OO))
+ set_castle(BLACK_OO, king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OO)));
+ if (pos.can_castle(WHITE_OOO))
+ set_castle(BLACK_OOO, king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OOO)));
+ if (pos.can_castle(BLACK_OO))
+ set_castle(WHITE_OO, king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OO)));
+ if (pos.can_castle(BLACK_OOO))
+ set_castle(WHITE_OOO, king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OOO)));
// En passant square
if (pos.st->epSquare != SQ_NONE)
if (piece_on(king_square(BLACK)) != BK)
return false;
- // Castle files OK?
- if (failedStep) (*failedStep)++;
- if (!square_is_ok(make_square(initialKRFile, RANK_1)))
- return false;
-
- if (!square_is_ok(make_square(initialQRFile, RANK_1)))
- return false;
-
// Do both sides have exactly one king?
if (failedStep) (*failedStep)++;
if (debugKingCount)
Color us = side_to_move();
Color them = opposite_color(us);
Square ksq = king_square(them);
- if (attackers_to(ksq) & pieces_of_color(us))
+ if (attackers_to(ksq) & pieces(us))
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)
+ if ((pieces(WHITE) & pieces(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())
+ if ((pieces(WHITE) | pieces(BLACK)) != occupied_squares())
return false;
// Separate piece type bitboards must have empty intersections
if (failedStep) (*failedStep)++;
if (debugCastleSquares)
- {
- for (Color c = WHITE; c <= BLACK; c++)
+ for (CastleRight f = WHITE_OO; f <= BLACK_OOO; f = CastleRight(f << 1))
{
- if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != make_piece(c, ROOK))
- return false;
+ if (!can_castle(f))
+ continue;
- if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != make_piece(c, ROOK))
- return false;
- }
- // If we cannot castle castleRightsMask[] could be not valid, for instance when
- // king initial file is FILE_A as queen rook.
- if (can_castle(WHITE) || can_castle(BLACK))
- {
- if (castleRightsMask[initial_kr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OO))
- return false;
- if (castleRightsMask[initial_qr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OOO))
- return false;
- if (castleRightsMask[initial_kr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OO))
- return false;
- if (castleRightsMask[initial_qr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OOO))
+ Piece rook = (f & (WHITE_OO | WHITE_OOO) ? WR : BR);
+
+ if ( castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f)
+ || piece_on(castleRookSquare[f]) != rook)
return false;
}
- }
if (failedStep) *failedStep = 0;
return true;