X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=74cb1f4eefef8c920ce7b1da55a70153fe9c08ca;hp=c8132d5e513d2a1b2d4aa6a711f96e1440b0b5f7;hb=7733dadfd7c8781e3bde3cc4e21751fa44ab6ed8;hpb=252537fd9c8cb60f765ea390d2464a42adeafc0a diff --git a/src/position.cpp b/src/position.cpp index c8132d5e..74cb1f4e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -46,7 +46,7 @@ using std::endl; static inline bool isZero(char c) { return c == '0'; } -struct PieceLetters : std::map { +struct PieceLetters : public std::map { PieceLetters() { @@ -71,10 +71,16 @@ struct PieceLetters : std::map { } }; + //// -//// Variables +//// Constants and variables //// +/// Bonus for having the side to move (modified by Joona Kiiski) + +static const Score TempoValue = make_score(48, 22); + + Key Position::zobrist[2][8][64]; Key Position::zobEp[64]; Key Position::zobCastle[16]; @@ -85,6 +91,12 @@ Score Position::PieceSquareTable[16][64]; static PieceLetters pieceLetters; +// Material values used by SEE, indexed by PieceType +const Value Position::seeValues[] = { + VALUE_ZERO, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, + RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10 +}; + /// Constructors @@ -182,7 +194,7 @@ void Position::from_fen(const string& fen) { { if (isdigit(token)) { - file += token - '0'; // Skip the given number of files + file += File(token - '0'); // Skip the given number of files continue; } else if (token == '/') @@ -240,6 +252,10 @@ void Position::from_fen(const string& fen) { castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO; castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; + isChess960 = initialKFile != FILE_E + || initialQRFile != FILE_A + || initialKRFile != FILE_H; + find_checkers(); st->key = compute_key(); @@ -346,21 +362,17 @@ const string Position::to_fen() const { if (st->castleRights != CASTLES_NONE) { - const bool Chess960 = initialKFile != FILE_E - || initialQRFile != FILE_A - || initialKRFile != FILE_H; - if (can_castle_kingside(WHITE)) - fen += Chess960 ? char(toupper(file_to_char(initialKRFile))) : 'K'; + fen += isChess960 ? char(toupper(file_to_char(initialKRFile))) : 'K'; if (can_castle_queenside(WHITE)) - fen += Chess960 ? char(toupper(file_to_char(initialQRFile))) : 'Q'; + fen += isChess960 ? char(toupper(file_to_char(initialQRFile))) : 'Q'; if (can_castle_kingside(BLACK)) - fen += Chess960 ? file_to_char(initialKRFile) : 'k'; + fen += isChess960 ? file_to_char(initialKRFile) : 'k'; if (can_castle_queenside(BLACK)) - fen += Chess960 ? file_to_char(initialQRFile) : 'q'; + fen += isChess960 ? file_to_char(initialQRFile) : 'q'; } else fen += '-'; @@ -370,7 +382,7 @@ const string Position::to_fen() const { /// Position::print() prints an ASCII representation of the position to -/// the standard output. If a move is given then also the san is print. +/// the standard output. If a move is given then also the san is printed. void Position::print(Move move) const { @@ -839,8 +851,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI // Reset rule 50 draw counter st->rule50 = 0; - // Update pawn hash key + // Update pawn hash key and prefetch in L1/L2 cache st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; + prefetchPawn(st->pawnKey, threadID); // Set en passant square, only if moved pawn can be captured if ((to ^ from) == 16) @@ -889,7 +902,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI st->value += pst(us, promotion, to); // Update material - st->npMaterial[us] += piece_value_midgame(promotion); + st->npMaterial[us] += PieceValueMidgame[promotion]; } } @@ -962,7 +975,7 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t st->pawnKey ^= zobrist[them][PAWN][capsq]; } else - st->npMaterial[them] -= piece_value_midgame(capture); + st->npMaterial[them] -= PieceValueMidgame[capture]; // Remove captured piece clear_bit(&(byColorBB[them]), capsq); @@ -1332,12 +1345,6 @@ void Position::undo_null_move() { /// move, and one which takes a 'from' and a 'to' square. The function does /// not yet understand promotions captures. -int Position::see(Square to) const { - - assert(square_is_ok(to)); - return see(SQ_NONE, to); -} - int Position::see(Move m) const { assert(move_is_ok(m)); @@ -1362,82 +1369,50 @@ int Position::see_sign(Move m) const { int Position::see(Square from, Square to) const { - // Material values - static const int seeValues[18] = { - 0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, - RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0, - 0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, - RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0, - 0, 0 - }; - - Bitboard attackers, stmAttackers, b; + Bitboard occ, attackers, stmAttackers, b; + int swapList[32], slIndex = 1; + PieceType capturedType, pt; + Color stm; - assert(square_is_ok(from) || from == SQ_NONE); + assert(square_is_ok(from)); assert(square_is_ok(to)); - // Initialize colors - Color us = (from != SQ_NONE ? color_of_piece_on(from) : opposite_color(color_of_piece_on(to))); - Color them = opposite_color(us); - - // Initialize pieces - Piece piece = piece_on(from); - Piece capture = piece_on(to); - Bitboard occ = occupied_squares(); + capturedType = type_of_piece_on(to); // King cannot be recaptured - if (type_of_piece(piece) == KING) - return seeValues[capture]; + if (capturedType == KING) + return seeValues[capturedType]; + + occ = occupied_squares(); // Handle en passant moves if (st->epSquare == to && type_of_piece_on(from) == PAWN) { - assert(capture == PIECE_NONE); + Square capQq = (side_to_move() == WHITE) ? (to - DELTA_N) : (to - DELTA_S); - Square capQq = (side_to_move() == WHITE)? (to - DELTA_N) : (to - DELTA_S); - capture = piece_on(capQq); + assert(capturedType == PIECE_TYPE_NONE); assert(type_of_piece_on(capQq) == PAWN); // Remove the captured pawn clear_bit(&occ, capQq); + capturedType = PAWN; } - while (true) - { - // Find all attackers to the destination square, with the moving piece - // removed, but possibly an X-ray attacker added behind it. - clear_bit(&occ, from); - attackers = (rook_attacks_bb(to, occ) & pieces(ROOK, QUEEN)) - | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN)) - | (attacks_from(to) & pieces(KNIGHT)) - | (attacks_from(to) & pieces(KING)) - | (attacks_from(to, WHITE) & pieces(PAWN, BLACK)) - | (attacks_from(to, BLACK) & pieces(PAWN, WHITE)); - - if (from != SQ_NONE) - break; - - // If we don't have any attacker we are finished - if ((attackers & pieces_of_color(us)) == EmptyBoardBB) - return 0; - - // Locate the least valuable attacker to the destination square - // and use it to initialize from square. - stmAttackers = attackers & pieces_of_color(us); - PieceType pt; - for (pt = PAWN; !(stmAttackers & pieces(pt)); pt++) - assert(pt < KING); - - from = first_1(stmAttackers & pieces(pt)); - piece = piece_on(from); - } + // Find all attackers to the destination square, with the moving piece + // removed, but possibly an X-ray attacker added behind it. + clear_bit(&occ, from); + attackers = (rook_attacks_bb(to, occ) & pieces(ROOK, QUEEN)) + | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN)) + | (attacks_from(to) & pieces(KNIGHT)) + | (attacks_from(to) & pieces(KING)) + | (attacks_from(to, WHITE) & pieces(PAWN, BLACK)) + | (attacks_from(to, BLACK) & pieces(PAWN, WHITE)); // If the opponent has no attackers we are finished - stmAttackers = attackers & pieces_of_color(them); + stm = opposite_color(color_of_piece_on(from)); + stmAttackers = attackers & pieces_of_color(stm); if (!stmAttackers) - return seeValues[capture]; - - attackers &= occ; // Remove the moving piece + return seeValues[capturedType]; // The destination square is defended, which makes things rather more // difficult to compute. We proceed by building up a "swap list" containing @@ -1445,12 +1420,8 @@ int Position::see(Square from, Square to) 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. - int lastCapturingPieceValue = seeValues[piece]; - int swapList[32], n = 1; - Color c = them; - PieceType pt; - - swapList[0] = seeValues[capture]; + swapList[0] = seeValues[capturedType]; + capturedType = type_of_piece_on(from); do { // Locate the least valuable attacker for the side to move. The loop @@ -1463,35 +1434,35 @@ int Position::see(Square from, Square to) const { // and scan for new X-ray attacks behind the attacker. b = stmAttackers & pieces(pt); occ ^= (b & (~b + 1)); - attackers |= (rook_attacks_bb(to, occ) & pieces(ROOK, QUEEN)) + attackers |= (rook_attacks_bb(to, occ) & pieces(ROOK, QUEEN)) | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN)); - attackers &= occ; + attackers &= occ; // Cut out pieces we've already done // Add the new entry to the swap list - assert(n < 32); - swapList[n] = -swapList[n - 1] + lastCapturingPieceValue; - n++; + assert(slIndex < 32); + swapList[slIndex] = -swapList[slIndex - 1] + seeValues[capturedType]; + slIndex++; // Remember the value of the capturing piece, and change the side to move // before beginning the next iteration - lastCapturingPieceValue = seeValues[pt]; - c = opposite_color(c); - stmAttackers = attackers & pieces_of_color(c); + capturedType = pt; + stm = opposite_color(stm); + stmAttackers = attackers & pieces_of_color(stm); // Stop after a king capture if (pt == KING && stmAttackers) { - assert(n < 32); - swapList[n++] = QueenValueMidgame*10; + assert(slIndex < 32); + swapList[slIndex++] = QueenValueMidgame*10; break; } } while (stmAttackers); // 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 (--n) - swapList[n-1] = Min(-swapList[n], swapList[n-1]); + while (--slIndex) + swapList[slIndex-1] = Min(-swapList[slIndex], swapList[slIndex-1]); return swapList[0]; } @@ -1590,7 +1561,7 @@ void Position::allow_ooo(Color c) { Key Position::compute_key() const { - Key result = Key(0ULL); + Key result = 0; for (Square s = SQ_A1; s <= SQ_H8; s++) if (square_is_occupied(s)) @@ -1615,7 +1586,7 @@ Key Position::compute_key() const { Key Position::compute_pawn_key() const { - Key result = Key(0ULL); + Key result = 0; Bitboard b; Square s; @@ -1640,7 +1611,7 @@ Key Position::compute_pawn_key() const { Key Position::compute_material_key() const { - Key result = Key(0ULL); + Key result = 0; for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= QUEEN; pt++) { @@ -1658,7 +1629,7 @@ Key Position::compute_material_key() const { /// updated by do_move and undo_move when the program is running in debug mode. Score Position::compute_value() const { - Score result = make_score(0, 0); + Score result = SCORE_ZERO; Bitboard b; Square s; @@ -1686,7 +1657,7 @@ Score Position::compute_value() const { Value Position::compute_non_pawn_material(Color c) const { - Value result = Value(0); + Value result = VALUE_ZERO; for (PieceType pt = KNIGHT; pt <= QUEEN; pt++) { @@ -1694,8 +1665,9 @@ Value Position::compute_non_pawn_material(Color c) const { while (b) { assert(piece_on(first_1(b)) == piece_of_color_and_type(c, pt)); + pop_1st_bit(&b); - result += piece_value_midgame(pt); + result += PieceValueMidgame[pt]; } } return result; @@ -1705,7 +1677,6 @@ Value Position::compute_non_pawn_material(Color c) const { /// 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. -// FIXME: Currently we are not handling 50 move rule correctly when in check bool Position::is_draw() const { @@ -1715,7 +1686,7 @@ bool Position::is_draw() const { return true; // Draw by the 50 moves rule? - if (st->rule50 > 100 || (st->rule50 == 100 && !is_check())) + if (st->rule50 > 99 && (st->rule50 > 100 || !is_mate())) return true; // Draw by repetition? @@ -1732,7 +1703,7 @@ bool Position::is_draw() const { bool Position::is_mate() const { - MoveStack moves[256]; + MoveStack moves[MOVES_MAX]; return is_check() && (generate_moves(*this, moves) == moves); } @@ -1742,7 +1713,7 @@ bool Position::is_mate() const { bool Position::has_mate_threat() { - MoveStack mlist[256], *last, *cur; + MoveStack mlist[MOVES_MAX], *last, *cur; StateInfo st1, st2; bool mateFound = false; @@ -1946,7 +1917,7 @@ bool Position::is_ok(int* failedStep) const { // Is there more than 2 checkers? if (failedStep) (*failedStep)++; - if (debugCheckerCount && count_1s(st->checkersBB) > 2) + if (debugCheckerCount && count_1s(st->checkersBB) > 2) return false; // Bitboards OK? @@ -2015,7 +1986,7 @@ bool Position::is_ok(int* failedStep) const { if (debugPieceCounts) for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) - if (pieceCount[c][pt] != count_1s(pieces(pt, c))) + if (pieceCount[c][pt] != count_1s(pieces(pt, c))) return false; if (failedStep) (*failedStep)++;