X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=7f0e1447d08bde86e81ee24781a260509e0da54c;hp=99445acdeadf223b6b7282c731f02801122c7135;hb=155bed18f5224d401ddf5b4b71d93d8a8c379b3c;hpb=018022b8666200dacd3533e215e2de41f93df9da diff --git a/src/position.cpp b/src/position.cpp index 99445acd..7f0e1447 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -42,34 +42,27 @@ Key Position::zobCastle[16]; Key Position::zobSideToMove; Key Position::zobExclusion; -Score Position::PieceSquareTable[16][64]; +Score Position::pieceSquareTable[16][64]; // Material values arrays, indexed by Piece -const Value Position::PieceValueMidgame[17] = { +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 Position::PieceValueEndgame[17] = { +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 }; -// Material values array used by SEE, indexed by PieceType -const Value Position::seeValues[] = { - VALUE_ZERO, - PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, - RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10 -}; - namespace { @@ -87,8 +80,8 @@ CheckInfo::CheckInfo(const Position& pos) { Color us = pos.side_to_move(); Color them = opposite_color(us); + Square ksq = pos.king_square(them); - ksq = pos.king_square(them); dcCandidates = pos.discovered_check_candidates(us); pinned = pos.pinned_pieces(us); @@ -128,7 +121,7 @@ void Position::detach() { startState = *st; st = &startState; - st->previous = NULL; // as a safe guard + st->previous = NULL; // As a safe guard } @@ -165,8 +158,7 @@ void Position::from_fen(const string& fen, bool isChess960) { 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); @@ -174,67 +166,48 @@ void Position::from_fen(const string& fen, bool isChess960) { 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(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->checkersBB = attackers_to(king_square(sideToMove)) & pieces(opposite_color(sideToMove)); st->key = compute_key(); st->pawnKey = compute_pawn_key(); @@ -242,10 +215,18 @@ void Position::from_fen(const string& fen, bool isChess960) { 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; + +/// Position::set_castle() is an helper function used to set +/// correct castling related flags. + +void Position::set_castle(int f, Square ksq, Square rsq) { + + st->castleRights |= f; + castleRightsMask[ksq] ^= f; + castleRightsMask[rsq] ^= f; + castleRookSquare[f] = rsq; } @@ -256,54 +237,31 @@ incorrect_fen: /// 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 = 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); + Color c = islower(token) ? BLACK : WHITE; + + 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)); 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); } @@ -324,7 +282,7 @@ const string Position::to_fen() const { { sq = make_square(file, rank); - if (square_is_occupied(sq)) + if (!square_is_empty(sq)) { if (emptyCnt != '0') { @@ -344,17 +302,17 @@ const string Position::to_fen() const { 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 += '-'; @@ -373,7 +331,7 @@ void Position::print(Move move) const { 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); } @@ -388,7 +346,7 @@ void Position::print(Move move) const { 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 << '|'; } } @@ -406,7 +364,7 @@ template 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. @@ -426,7 +384,7 @@ Bitboard Position::hidden_checkers(Color c) const { 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; @@ -517,7 +475,7 @@ bool Position::move_attacks_square(Move m, Square s) const { 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; @@ -527,7 +485,7 @@ bool Position::move_attacks_square(Move m, Square s) const { 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(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. @@ -535,19 +493,6 @@ bool Position::move_attacks_square(Move m, Square s) const { } -/// Position::find_checkers() computes the checkersBB bitboard, which -/// contains a nonzero bit for each checking piece (0, 1 or 2). It -/// currently works by calling Position::attackers_to, which is probably -/// inefficient. Consider rewriting this function to use the last move -/// played, like in non-bitboard versions of Glaurung. - -void Position::find_checkers() { - - Color us = side_to_move(); - st->checkersBB = attackers_to(king_square(us)) & pieces_of_color(opposite_color(us)); -} - - /// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { @@ -559,7 +504,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { 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 @@ -589,8 +534,8 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // 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) - return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us))); + if (piece_type(piece_on(from)) == KING) + 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. @@ -600,28 +545,22 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// 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 -/// only in non time-critical paths. +/// Position::move_is_legal() takes a move and tests whether the move +/// is 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 { +bool Position::move_is_legal(const Move m) const { - MoveStack mlist[MAX_MOVES]; - MoveStack *cur, *last; - - last = in_check() ? generate(*this, mlist) - : generate(*this, mlist); - - for (cur = mlist; cur != last; cur++) - if (cur->move == m) + for (MoveList ml(*this); !ml.end(); ++ml) + if (ml.move() == m) return true; return false; } -/// 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 { @@ -635,7 +574,7 @@ bool Position::move_is_pl(const Move m) const { // Use a slower but simpler function for uncommon cases if (move_is_special(m)) - return move_is_pl_slow(m); + return move_is_legal(m); // Is not a promotion, so promotion piece must be empty if (promotion_piece_type(m) - 2 != PIECE_TYPE_NONE) @@ -643,15 +582,15 @@ 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; @@ -673,7 +612,7 @@ bool Position::move_is_pl(const Move m) const { 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 @@ -719,11 +658,11 @@ bool Position::move_is_pl(const Move m) const { { // 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); - 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 @@ -752,12 +691,11 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { 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_on(ci.ksq) == make_piece(opposite_color(side_to_move()), KING)); + 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)) @@ -768,7 +706,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { { // For pawn and king moves we need to verify also direction if ( (pt != PAWN && pt != KING) - || !squares_aligned(from, to, ci.ksq)) + || !squares_aligned(from, to, king_square(opposite_color(side_to_move())))) return true; } @@ -778,6 +716,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { Color us = side_to_move(); Bitboard b = occupied_squares(); + Square ksq = king_square(opposite_color(us)); // Promotion with check ? if (move_is_promotion(m)) @@ -787,13 +726,13 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { switch (promotion_piece_type(m)) { case KNIGHT: - return bit_is_set(attacks_from(to), ci.ksq); + return bit_is_set(attacks_from(to), ksq); case BISHOP: - return bit_is_set(bishop_attacks_bb(to, b), ci.ksq); + return bit_is_set(bishop_attacks_bb(to, b), ksq); case ROOK: - return bit_is_set(rook_attacks_bb(to, b), ci.ksq); + return bit_is_set(rook_attacks_bb(to, b), ksq); case QUEEN: - return bit_is_set(queen_attacks_bb(to, b), ci.ksq); + return bit_is_set(queen_attacks_bb(to, b), ksq); default: assert(false); } @@ -809,8 +748,8 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { clear_bit(&b, from); clear_bit(&b, capsq); set_bit(&b, to); - return (rook_attacks_bb(ci.ksq, b) & pieces(ROOK, QUEEN, us)) - ||(bishop_attacks_bb(ci.ksq, b) & pieces(BISHOP, QUEEN, us)); + return (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us)) + ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us)); } // Castling with check ? @@ -832,7 +771,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { clear_bit(&b, rfrom); set_bit(&b, rto); set_bit(&b, kto); - return bit_is_set(rook_attacks_bb(rto, b), ci.ksq); + return bit_is_set(rook_attacks_bb(rto, b), ksq); } return false; @@ -846,6 +785,10 @@ void Position::do_setup_move(Move m) { 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. @@ -853,9 +796,6 @@ void Position::do_setup_move(Move m) { 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(); @@ -924,11 +864,11 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI 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); @@ -959,9 +899,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI // Move the piece Bitboard move_bb = make_move_bb(from, to); - do_move_bb(&(byColorBB[us]), move_bb); - do_move_bb(&(byTypeBB[pt]), move_bb); - do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares + do_move_bb(&byColorBB[us], move_bb); + do_move_bb(&byTypeBB[pt], move_bb); + do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares board[to] = board[from]; board[from] = PIECE_NONE; @@ -998,8 +938,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI assert(promotion >= KNIGHT && promotion <= QUEEN); // Insert promoted piece instead of pawn - clear_bit(&(byTypeBB[PAWN]), to); - set_bit(&(byTypeBB[promotion]), to); + clear_bit(&byTypeBB[PAWN], to); + set_bit(&byTypeBB[promotion], to); board[to] = make_piece(us, promotion); // Update piece counts @@ -1024,8 +964,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI 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]; @@ -1051,7 +991,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI 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 @@ -1062,10 +1002,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from)) { if (pt != ROOK) - st->checkersBB |= (attacks_from(ci.ksq) & pieces(ROOK, QUEEN, us)); + st->checkersBB |= (attacks_from(king_square(them)) & pieces(ROOK, QUEEN, us)); if (pt != BISHOP) - st->checkersBB |= (attacks_from(ci.ksq) & pieces(BISHOP, QUEEN, us)); + st->checkersBB |= (attacks_from(king_square(them)) & pieces(BISHOP, QUEEN, us)); } } } @@ -1108,15 +1048,15 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t st->npMaterial[them] -= PieceValueMidgame[capture]; // Remove captured piece - clear_bit(&(byColorBB[them]), capsq); - clear_bit(&(byTypeBB[capture]), capsq); - clear_bit(&(byTypeBB[0]), capsq); + clear_bit(&byColorBB[them], capsq); + clear_bit(&byTypeBB[capture], capsq); + clear_bit(&byTypeBB[0], capsq); // Update hash key 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]--; @@ -1154,12 +1094,9 @@ void Position::do_castle_move(Move m) { Color us = side_to_move(); Color them = opposite_color(us); - // Reset capture field - st->capturedType = PIECE_TYPE_NONE; - // 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 rfrom = move_to(m); Square kto, rto; assert(piece_on(kfrom) == make_piece(us, KING)); @@ -1170,28 +1107,30 @@ void Position::do_castle_move(Move m) { { kto = relative_square(us, SQ_G1); rto = relative_square(us, SQ_F1); - } else { // O-O-O + } + else // O-O-O + { kto = relative_square(us, SQ_C1); rto = relative_square(us, SQ_D1); } - // 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 - clear_bit(&(byColorBB[us]), rfrom); - clear_bit(&(byTypeBB[ROOK]), rfrom); - clear_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied 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 - set_bit(&(byColorBB[us]), rto); - set_bit(&(byTypeBB[ROOK]), rto); - set_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares - - // Update board array + // Remove pieces from source squares + clear_bit(&byColorBB[us], kfrom); + clear_bit(&byTypeBB[KING], kfrom); + clear_bit(&byTypeBB[0], kfrom); + clear_bit(&byColorBB[us], rfrom); + clear_bit(&byTypeBB[ROOK], rfrom); + clear_bit(&byTypeBB[0], rfrom); + + // Put pieces on destination squares + set_bit(&byColorBB[us], kto); + set_bit(&byTypeBB[KING], kto); + set_bit(&byTypeBB[0], kto); + set_bit(&byColorBB[us], rto); + set_bit(&byTypeBB[ROOK], rto); + set_bit(&byTypeBB[0], rto); + + // Update board Piece king = make_piece(us, KING); Piece rook = make_piece(us, ROOK); board[kfrom] = board[rfrom] = PIECE_NONE; @@ -1201,10 +1140,13 @@ void Position::do_castle_move(Move m) { // Update piece lists pieceList[us][KING][index[kfrom]] = kto; pieceList[us][ROOK][index[rfrom]] = rto; - int tmp = index[rfrom]; // In Chess960 could be rto == kfrom + int tmp = index[rfrom]; // In Chess960 could be kto == rfrom index[kto] = index[kfrom]; index[rto] = tmp; + // Reset capture field + st->capturedType = PIECE_TYPE_NONE; + // Update incremental scores st->value += pst_delta(king, kfrom, kto); st->value += pst_delta(rook, rfrom, rto); @@ -1229,7 +1171,7 @@ void Position::do_castle_move(Move m) { 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); @@ -1262,10 +1204,10 @@ void Position::undo_move(Move m) { 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); @@ -1280,8 +1222,8 @@ void Position::undo_move(Move m) { assert(piece_on(to) == make_piece(us, promotion)); // Replace promoted piece with a pawn - clear_bit(&(byTypeBB[promotion]), to); - set_bit(&(byTypeBB[PAWN]), to); + clear_bit(&byTypeBB[promotion], to); + set_bit(&byTypeBB[PAWN], to); // Update piece counts pieceCount[us][promotion]--; @@ -1298,9 +1240,9 @@ void Position::undo_move(Move m) { // Put the piece back at the source square Bitboard move_bb = make_move_bb(to, from); - do_move_bb(&(byColorBB[us]), move_bb); - do_move_bb(&(byTypeBB[pt]), move_bb); - do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares + do_move_bb(&byColorBB[us], move_bb); + do_move_bb(&byTypeBB[pt], move_bb); + do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares board[from] = make_piece(us, pt); board[to] = PIECE_NONE; @@ -1320,9 +1262,9 @@ void Position::undo_move(Move m) { assert(!ep || square_is_empty(capsq)); // Restore the captured piece - set_bit(&(byColorBB[them]), capsq); - set_bit(&(byTypeBB[st->capturedType]), capsq); - set_bit(&(byTypeBB[0]), capsq); + set_bit(&byColorBB[them], capsq); + set_bit(&byTypeBB[st->capturedType], capsq); + set_bit(&byTypeBB[0], capsq); board[capsq] = make_piece(them, st->capturedType); @@ -1352,13 +1294,13 @@ void Position::undo_castle_move(Move m) { assert(move_is_castle(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. Color us = side_to_move(); // 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 rfrom = move_to(m); Square kto, rto; // Find destination squares for king and rook @@ -1366,7 +1308,9 @@ void Position::undo_castle_move(Move m) { { kto = relative_square(us, SQ_G1); rto = relative_square(us, SQ_F1); - } else { // O-O-O + } + else // O-O-O + { kto = relative_square(us, SQ_C1); rto = relative_square(us, SQ_D1); } @@ -1374,26 +1318,28 @@ void Position::undo_castle_move(Move m) { assert(piece_on(kto) == make_piece(us, KING)); assert(piece_on(rto) == make_piece(us, ROOK)); - // 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 - clear_bit(&(byColorBB[us]), rto); - clear_bit(&(byTypeBB[ROOK]), rto); - clear_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied 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 - set_bit(&(byColorBB[us]), rfrom); - set_bit(&(byTypeBB[ROOK]), rfrom); - set_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied squares + // Remove pieces from destination squares + clear_bit(&byColorBB[us], kto); + clear_bit(&byTypeBB[KING], kto); + clear_bit(&byTypeBB[0], kto); + clear_bit(&byColorBB[us], rto); + clear_bit(&byTypeBB[ROOK], rto); + clear_bit(&byTypeBB[0], rto); + + // Put pieces on source squares + set_bit(&byColorBB[us], kfrom); + set_bit(&byTypeBB[KING], kfrom); + set_bit(&byTypeBB[0], kfrom); + set_bit(&byColorBB[us], rfrom); + set_bit(&byTypeBB[ROOK], rfrom); + set_bit(&byTypeBB[0], rfrom); // Update board - board[rto] = board[kto] = PIECE_NONE; - board[rfrom] = make_piece(us, ROOK); - board[kfrom] = make_piece(us, KING); + Piece king = make_piece(us, KING); + Piece rook = make_piece(us, ROOK); + board[kto] = board[rto] = PIECE_NONE; + board[kfrom] = king; + board[rfrom] = rook; // Update piece lists pieceList[us][KING][index[kto]] = kfrom; @@ -1485,7 +1431,7 @@ int Position::see_sign(Move m) const { // Early return if SEE cannot be negative because captured piece value // is not less then capturing one. Note that king moves always return // here because king midgame value is set to 0. - if (midgame_value_of_piece_on(to) >= midgame_value_of_piece_on(from)) + if (piece_value_midgame(piece_on(to)) >= piece_value_midgame(piece_on(from))) return 1; return see(m); @@ -1509,16 +1455,16 @@ int Position::see(Move m) const { 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); @@ -1531,10 +1477,10 @@ int Position::see(Move m) const { attackers = attackers_to(to, occupied); // If the opponent has no attackers we are finished - stm = opposite_color(color_of_piece_on(from)); - stmAttackers = attackers & pieces_of_color(stm); + stm = opposite_color(piece_color(piece_on(from))); + stmAttackers = attackers & pieces(stm); if (!stmAttackers) - return seeValues[capturedType]; + return PieceValueMidgame[capturedType]; // The destination square is defended, which makes things rather more // difficult to compute. We proceed by building up a "swap list" containing @@ -1542,8 +1488,8 @@ int Position::see(Move m) const { // 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. - swapList[0] = seeValues[capturedType]; - capturedType = type_of_piece_on(from); + swapList[0] = PieceValueMidgame[capturedType]; + capturedType = piece_type(piece_on(from)); do { // Locate the least valuable attacker for the side to move. The loop @@ -1563,14 +1509,14 @@ int Position::see(Move m) const { // Add the new entry to the swap list assert(slIndex < 32); - swapList[slIndex] = -swapList[slIndex - 1] + seeValues[capturedType]; + swapList[slIndex] = -swapList[slIndex - 1] + PieceValueMidgame[capturedType]; slIndex++; // Remember the value of the capturing piece, and change the side to // 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) @@ -1598,28 +1544,24 @@ void Position::clear() { 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; } @@ -1628,16 +1570,16 @@ void Position::clear() { 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]++; 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. } @@ -1651,8 +1593,8 @@ Key Position::compute_key() const { Key result = zobCastle[st->castleRights]; 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 (!square_is_empty(s)) + result ^= zobrist[piece_color(piece_on(s))][piece_type(piece_on(s))][s]; if (ep_square() != SQ_NONE) result ^= zobEp[ep_square()]; @@ -1693,16 +1635,13 @@ Key Position::compute_pawn_key() const { 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; } @@ -1721,7 +1660,7 @@ Score Position::compute_value() const { { 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); @@ -1779,8 +1718,7 @@ template bool Position::is_draw() const; bool Position::is_mate() const { - MoveStack moves[MAX_MOVES]; - return in_check() && generate(*this, moves) == moves; + return in_check() && !MoveList(*this).size(); } @@ -1811,11 +1749,11 @@ void Position::init() { for (Square s = SQ_A1; s <= SQ_H8; s++) for (Piece p = WP; p <= WK; p++) - PieceSquareTable[p][s] = make_score(MgPST[p][s], EgPST[p][s]); + pieceSquareTable[p][s] = make_score(MgPST[p][s], EgPST[p][s]); for (Square s = SQ_A1; s <= SQ_H8; s++) for (Piece p = BP; p <= BK; p++) - PieceSquareTable[p][s] = -PieceSquareTable[p-8][flip_square(s)]; + pieceSquareTable[p][s] = -pieceSquareTable[p-8][flip_square(s)]; } @@ -1841,28 +1779,21 @@ void Position::flip() { 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) st->epSquare = flip_square(pos.st->epSquare); // Checkers - find_checkers(); + st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(opposite_color(sideToMove)); // Hash keys st->key = compute_key(); @@ -1916,22 +1847,14 @@ bool Position::is_ok(int* failedStep) const { 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) { 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; @@ -1944,7 +1867,7 @@ bool Position::is_ok(int* failedStep) const { 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; } @@ -1958,12 +1881,12 @@ bool Position::is_ok(int* failedStep) const { 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 @@ -2028,33 +1951,26 @@ bool Position::is_ok(int* failedStep) const { for (PieceType pt = PAWN; pt <= KING; pt++) for (int i = 0; i < pieceCount[c][pt]; i++) { - if (piece_on(piece_list(c, pt, i)) != make_piece(c, pt)) + if (piece_on(piece_list(c, pt)[i]) != make_piece(c, pt)) return false; - if (index[piece_list(c, pt, i)] != i) + if (index[piece_list(c, pt)[i]] != i) return false; } 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; + + Piece rook = (f & (WHITE_OO | WHITE_OOO) ? WR : BR); - if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != make_piece(c, ROOK)) + if ( castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f) + || piece_on(castleRookSquare[f]) != rook) return false; } - 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)) - return false; - } if (failedStep) *failedStep = 0; return true;