X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=ff0c4162a8f4e77303be946d4b68e171b304f6dc;hp=efac40b328a647414f64bb661da106fe023c59ea;hb=f3e0b32def471a698e855061aa8e728657248a0f;hpb=201e8d5f87a2bbd2d199b744cf8e92213c1e4bc4 diff --git a/src/position.cpp b/src/position.cpp index efac40b3..ff0c4162 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -17,12 +17,6 @@ along with this program. If not, see . */ - -//// -//// Includes -//// - -#include #include #include #include @@ -32,11 +26,9 @@ #include "bitcount.h" #include "movegen.h" -#include "movepick.h" #include "position.h" #include "psqtab.h" #include "rkiss.h" -#include "san.h" #include "tt.h" #include "ucioption.h" @@ -44,11 +36,6 @@ using std::string; using std::cout; using std::endl; - -//// -//// Position's static data definitions -//// - Key Position::zobrist[2][8][64]; Key Position::zobEp[64]; Key Position::zobCastle[16]; @@ -89,8 +76,6 @@ namespace { // Bonus for having the side to move (modified by Joona Kiiski) const Score TempoValue = make_score(48, 22); - bool isZero(char c) { return c == '0'; } - struct PieceLetters : public std::map { PieceLetters() { @@ -101,20 +86,23 @@ namespace { operator[]('B') = WB; operator[]('b') = BB; operator[]('N') = WN; operator[]('n') = BN; operator[]('P') = WP; operator[]('p') = BP; - operator[](' ') = PIECE_NONE; operator[]('.') = PIECE_NONE_DARK_SQ; + operator[](' ') = PIECE_NONE; + operator[]('.') = PIECE_NONE_DARK_SQ; } char from_piece(Piece p) const { - std::map::const_iterator it; - for (it = begin(); it != end(); ++it) - if (it->second == p) - return it->first; + std::map::const_iterator it; + for (it = begin(); it != end(); ++it) + if (it->second == p) + return it->first; - assert(false); - return 0; + assert(false); + return 0; } - } pieceLetters; + }; + + PieceLetters pieceLetters; } @@ -149,9 +137,9 @@ Position::Position(const Position& pos, int th) { nodes = 0; } -Position::Position(const string& fen, int th) { +Position::Position(const string& fen, bool isChess960, int th) { - from_fen(fen); + from_fen(fen, isChess960); threadID = th; } @@ -172,14 +160,14 @@ void Position::detach() { /// string. This function is not very robust - make sure that input FENs are /// correct (this is assumed to be the responsibility of the GUI). -void Position::from_fen(const string& fen) { +void Position::from_fen(const string& fen, bool c960) { /* A FEN string defines a particular position using only the ASCII character set. A FEN string contains six fields. The separator between fields is a space. The fields are: 1) Piece placement (from white's perspective). Each rank is described, starting with rank 8 and ending - with rank 1; within each rank, the contents of each square are described from file a through file h. + with rank 1; within each rank, the contents of each square are described from file A through file H. Following the Standard Algebraic Notation (SAN), each piece is identified by a single letter taken from the standard English names. White pieces are designated using upper-case letters ("PNBRQK") while Black take lowercase ("pnbrqk"). Blank squares are noted using digits 1 through 8 (the number @@ -202,32 +190,26 @@ void Position::from_fen(const string& fen) { */ char token; + int hmc, fmn; std::istringstream ss(fen); - Rank rank = RANK_8; - File file = FILE_A; + Square sq = SQ_A8; clear(); // 1. Piece placement field while (ss.get(token) && token != ' ') { - if (isdigit(token)) + if (pieceLetters.find(token) != pieceLetters.end()) { - file += File(token - '0'); // Skip the given number of files - continue; + put_piece(pieceLetters[token], sq); + sq++; } + else if (isdigit(token)) + sq += Square(token - '0'); // Skip the given number of files else if (token == '/') - { - file = FILE_A; - rank--; - continue; - } - - if (pieceLetters.find(token) == pieceLetters.end()) + sq -= SQ_A3; // Jump back of 2 rows + else goto incorrect_fen; - - put_piece(pieceLetters[token], make_square(file, rank)); - file++; } // 2. Active color @@ -241,27 +223,29 @@ void Position::from_fen(const string& fen) { // 3. Castling availability while (ss.get(token) && token != ' ') - { - if (token == '-') - continue; - if (!set_castling_rights(token)) goto incorrect_fen; - } - // 4. En passant square -- ignore if no capture is possible + // 4. En passant square char col, row; if ( (ss.get(col) && (col >= 'a' && col <= 'h')) && (ss.get(row) && (row == '3' || row == '6'))) { - Square fenEpSquare = make_square(file_from_char(col), rank_from_char(row)); - Color them = opposite_color(sideToMove); + st->epSquare = make_square(file_from_char(col), rank_from_char(row)); - if (attacks_from(fenEpSquare, them) & pieces(PAWN, sideToMove)) - st->epSquare = fenEpSquare; + // Ignore if no capture is possible + Color them = opposite_color(sideToMove); + if (!(attacks_from(st->epSquare, them) & pieces(PAWN, sideToMove))) + st->epSquare = SQ_NONE; } - // 5-6. Halfmove clock and fullmove number are not parsed + // 5. Halfmove clock + if (ss >> hmc) + st->rule50 = hmc; + + // 6. Fullmove number + if (ss >> fmn) + startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK); // Various initialisations castleRightsMask[make_square(initialKFile, RANK_1)] ^= WHITE_OO | WHITE_OOO; @@ -271,10 +255,7 @@ 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; - + isChess960 = c960; find_checkers(); st->key = compute_key(); @@ -341,7 +322,8 @@ bool Position::set_castling_rights(char token) { initialKRFile = rookFile; } } - else return false; + else + return token == '-'; return true; } @@ -356,7 +338,7 @@ const string Position::to_fen() const { Square sq; char emptyCnt = '0'; - for (Rank rank = RANK_8; rank >= RANK_1; rank--) + for (Rank rank = RANK_8; rank >= RANK_1; rank--, fen += '/') { for (File file = FILE_A; file <= FILE_H; file++) { @@ -364,19 +346,23 @@ const string Position::to_fen() const { if (square_is_occupied(sq)) { - fen += emptyCnt; + if (emptyCnt != '0') + { + fen += emptyCnt; + emptyCnt = '0'; + } fen += pieceLetters.from_piece(piece_on(sq)); - emptyCnt = '0'; } else emptyCnt++; } - fen += emptyCnt; - fen += '/'; - emptyCnt = '0'; + + if (emptyCnt != '0') + { + fen += emptyCnt; + emptyCnt = '0'; + } } - fen.erase(std::remove_if(fen.begin(), fen.end(), isZero), fen.end()); - fen.erase(--fen.end()); fen += (sideToMove == WHITE ? " w " : " b "); if (st->castleRights != CASTLES_NONE) @@ -406,14 +392,6 @@ const string Position::to_fen() const { void Position::print(Move move) const { const char* dottedLine = "\n+---+---+---+---+---+---+---+---+\n"; - static bool requestPending = false; - - // Check for reentrancy, as example when called from inside - // MovePicker that is used also here in move_to_san() - if (requestPending) - return; - - requestPending = true; if (move) { @@ -428,17 +406,16 @@ void Position::print(Move move) const { for (File file = FILE_A; file <= FILE_H; file++) { Square sq = make_square(file, rank); - char c = (color_of_piece_on(sq) == BLACK ? '=' : ' '); Piece piece = piece_on(sq); if (piece == PIECE_NONE && square_color(sq) == DARK) piece = PIECE_NONE_DARK_SQ; + char c = (color_of_piece_on(sq) == BLACK ? '=' : ' '); cout << c << pieceLetters.from_piece(piece) << c << '|'; } } cout << dottedLine << "Fen is: " << to_fen() << "\nKey is: " << st->key << endl; - requestPending = false; } @@ -524,7 +501,7 @@ Bitboard Position::attacks_from(Piece p, Square s) const { case WB: case BB: return attacks_from(s); case WR: case BR: return attacks_from(s); case WQ: case BQ: return attacks_from(s); - default: return StepAttackBB[p][s]; + default: return NonSlidingAttacksBB[p][s]; } } @@ -537,7 +514,7 @@ Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) { case WB: case BB: return bishop_attacks_bb(s, occ); case WR: case BR: return rook_attacks_bb(s, occ); case WQ: case BQ: return bishop_attacks_bb(s, occ) | rook_attacks_bb(s, occ); - default: return StepAttackBB[p][s]; + default: return NonSlidingAttacksBB[p][s]; } } @@ -635,9 +612,9 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // 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. - return ( !pinned - || !bit_is_set(pinned, from) - || (direction_between_squares(from, king_square(us)) == direction_between_squares(move_to(m), king_square(us)))); + return !pinned + || !bit_is_set(pinned, from) + || squares_aligned(from, move_to(m), king_square(us)); } @@ -695,7 +672,7 @@ bool Position::move_is_check(Move m, const CheckInfo& ci) const { { // For pawn and king moves we need to verify also direction if ( (pt != PAWN && pt != KING) - ||(direction_between_squares(from, ci.ksq) != direction_between_squares(to, ci.ksq))) + || !squares_aligned(from, to, ci.ksq)) return true; } @@ -766,6 +743,29 @@ bool Position::move_is_check(Move m, const CheckInfo& ci) const { } +/// Position::do_setup_move() makes a permanent move on the board. +/// It should be used when setting up a position on board. +/// You can't undo the move. + +void Position::do_setup_move(Move m) { + + StateInfo newSt; + + do_move(m, newSt); + + // Reset "game ply" in case we made a non-reversible move. + // "game ply" is used for repetition detection. + 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 inside pos before it disappears. + detach(); +} + /// Position::do_move() makes a move, and saves all information necessary /// to a StateInfo object. The move is assumed to be legal. /// Pseudo-legal moves should be filtered out before this function is called. @@ -780,6 +780,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI assert(is_ok()); assert(move_is_ok(m)); + assert(&newSt != st); nodes++; Key key = st->key; @@ -795,8 +796,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI Value npMaterial[2]; }; - if (&newSt != st) - memcpy(&newSt, st, sizeof(ReducedStateInfo)); + memcpy(&newSt, st, sizeof(ReducedStateInfo)); newSt.previous = st; st = &newSt; @@ -1533,22 +1533,6 @@ void Position::clear() { } -/// Position::reset_game_ply() simply sets gamePly to 0. It is used from the -/// UCI interface code, whenever a non-reversible move is made in a -/// 'position fen moves m1 m2 ...' command. This makes it possible -/// for the program to handle games of arbitrary length, as long as the GUI -/// handles draws by the 50 move rule correctly. - -void Position::reset_game_ply() { - - st->gamePly = 0; -} - -void Position::inc_startpos_ply_counter() { - - startPosPlyCounter++; -} - /// Position::put_piece() puts a piece on the given square of the board, /// updating the board array, pieces list, bitboards, and piece counts. @@ -1683,7 +1667,7 @@ bool Position::is_draw() const { return true; // Draw by the 50 moves rule? - if (st->rule50 > 99 && (st->rule50 > 100 || !is_mate())) + if (st->rule50 > 99 && !is_mate()) return true; // Draw by repetition? @@ -1701,7 +1685,7 @@ bool Position::is_draw() const { bool Position::is_mate() const { MoveStack moves[MOVES_MAX]; - return is_check() && generate_moves(*this, moves) == moves; + return is_check() && generate(*this, moves) == moves; } @@ -1722,8 +1706,8 @@ bool Position::has_mate_threat() { do_null_move(st1); // Then generate pseudo-legal moves that could give check - last = generate_non_capture_checks(*this, mlist); - last = generate_captures(*this, last); + last = generate(*this, mlist); + last = generate(*this, last); // Loop through the moves, and see if one of them gives mate Bitboard pinned = pinned_pieces(sideToMove);