X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=1364c7ed7d2cb9c7b3453fd02d578d9d528947e0;hp=7ee63b22aa6cdf16076e75214302ac6e77acb9d5;hb=03cfd94414b49489cae12abfd6c39f7fbb53515a;hpb=5ed0a60203c1c93c5630894b4eca1f801241fe27 diff --git a/src/position.cpp b/src/position.cpp index 7ee63b22..1364c7ed 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2009 Marco Costalba + Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,8 +44,6 @@ using std::string; //// Variables //// -int Position::castleRightsMask[64]; - Key Position::zobrist[2][8][64]; Key Position::zobEp[64]; Key Position::zobCastle[16]; @@ -76,15 +74,39 @@ CheckInfo::CheckInfo(const Position& pos) { checkSq[KING] = EmptyBoardBB; } + +/// Position c'tors. Here we always create a slower but safer copy of +/// the original position or the FEN string, we want the new born Position +/// object do not depend on any external data. Instead if we know what we +/// are doing and we need speed we can create a position with default +/// c'tor Position() and then use just fast_copy(). + +Position::Position() {} + Position::Position(const Position& pos) { - copy(pos); + + memcpy(this, &pos, sizeof(Position)); + detach(); // Always detach() in copy c'tor to avoid surprises } Position::Position(const string& fen) { + from_fen(fen); } +/// Position::detach() copies the content of the current state and castling +/// masks inside the position itself. This is needed when the st pointee could +/// become stale, as example because the caller is about to going out of scope. + +void Position::detach() { + + startState = *st; + st = &startState; + st->previous = NULL; // as a safe guard +} + + /// Position::from_fen() initializes the position object with the given FEN /// string. This function is not very robust - make sure that input FENs are /// correct (this is assumed to be the responsibility of the GUI). @@ -143,61 +165,61 @@ void Position::from_fen(const string& fen) { } i++; - while(strchr("KQkqabcdefghABCDEFGH-", fen[i])) { - if (fen[i] == '-') - { - i++; - break; - } - else if(fen[i] == 'K') allow_oo(WHITE); - else if(fen[i] == 'Q') allow_ooo(WHITE); - else if(fen[i] == 'k') allow_oo(BLACK); - else if(fen[i] == 'q') allow_ooo(BLACK); - else if(fen[i] >= 'A' && fen[i] <= 'H') { - File rookFile, kingFile = FILE_NONE; - for(Square square = SQ_B1; square <= SQ_G1; square++) - if(piece_on(square) == WK) - kingFile = square_file(square); - if(kingFile == FILE_NONE) { - std::cout << "Error in FEN at character " << i << std::endl; - return; - } - initialKFile = kingFile; - rookFile = File(fen[i] - 'A') + FILE_A; - if(rookFile < initialKFile) { - allow_ooo(WHITE); - initialQRFile = rookFile; - } - else { - allow_oo(WHITE); - initialKRFile = rookFile; + while (strchr("KQkqabcdefghABCDEFGH-", fen[i])) { + if (fen[i] == '-') + { + i++; + break; } - } - else if(fen[i] >= 'a' && fen[i] <= 'h') { - File rookFile, kingFile = FILE_NONE; - for(Square square = SQ_B8; square <= SQ_G8; square++) - if(piece_on(square) == BK) - kingFile = square_file(square); - if(kingFile == FILE_NONE) { - std::cout << "Error in FEN at character " << i << std::endl; - return; + else if (fen[i] == 'K') allow_oo(WHITE); + else if (fen[i] == 'Q') allow_ooo(WHITE); + else if (fen[i] == 'k') allow_oo(BLACK); + else if (fen[i] == 'q') allow_ooo(BLACK); + else if (fen[i] >= 'A' && fen[i] <= 'H') { + File rookFile, kingFile = FILE_NONE; + for (Square square = SQ_B1; square <= SQ_G1; square++) + if (piece_on(square) == WK) + kingFile = square_file(square); + if (kingFile == FILE_NONE) { + std::cout << "Error in FEN at character " << i << std::endl; + return; + } + initialKFile = kingFile; + rookFile = File(fen[i] - 'A') + FILE_A; + if (rookFile < initialKFile) { + allow_ooo(WHITE); + initialQRFile = rookFile; + } + else { + allow_oo(WHITE); + initialKRFile = rookFile; + } } - initialKFile = kingFile; - rookFile = File(fen[i] - 'a') + FILE_A; - if(rookFile < initialKFile) { - allow_ooo(BLACK); - initialQRFile = rookFile; + else if (fen[i] >= 'a' && fen[i] <= 'h') { + File rookFile, kingFile = FILE_NONE; + for (Square square = SQ_B8; square <= SQ_G8; square++) + if (piece_on(square) == BK) + kingFile = square_file(square); + if (kingFile == FILE_NONE) { + std::cout << "Error in FEN at character " << i << std::endl; + return; + } + initialKFile = kingFile; + rookFile = File(fen[i] - 'a') + FILE_A; + if (rookFile < initialKFile) { + allow_ooo(BLACK); + initialQRFile = rookFile; + } + else { + allow_oo(BLACK); + initialKRFile = rookFile; + } } else { - allow_oo(BLACK); - initialKRFile = rookFile; + std::cout << "Error in FEN at character " << i << std::endl; + return; } - } - else { - std::cout << "Error in FEN at character " << i << std::endl; - return; - } - i++; + i++; } // Skip blanks @@ -277,16 +299,16 @@ const string Position::to_fen() const { if (can_castle_queenside(WHITE)) fen += 'Q'; if (can_castle_kingside(BLACK)) fen += 'k'; if (can_castle_queenside(BLACK)) fen += 'q'; - } + } else { - if (can_castle_kingside(WHITE)) - fen += toupper(file_to_char(initialKRFile)); - if (can_castle_queenside(WHITE)) - fen += toupper(file_to_char(initialQRFile)); - if (can_castle_kingside(BLACK)) + if (can_castle_kingside(WHITE)) + fen += char(toupper(file_to_char(initialKRFile))); + if (can_castle_queenside(WHITE)) + fen += char(toupper(file_to_char(initialQRFile))); + if (can_castle_kingside(BLACK)) fen += file_to_char(initialKRFile); - if (can_castle_queenside(BLACK)) + if (can_castle_queenside(BLACK)) fen += file_to_char(initialQRFile); } } else @@ -319,8 +341,9 @@ void Position::print(Move m) const { std::cout << std::endl; if (m != MOVE_NONE) { + Position p(*this); string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : ""); - std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl; + std::cout << "Move is: " << col << move_to_san(p, m) << std::endl; } for (Rank rank = RANK_8; rank >= RANK_1; rank--) { @@ -345,15 +368,6 @@ void Position::print(Move m) const { } -/// Position::copy() creates a copy of the input position. - -void Position::copy(const Position& pos) { - - memcpy(this, &pos, sizeof(Position)); - saveState(); // detach and copy state info -} - - /// Position:hidden_checkers<>() returns a bitboard of all pinned (against the /// king) pieces for the given color and for the given pinner type. Or, when /// template parameter FindPinned is false, the pieces of the given color @@ -683,7 +697,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI assert(is_ok()); assert(move_is_ok(m)); - Bitboard key = st->key; + Key key = st->key; // Copy some fields of old state to our new StateInfo object except the // ones which are recalculated from scratch anyway, then switch our state @@ -814,13 +828,13 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI set_bit(&(byTypeBB[promotion]), to); board[to] = piece_of_color_and_type(us, promotion); + // Update piece counts + pieceCount[us][promotion]++; + pieceCount[us][PAWN]--; + // Update material key st->materialKey ^= zobMaterial[us][PAWN][pieceCount[us][PAWN]]; - st->materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]+1]; - - // Update piece counts - pieceCount[us][PAWN]--; - pieceCount[us][promotion]++; + st->materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]-1]; // Update piece lists, move the last pawn at index[to] position // and shrink the list. Add a new promotion piece to the list. @@ -882,7 +896,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI /// Position::do_capture_move() is a private method used to update captured /// piece info. It is called from the main Position::do_move function. -void Position::do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep) { +void Position::do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep) { assert(capture != KING); @@ -918,12 +932,12 @@ void Position::do_capture_move(Bitboard& key, PieceType capture, Color them, Squ else st->npMaterial[them] -= piece_value_midgame(capture); - // Update material hash key - st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]]; - // Update piece count pieceCount[them][capture]--; + // Update material hash key + st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]]; + // Update piece list, move the last piece at index[capsq] position // // WARNING: This is a not perfectly revresible operation. When we @@ -1443,19 +1457,6 @@ int Position::see(Square from, Square to) const { } -/// Position::saveState() copies the content of the current state -/// inside startState and makes st point to it. This is needed -/// when the st pointee could become stale, as example because -/// the caller is about to going out of scope. - -void Position::saveState() { - - startState = *st; - st = &startState; - st->previous = NULL; // as a safe guard -} - - /// Position::clear() erases the position object to a pristine state, with an /// empty board, white to move, and no castling rights. @@ -1574,7 +1575,7 @@ Key Position::compute_pawn_key() const { for (Color c = WHITE; c <= BLACK; c++) { b = pieces(PAWN, c); - while(b) + while (b) { s = pop_1st_bit(&b); result ^= zobrist[c][PAWN][s]; @@ -1597,7 +1598,7 @@ Key Position::compute_material_key() const { for (PieceType pt = PAWN; pt <= QUEEN; pt++) { int count = piece_count(c, pt); - for (int i = 0; i <= count; i++) + for (int i = 0; i < count; i++) result ^= zobMaterial[c][pt][i]; } return result; @@ -1618,7 +1619,7 @@ Score Position::compute_value() const { for (PieceType pt = PAWN; pt <= KING; pt++) { b = pieces(pt, c); - while(b) + while (b) { s = pop_1st_bit(&b); assert(piece_on(s) == piece_of_color_and_type(c, pt)); @@ -1657,6 +1658,7 @@ 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 { @@ -1670,7 +1672,7 @@ bool Position::is_draw() const { return true; // Draw by repetition? - for (int i = 2; i < Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2) + for (int i = 4; i <= Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2) if (history[gamePly - i] == st->key) return true; @@ -1753,10 +1755,10 @@ void Position::init_zobrist() { for (int i = 0; i < 2; i++) for (int j = 0; j < 8; j++) - for (int k = 0; k < 16; k++) - zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL); + for (int k = 0; k < 8; k++) + zobMaterial[i][j][k] = Key(genrand_int64()); - for (int i = 0; i < 16; i++) + for (int i = 0; i < 8; i++) zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL); zobExclusion = genrand_int64(); @@ -1990,9 +1992,9 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) (*failedStep)++; if (debugPieceList) { - for(Color c = WHITE; c <= BLACK; c++) - for(PieceType pt = PAWN; pt <= KING; pt++) - for(int i = 0; i < pieceCount[c][pt]; i++) + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= KING; pt++) + for (int i = 0; i < pieceCount[c][pt]; i++) { if (piece_on(piece_list(c, pt, i)) != piece_of_color_and_type(c, pt)) return false; @@ -2004,20 +2006,20 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) (*failedStep)++; if (debugCastleSquares) { - for (Color c = WHITE; c <= BLACK; c++) { - if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != piece_of_color_and_type(c, ROOK)) - return false; - if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != piece_of_color_and_type(c, 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; + for (Color c = WHITE; c <= BLACK; c++) { + if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != piece_of_color_and_type(c, ROOK)) + return false; + if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != piece_of_color_and_type(c, 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;