From: Fabian Fichter Date: Sat, 9 Feb 2019 16:58:41 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=40ddb1a9913009c995404c03e5cbf72d185b08c1;p=fairystockfish.git Merge official-stockfish/master --- 40ddb1a9913009c995404c03e5cbf72d185b08c1 diff --cc src/position.cpp index 63b98dc,29a2b31..a5d4c44 --- a/src/position.cpp +++ b/src/position.cpp @@@ -309,131 -257,60 +305,131 @@@ Position& Position::set(const Variant* put_piece(Piece(idx), sq); ++sq; } + // Promoted shogi pieces + else if (token == '+') + { + ss >> token; + idx = piece_to_char().find(token); + unpromotedBoard[sq] = Piece(idx); + promotedPieces |= SquareBB[sq]; + put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq); + ++sq; + } + // Set flag for promoted pieces + else if (captures_to_hand() && !drop_loop() && token == '~') + promotedPieces |= SquareBB[sq - 1]; + // Stop before pieces in hand + else if (token == '[') + break; } + // Pieces in hand + if (!isspace(token)) + while ((ss >> token) && !isspace(token)) + { + if (token == ']') + continue; + else if ((idx = piece_to_char().find(token)) != string::npos) - add_to_hand(color_of(Piece(idx)), type_of(Piece(idx))); ++ add_to_hand(Piece(idx)); + } // 2. Active color ss >> token; sideToMove = (token == 'w' ? WHITE : BLACK); + // Invert side to move for SFEN + if (sfen) + sideToMove = ~sideToMove; ss >> token; - // 3. Castling availability. Compatible with 3 standards: Normal FEN standard, - // Shredder-FEN that uses the letters of the columns on which the rooks began - // the game instead of KQkq and also X-FEN standard that, in case of Chess960, - // if an inner rook is associated with the castling right, the castling tag is - // replaced by the file letter of the involved rook, as for the Shredder-FEN. - while ((ss >> token) && !isspace(token)) + // 3-4. Skip parsing castling and en passant flags if not present + st->epSquare = SQ_NONE; + if (!isdigit(ss.peek()) && !sfen) { - Square rsq; - Color c = islower(token) ? BLACK : WHITE; - Piece rook = make_piece(c, ROOK); + // 3. Castling availability. Compatible with 3 standards: Normal FEN standard, + // Shredder-FEN that uses the letters of the columns on which the rooks began + // the game instead of KQkq and also X-FEN standard that, in case of Chess960, + // if an inner rook is associated with the castling right, the castling tag is + // replaced by the file letter of the involved rook, as for the Shredder-FEN. + while ((ss >> token) && !isspace(token)) + { + Square rsq; + Color c = islower(token) ? BLACK : WHITE; + Piece rook = make_piece(c, ROOK); - token = char(toupper(token)); + token = char(toupper(token)); - if (token == 'K') - for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {} + if (token == 'K') + for (rsq = make_square(FILE_MAX, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; --rsq) {} - else if (token == 'Q') - for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {} + else if (token == 'Q') + for (rsq = make_square(FILE_A, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; ++rsq) {} - else if (token >= 'A' && token <= 'H') - rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1)); + else if (token >= 'A' && token <= 'A' + max_file()) + rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1, max_rank())); - else - continue; + else + continue; + + set_castling_right(c, rsq); + } + + // counting limit + if (counting_rule() && isdigit(ss.peek())) + ss >> st->countingLimit; - set_castling_right(c, rsq); + // 4. En passant square. Ignore if no pawn capture is possible + else if ( ((ss >> col) && (col >= 'a' && col <= 'a' + max_file())) + && ((ss >> row) && (row >= '1' && row <= '1' + max_rank()))) + { + st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); + + if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)) + || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))) + st->epSquare = SQ_NONE; + } } - // 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'), Rank(row - '1')); + // Check counter for nCheck + ss >> std::skipws >> token >> std::noskipws; - if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)) - || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))) - st->epSquare = SQ_NONE; + if (max_check_count() && ss.peek() == '+') + { + st->checksGiven[WHITE] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0)); + ss >> token >> token; + st->checksGiven[BLACK] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0)); } else - st->epSquare = SQ_NONE; + ss.putback(token); // 5-6. Halfmove clock and fullmove number - ss >> std::skipws >> st->rule50 >> gamePly; + if (sfen) + { + // Pieces in hand for SFEN + while ((ss >> token) && !isspace(token)) + { + if (token == '-') + continue; + else if ((idx = piece_to_char().find(token)) != string::npos) - add_to_hand(color_of(Piece(idx)), type_of(Piece(idx))); ++ add_to_hand(Piece(idx)); + } + // Move count is in ply for SFEN + ss >> std::skipws >> gamePly; + gamePly = std::max(gamePly - 1, 0); + } + else + { + ss >> std::skipws >> st->rule50 >> gamePly; + + // Convert from fullmove starting from 1 to gamePly starting from 0, + // handle also common incorrect FEN with fullmove = 0. + gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); + } - // Convert from fullmove starting from 1 to gamePly starting from 0, - // handle also common incorrect FEN with fullmove = 0. - gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); + // counting rules + if (st->countingLimit && st->rule50) + { + st->countingPly = st->rule50; + st->rule50 = 0; + } chess960 = isChess960; thisThread = th; @@@ -499,8 -377,7 +495,7 @@@ void Position::set_state(StateInfo* si si->key = si->materialKey = 0; si->pawnKey = Zobrist::noPawns; si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; - si->psq = SCORE_ZERO; - si->checkersBB = attackers_to(square(sideToMove)) & pieces(~sideToMove); + si->checkersBB = count(sideToMove) ? attackers_to(square(sideToMove), ~sideToMove) : 0; set_check_info(si); @@@ -1064,19 -778,6 +1050,18 @@@ void Position::do_move(Move m, StateInf // Update board and piece lists remove_piece(captured, capsq); + if (captures_to_hand()) + { + st->capturedpromoted = is_promoted(to); + Piece pieceToHand = !is_promoted(to) ? ~captured + : unpromotedCaptured ? ~unpromotedCaptured + : make_piece(~color_of(captured), PAWN); - add_to_hand(color_of(pieceToHand), type_of(pieceToHand)); - st->psq += PSQT::psq[pieceToHand][SQ_NONE]; ++ add_to_hand(pieceToHand); + k ^= Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1] + ^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]]; + promotedPieces -= to; + } + unpromotedBoard[to] = NO_PIECE; // Update material hash key and prefetch access to materialTable k ^= Zobrist::psq[captured][capsq]; @@@ -1192,55 -848,9 +1171,46 @@@ // Reset rule 50 draw counter st->rule50 = 0; } + else if (type_of(m) == PIECE_PROMOTION) + { + Piece promotion = make_piece(us, promoted_piece_type(type_of(pc))); + + remove_piece(pc, to); + put_piece(promotion, to); + promotedPieces |= to; + unpromotedBoard[to] = pc; + + // Update hash keys + k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to]; + st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1] + ^ Zobrist::psq[pc][pieceCount[pc]]; + - // Update incremental score - st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to]; - + // Update material + st->nonPawnMaterial[us] += PieceValue[MG][promotion] - PieceValue[MG][pc]; + } + else if (type_of(m) == PIECE_DEMOTION) + { + Piece demotion = unpromoted_piece_on(from); + + remove_piece(pc, to); + put_piece(demotion, to); + promotedPieces ^= from; + unpromotedBoard[from] = NO_PIECE; + + // Update hash keys + k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[demotion][to]; + st->materialKey ^= Zobrist::psq[demotion][pieceCount[demotion]-1] + ^ Zobrist::psq[pc][pieceCount[pc]]; + - // Update incremental score - st->psq += PSQT::psq[demotion][to] - PSQT::psq[pc][to]; - + // Update material + st->nonPawnMaterial[us] += PieceValue[MG][demotion] - PieceValue[MG][pc]; + } - // Update incremental scores - st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from]; - // Set capture piece st->capturedPiece = captured; + st->unpromotedCapturedPiece = captured ? unpromotedCaptured : NO_PIECE; + if (captures_to_hand() && !captured) + st->capturedpromoted = false; // Update the key with the final value st->key = k; @@@ -1365,17 -920,6 +1335,16 @@@ void Position::undo_move(Move m) } put_piece(st->capturedPiece, capsq); // Restore the captured piece + if (captures_to_hand()) + { - remove_from_hand(~color_of(st->capturedPiece), - !drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? type_of(st->unpromotedCapturedPiece) - : PAWN) - : type_of(st->capturedPiece)); ++ remove_from_hand(!drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? ~st->unpromotedCapturedPiece ++ : make_piece(~color_of(st->capturedPiece), PAWN)) ++ : ~st->capturedPiece); + if (!drop_loop() && st->capturedpromoted) + promotedPieces |= to; + } + if (st->unpromotedCapturedPiece) + unpromotedBoard[to] = st->unpromotedCapturedPiece; } } diff --cc src/position.h index b3686c2,18be2ec..e2b779e --- a/src/position.h +++ b/src/position.h @@@ -45,10 -43,6 +45,9 @@@ struct StateInfo int castlingRights; int rule50; int pliesFromNull; + int countingPly; + int countingLimit; + CheckCount checksGiven[COLOR_NB]; - Score psq; Square epSquare; // Not copied when making a move (will be recomputed anyhow) @@@ -262,327 -187,18 +261,332 @@@ private Bitboard castlingPath[CASTLING_RIGHT_NB]; int gamePly; Color sideToMove; + Score psq; Thread* thisThread; StateInfo* st; + + // variant-specific + const Variant* var; bool chess960; + int pieceCountInHand[COLOR_NB][PIECE_TYPE_NB]; + Bitboard promotedPieces; - void add_to_hand(Color c, PieceType pt); - void remove_from_hand(Color c, PieceType pt); ++ void add_to_hand(Piece pc); ++ void remove_from_hand(Piece pc); + void drop_piece(Piece pc_hand, Piece pc_drop, Square s); + void undrop_piece(Piece pc_hand, Piece pc_drop, Square s); }; + namespace PSQT { - extern Score psq[PIECE_NB][SQUARE_NB]; ++ extern Score psq[PIECE_NB][SQUARE_NB + 1]; + } + extern std::ostream& operator<<(std::ostream& os, const Position& pos); +inline const Variant* Position::variant() const { + assert(var != nullptr); + return var; +} + +inline Rank Position::max_rank() const { + assert(var != nullptr); + return var->maxRank; +} + +inline File Position::max_file() const { + assert(var != nullptr); + return var->maxFile; +} + +inline Bitboard Position::board_bb() const { + assert(var != nullptr); + return board_size_bb(var->maxFile, var->maxRank); +} + +inline const std::set& Position::piece_types() const { + assert(var != nullptr); + return var->pieceTypes; +} + +inline const std::string Position::piece_to_char() const { + assert(var != nullptr); + return var->pieceToChar; +} + +inline Rank Position::promotion_rank() const { + assert(var != nullptr); + return var->promotionRank; +} + +inline const std::set >& Position::promotion_piece_types() const { + assert(var != nullptr); + return var->promotionPieceTypes; +} + +inline bool Position::sittuyin_promotion() const { + assert(var != nullptr); + return var->sittuyinPromotion; +} + +inline PieceType Position::promoted_piece_type(PieceType pt) const { + assert(var != nullptr); + return var->promotedPieceType[pt]; +} + +inline bool Position::mandatory_piece_promotion() const { + assert(var != nullptr); + return var->mandatoryPiecePromotion; +} + +inline bool Position::piece_demotion() const { + assert(var != nullptr); + return var->pieceDemotion; +} + +inline bool Position::endgame_eval() const { + assert(var != nullptr); + return var->endgameEval; +} + +inline bool Position::double_step_enabled() const { + assert(var != nullptr); + return var->doubleStep; +} + +inline bool Position::first_rank_double_steps() const { + assert(var != nullptr); + return var->firstRankDoubleSteps; +} + +inline bool Position::castling_enabled() const { + assert(var != nullptr); + return var->castling; +} + +inline bool Position::castling_dropped_piece() const { + assert(var != nullptr); + return var->castlingDroppedPiece; +} + +inline File Position::castling_kingside_file() const { + assert(var != nullptr); + return var->castlingKingsideFile; +} + +inline File Position::castling_queenside_file() const { + assert(var != nullptr); + return var->castlingQueensideFile; +} + +inline bool Position::checking_permitted() const { + assert(var != nullptr); + return var->checking; +} + +inline bool Position::must_capture() const { + assert(var != nullptr); + return var->mustCapture; +} + +inline bool Position::must_drop() const { + assert(var != nullptr); + return var->mustDrop; +} + +inline bool Position::piece_drops() const { + assert(var != nullptr); + return var->pieceDrops; +} + +inline bool Position::drop_loop() const { + assert(var != nullptr); + return var->dropLoop; +} + +inline bool Position::captures_to_hand() const { + assert(var != nullptr); + return var->capturesToHand; +} + +inline bool Position::first_rank_drops() const { + assert(var != nullptr); + return var->firstRankDrops; +} + +inline bool Position::drop_on_top() const { + assert(var != nullptr); + return var->dropOnTop; +} + +inline Bitboard Position::drop_region(Color c) const { + assert(var != nullptr); + return c == WHITE ? var->whiteDropRegion : var->blackDropRegion; +} + +inline Bitboard Position::drop_region(Color c, PieceType pt) const { + Bitboard b = drop_region(c) & board_bb(); + + // Connect4-style drops + if (drop_on_top()) + b &= shift(pieces()) | Rank1BB; + // Pawns on back ranks + if (pt == PAWN) + { + b &= ~promotion_zone_bb(c, promotion_rank(), max_rank()); + if (!first_rank_drops()) + b &= ~rank_bb(relative_rank(c, RANK_1, max_rank())); + } + // Doubled shogi pawns + if (pt == SHOGI_PAWN && !shogi_doubled_pawn()) + for (File f = FILE_A; f <= max_file(); ++f) + if (file_bb(f) & pieces(c, pt)) + b &= ~file_bb(f); + // Sittuyin rook drops + if (pt == ROOK && sittuyin_rook_drop()) + b &= rank_bb(relative_rank(c, RANK_1, max_rank())); + + return b; +} + +inline bool Position::sittuyin_rook_drop() const { + assert(var != nullptr); + return var->sittuyinRookDrop; +} + +inline bool Position::drop_opposite_colored_bishop() const { + assert(var != nullptr); + return var->dropOppositeColoredBishop; +} + +inline bool Position::drop_promoted() const { + assert(var != nullptr); + return var->dropPromoted; +} + +inline bool Position::shogi_doubled_pawn() const { + assert(var != nullptr); + return var->shogiDoubledPawn; +} + +inline bool Position::immobility_illegal() const { + assert(var != nullptr); + return var->immobilityIllegal; +} + +inline int Position::n_move_rule() const { + assert(var != nullptr); + return var->nMoveRule; +} + +inline int Position::n_fold_rule() const { + assert(var != nullptr); + return var->nFoldRule; +} + +inline Value Position::stalemate_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->stalemateValue, ply); +} + +inline Value Position::checkmate_value(int ply) const { + assert(var != nullptr); + // Check for illegal mate by shogi pawn drop + if ( var->shogiPawnDropMateIllegal + && !(checkers() & ~pieces(SHOGI_PAWN)) + && !st->capturedPiece + && st->pliesFromNull > 0 + && (st->materialKey != st->previous->materialKey)) + { + return mate_in(ply); + } + // Check for shatar mate rule + if (var->shatarMateRule) + { + // Mate by knight is illegal + if (!(checkers() & ~pieces(KNIGHT))) + return mate_in(ply); + + StateInfo* stp = st; + while (stp->checkersBB) + { + // Return mate score if there is at least one shak in series of checks + if (stp->shak) + return convert_mate_value(var->checkmateValue, ply); + + if (stp->pliesFromNull < 2) + break; + + stp = stp->previous->previous; + } + // Niol + return VALUE_DRAW; + } + // Return mate value + return convert_mate_value(var->checkmateValue, ply); +} + +inline Value Position::bare_king_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->bareKingValue, ply); +} + +inline Value Position::extinction_value(int ply) const { + assert(var != nullptr); + return convert_mate_value(var->extinctionValue, ply); +} + +inline bool Position::bare_king_move() const { + assert(var != nullptr); + return var->bareKingMove; +} + +inline const std::set& Position::extinction_piece_types() const { + assert(var != nullptr); + return var->extinctionPieceTypes; +} + +inline PieceType Position::capture_the_flag_piece() const { + assert(var != nullptr); + return var->flagPiece; +} + +inline Bitboard Position::capture_the_flag(Color c) const { + assert(var != nullptr); + return c == WHITE ? var->whiteFlag : var->blackFlag; +} + +inline bool Position::flag_move() const { + assert(var != nullptr); + return var->flagMove; +} + +inline CheckCount Position::max_check_count() const { + assert(var != nullptr); + return var->maxCheckCount; +} + +inline int Position::connect_n() const { + assert(var != nullptr); + return var->connectN; +} + +inline CheckCount Position::checks_given(Color c) const { + return st->checksGiven[c]; +} + +inline CountingRule Position::counting_rule() const { + assert(var != nullptr); + return var->countingRule; +} + +inline bool Position::is_immediate_game_end() const { + Value result; + return is_immediate_game_end(result); +} + +inline bool Position::is_game_end(Value& result, int ply) const { + return is_immediate_game_end(result, ply) || is_optional_game_end(result, ply); +} + inline Color Position::side_to_move() const { return sideToMove; } @@@ -827,31 -428,4 +834,33 @@@ inline void Position::do_move(Move m, S do_move(m, newSt, gives_check(m)); } +inline int Position::count_in_hand(Color c, PieceType pt) const { + return pieceCountInHand[c][pt]; +} + - inline void Position::add_to_hand(Color c, PieceType pt) { - pieceCountInHand[c][pt]++; - pieceCountInHand[c][ALL_PIECES]++; ++inline void Position::add_to_hand(Piece pc) { ++ pieceCountInHand[color_of(pc)][type_of(pc)]++; ++ pieceCountInHand[color_of(pc)][ALL_PIECES]++; ++ psq += PSQT::psq[pc][SQ_NONE]; +} + - inline void Position::remove_from_hand(Color c, PieceType pt) { - pieceCountInHand[c][pt]--; - pieceCountInHand[c][ALL_PIECES]--; ++inline void Position::remove_from_hand(Piece pc) { ++ pieceCountInHand[color_of(pc)][type_of(pc)]--; ++ pieceCountInHand[color_of(pc)][ALL_PIECES]--; ++ psq -= PSQT::psq[pc][SQ_NONE]; +} + +inline void Position::drop_piece(Piece pc_hand, Piece pc_drop, Square s) { + assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]); + put_piece(pc_drop, s); - remove_from_hand(color_of(pc_hand), type_of(pc_hand)); ++ remove_from_hand(pc_hand); +} + +inline void Position::undrop_piece(Piece pc_hand, Piece pc_drop, Square s) { + remove_piece(pc_drop, s); + board[s] = NO_PIECE; - add_to_hand(color_of(pc_hand), type_of(pc_hand)); ++ add_to_hand(pc_hand); + assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]); +} + #endif // #ifndef POSITION_H_INCLUDED