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
}
*/
char token;
- int hmc, fmn;
size_t p;
+ string ep;
Square sq = SQ_A8;
std::istringstream ss(fen);
clear();
- ss >> std::noskipws;
+ ss >> std::skipws >> token >> std::noskipws;
- // 1. Piece placement field
- while ((ss >> token) && !isspace(token))
+ // 1. Piece placement
+ while (!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;
+
+ ss >> token;
}
// 2. Active color
- if (!(ss >> token) || (token != 'w' && token != 'b'))
- goto incorrect_fen;
-
+ ss >> std::skipws >> token;
sideToMove = (token == 'w' ? WHITE : BLACK);
- if (!(ss >> token) || !isspace(token))
- goto incorrect_fen;
-
// 3. Castling availability
- while ((ss >> token) && !isspace(token))
- if (!set_castling_rights(token))
- goto incorrect_fen;
-
- // 4. En passant square
- char col, row;
- if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
- && ((ss >> row) && (row == '3' || row == '6')))
+ ss >> token >> std::noskipws;
+ while (token != '-' && !isspace(token))
+ {
+ set_castling_rights(token);
+ ss >> token;
+ }
+
+ // 4. En passant square. Ignore if no pawn capture is possible
+ ss >> std::skipws >> ep;
+ if (ep.size() == 2)
{
- st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1);
+ st->epSquare = make_square(File(ep[0] - 'a'), Rank(ep[1] - '1'));
- // Ignore if no capture is possible
- Color them = opposite_color(sideToMove);
- if (!(attacks_from<PAWN>(st->epSquare, them) & pieces(PAWN, sideToMove)))
+ if (!(attackers_to(st->epSquare) & 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 >> st->rule50 >> fullMoves;
// Various initialisations
castleRightsMask[make_square(initialKFile, RANK_1)] ^= WHITE_OO | WHITE_OOO;
st->value = compute_value();
st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
- return;
-
-incorrect_fen:
- cout << "Error in FEN string: " << fen << endl;
}
/// 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);
initialKFile = square_file(king_square(c));
- token = char(toupper(token));
- if (token == 'K')
+ if (toupper(token) == 'K')
{
for (Square sq = sqH; sq >= sqA; sq--)
- if (piece_on(sq) == rook)
+ if (piece_on(sq) == make_piece(c, ROOK))
{
set_castle_kingside(c);
initialKRFile = square_file(sq);
break;
}
}
- else if (token == 'Q')
+ else if (toupper(token) == 'Q')
{
for (Square sq = sqA; sq <= sqH; sq++)
- if (piece_on(sq) == rook)
+ if (piece_on(sq) == make_piece(c, ROOK))
{
set_castle_queenside(c);
initialQRFile = square_file(sq);
break;
}
}
- else if (token >= 'A' && token <= 'H')
+ else if (toupper(token) >= 'A' && toupper(token) <= 'H')
{
- File rookFile = File(token - 'A') + FILE_A;
+ File rookFile = File(toupper(token) - 'A');
+
if (rookFile < initialKFile)
{
set_castle_queenside(c);
initialKRFile = rookFile;
}
}
- else
- return token == '-';
-
- return true;
}
if (move)
{
Position p(*this, thread());
- string dd = (color_of_piece_on(move_from(move)) == BLACK ? ".." : "");
+ string dd = (piece_color(piece_on(move_from(move))) == BLACK ? ".." : "");
cout << "\nMove is: " << dd << move_to_san(p, move);
}
if (piece == PIECE_NONE && square_color(sq) == DARK)
piece = PIECE_NONE_DARK_SQ;
- char c = (color_of_piece_on(sq) == BLACK ? '=' : ' ');
+ char c = (piece_color(piece_on(sq)) == BLACK ? '=' : ' ');
cout << c << PieceToChar[piece] << c << '|';
}
}
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(color_of_piece_on(f));
+ & pieces_of_color(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.
Color us = side_to_move();
Square from = move_from(m);
- assert(color_of_piece_on(from) == us);
+ assert(piece_color(piece_on(from)) == us);
assert(piece_on(king_square(us)) == make_piece(us, KING));
// En passant captures are a tricky special case. Because they are
// If the moving piece is a king, check whether the destination
// square is attacked by the opponent. Castling moves are checked
// for legality during move generation.
- if (type_of_piece_on(from) == KING)
+ if (piece_type(piece_on(from)) == KING)
return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us)));
// A non-king move is legal if and only if it is not pinned or it
}
-/// 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 {
// If the from square is not occupied by a piece belonging to the side to
// move, the move is obviously not legal.
- if (pc == PIECE_NONE || color_of_piece(pc) != us)
+ if (pc == PIECE_NONE || piece_color(pc) != us)
return false;
// The destination square cannot be occupied by a friendly piece
- if (color_of_piece_on(to) == us)
+ if (piece_color(piece_on(to)) == us)
return false;
// Handle the special case of a pawn move
- if (type_of_piece(pc) == PAWN)
+ if (piece_type(pc) == PAWN)
{
// Move direction must be compatible with pawn color
int direction = to - from;
case DELTA_SE:
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
- if (color_of_piece_on(to) != them)
+ if (piece_color(piece_on(to)) != them)
return false;
// From and to files must be one file apart, avoids a7h5
{
// In case of king moves under check we have to remove king so to catch
// as invalid moves like b1a1 when opposite queen is on c1.
- if (type_of_piece_on(from) == KING)
+ if (piece_type(piece_on(from)) == KING)
{
Bitboard b = occupied_squares();
clear_bit(&b, from);
assert(is_ok());
assert(move_is_ok(m));
assert(ci.dcCandidates == discovered_check_candidates(side_to_move()));
- assert(color_of_piece_on(move_from(m)) == side_to_move());
+ assert(piece_color(piece_on(move_from(m))) == side_to_move());
Square from = move_from(m);
Square to = move_to(m);
- PieceType pt = type_of_piece_on(from);
+ PieceType pt = piece_type(piece_on(from));
// Direct check ?
if (bit_is_set(ci.checkSq[pt], to))
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();
bool pm = move_is_promotion(m);
Piece piece = piece_on(from);
- PieceType pt = type_of_piece(piece);
- PieceType capture = ep ? PAWN : type_of_piece_on(to);
+ PieceType pt = piece_type(piece);
+ PieceType capture = ep ? PAWN : piece_type(piece_on(to));
- assert(color_of_piece_on(from) == us);
- assert(color_of_piece_on(to) == them || square_is_empty(to));
+ assert(piece_color(piece_on(from)) == us);
+ assert(piece_color(piece_on(to)) == them || square_is_empty(to));
assert(!(ep || pm) || piece == make_piece(us, PAWN));
assert(!pm || relative_rank(us, to) == RANK_8);
bool ep = move_is_ep(m);
bool pm = move_is_promotion(m);
- PieceType pt = type_of_piece_on(to);
+ PieceType pt = piece_type(piece_on(to));
assert(square_is_empty(from));
- assert(color_of_piece_on(to) == us);
+ assert(piece_color(piece_on(to)) == us);
assert(!pm || relative_rank(us, to) == RANK_8);
assert(!ep || to == st->previous->epSquare);
assert(!ep || relative_rank(us, to) == RANK_6);
from = move_from(m);
to = move_to(m);
- capturedType = type_of_piece_on(to);
+ capturedType = piece_type(piece_on(to));
occupied = occupied_squares();
// Handle en passant moves
- if (st->epSquare == to && type_of_piece_on(from) == PAWN)
+ if (st->epSquare == to && piece_type(piece_on(from)) == PAWN)
{
Square capQq = (side_to_move() == WHITE ? to - DELTA_N : to - DELTA_S);
assert(capturedType == PIECE_TYPE_NONE);
- assert(type_of_piece_on(capQq) == PAWN);
+ assert(piece_type(piece_on(capQq)) == PAWN);
// Remove the captured pawn
clear_bit(&occupied, capQq);
attackers = attackers_to(to, occupied);
// If the opponent has no attackers we are finished
- stm = opposite_color(color_of_piece_on(from));
+ stm = opposite_color(piece_color(piece_on(from)));
stmAttackers = attackers & pieces_of_color(stm);
if (!stmAttackers)
return PieceValueMidgame[capturedType];
// capture with the least valuable piece. After each capture, we look for
// new X-ray attacks from behind the capturing piece.
swapList[0] = PieceValueMidgame[capturedType];
- capturedType = type_of_piece_on(from);
+ capturedType = piece_type(piece_on(from));
do {
// Locate the least valuable attacker for the side to move. The loop
st = &startState;
memset(st, 0, sizeof(StateInfo));
st->epSquare = SQ_NONE;
- startPosPlyCounter = 0;
+ fullMoves = 1;
nodes = 0;
memset(byColorBB, 0, sizeof(Bitboard) * 2);
void Position::put_piece(Piece p, Square s) {
- Color c = color_of_piece(p);
- PieceType pt = type_of_piece(p);
+ Color c = piece_color(p);
+ PieceType pt = piece_type(p);
board[s] = p;
index[s] = pieceCount[c][pt]++;
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];
+ result ^= zobrist[piece_color(piece_on(s))][piece_type(piece_on(s))][s];
if (ep_square() != SQ_NONE)
result ^= zobEp[ep_square()];
{
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 (piece_type(piece_on(s)) == KING)
+ kingCount[piece_color(piece_on(s))]++;
if (kingCount[0] != 1 || kingCount[1] != 1)
return false;