From: Fabian Fichter Date: Sat, 19 Sep 2020 12:45:56 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=beb347c7db64f435f01065da1e8d126e3833f518;p=fairystockfish.git Merge official-stockfish/master No functional change. --- beb347c7db64f435f01065da1e8d126e3833f518 diff --cc src/bitboard.h index f77d290,1c59810..088edcd --- a/src/bitboard.h +++ b/src/bitboard.h @@@ -370,33 -276,20 +373,36 @@@ template<> inline int distance(Sq template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } -inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); } -inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } +inline int edge_distance(File f, File maxFile = FILE_H) { return std::min(f, File(maxFile - f)); } +inline int edge_distance(Rank r, Rank maxRank = RANK_8) { return std::min(r, Rank(maxRank - r)); } - /// Return the target square bitboard if we do not step off the board, empty otherwise + + /// safe_destination() returns the bitboard of target square for the given step + /// from the given square. If the step is off the board, returns empty bitboard. inline Bitboard safe_destination(Square s, int step) { Square to = Square(s + step); - return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); + return is_ok(to) && distance(s, to) <= 3 ? square_bb(to) : Bitboard(0); +} + +template +inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) { + + assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V + || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT); + const Magic& m = R == RIDER_ROOK_H ? RookMagicsH[s] + : R == RIDER_ROOK_V ? RookMagicsV[s] + : R == RIDER_CANNON_H ? CannonMagicsH[s] + : R == RIDER_CANNON_V ? CannonMagicsV[s] + : R == RIDER_HORSE ? HorseMagics[s] + : R == RIDER_ELEPHANT ? ElephantMagics[s] + : R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s] + : BishopMagics[s]; + return m.attacks[m.index(occupied)]; } + /// attacks_bb(Square) returns the pseudo attacks of the give piece type /// assuming an empty board. @@@ -405,9 -298,10 +411,10 @@@ inline Bitboard attacks_bb(Square s) assert((Pt != PAWN) && (is_ok(s))); - return PseudoAttacks[Pt][s]; + return PseudoAttacks[WHITE][Pt][s]; } + /// attacks_bb(Square, Bitboard) returns the attacks by the given piece /// assuming the board is occupied according to the passed Bitboard. /// Sliding piece attacks do not continue passed an occupied square. diff --cc src/evaluate.cpp index c133569,60ec9c7..9b1c26a --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -131,13 -126,11 +131,15 @@@ namespace S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; + // KingProximity contains a penalty according to distance from king + constexpr Score KingProximity = S(2, 4); + constexpr Score EndgameKingProximity = S(0, 10); + // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopKingProtector = S( 6, 9); constexpr Score BishopOnKingRing = S( 24, 0); + constexpr Score BishopOutpost = S( 30, 23); + constexpr Score BishopPawns = S( 3, 7); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@@ -286,8 -257,9 +288,9 @@@ // Evaluation::pieces() scores pieces of a given color and type + - template template - Score Evaluation::pieces() { + template template + Score Evaluation::pieces(PieceType Pt) { constexpr Color Them = ~Us; constexpr Direction Down = -pawn_push(Us); @@@ -451,43 -389,9 +454,44 @@@ return score; } + // Evaluation::hand() scores pieces of a given color and type in hand + template template + Score Evaluation::hand(PieceType pt) { + + constexpr Color Them = ~Us; + + Score score = SCORE_ZERO; + + if (pos.count_in_hand(Us, pt)) + { + Bitboard b = pos.drop_region(Us, pt) & ~pos.pieces() & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]); + if ((b & kingRing[Them]) && pt != SHOGI_PAWN) + { + kingAttackersCountInHand[Us] += pos.count_in_hand(Us, pt); + kingAttackersWeightInHand[Us] += KingAttackWeights[std::min(int(pt), QUEEN + 1)] * pos.count_in_hand(Us, pt); + kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); + } + Bitboard theirHalf = pos.board_bb() & ~forward_ranks_bb(Them, relative_rank(Them, Rank((pos.max_rank() - 1) / 2), pos.max_rank())); + mobility[Us] += DropMobility * popcount(b & theirHalf & ~attackedBy[Them][ALL_PIECES]); + if (pos.promoted_piece_type(pt) != NO_PIECE_TYPE && pos.drop_promoted()) + score += make_score(std::max(PieceValue[MG][pos.promoted_piece_type(pt)] - PieceValue[MG][pt], VALUE_ZERO), + std::max(PieceValue[EG][pos.promoted_piece_type(pt)] - PieceValue[EG][pt], VALUE_ZERO)) / 4 * pos.count_in_hand(Us, pt); + if (pos.enclosing_drop()) + mobility[Us] += make_score(500, 500) * popcount(b); + + // Reduce score if there is a deficit of gates + if (pos.seirawan_gating() && !pos.piece_drops() && pos.count_in_hand(Us, ALL_PIECES) > popcount(pos.gates(Us))) + score -= make_score(200, 900) / pos.count_in_hand(Us, ALL_PIECES) * (pos.count_in_hand(Us, ALL_PIECES) - popcount(pos.gates(Us))); + + if (pt == SHOGI_PAWN && !pos.shogi_doubled_pawn()) + score -= make_score(50, 20) * std::max(pos.count_with_hand(Us, SHOGI_PAWN) - pos.max_file() - 1, 0); + } + + return score; + } // Evaluation::king() assigns bonuses and penalties to a king of a given color + template template Score Evaluation::king() const { @@@ -946,147 -725,9 +951,147 @@@ } + // Evaluation::variant() computes variant-specific evaluation bonuses for a given side. + + template template + Score Evaluation::variant() const { + + constexpr Color Them = ~Us; + constexpr Direction Down = pawn_push(Them); + + Score score = SCORE_ZERO; + + // Capture the flag + if (pos.capture_the_flag(Us)) + { + PieceType ptCtf = pos.capture_the_flag_piece(); + Bitboard ctfPieces = pos.pieces(Us, ptCtf); + Bitboard ctfTargets = pos.capture_the_flag(Us) & pos.board_bb(); + Bitboard onHold = 0; + Bitboard onHold2 = 0; + Bitboard processed = 0; + Bitboard blocked = pos.pieces(Us, PAWN) | attackedBy[Them][ALL_PIECES]; + Bitboard doubleBlocked = attackedBy2[Them] + | (pos.pieces(Us, PAWN) & (shift(pos.pieces()) | attackedBy[Them][ALL_PIECES])) + | (pos.pieces(Them) & pe->pawn_attacks(Them)) + | (pawn_attacks_bb(pos.pieces(Them, PAWN) & pe->pawn_attacks(Them))); + Bitboard inaccessible = pos.pieces(Us, PAWN) & shift(pos.pieces(Them, PAWN)); + // Traverse all paths of the CTF pieces to the CTF targets. + // Put squares that are attacked or occupied on hold for one iteration. + for (int dist = 0; (ctfPieces || onHold || onHold2) && (ctfTargets & ~processed); dist++) + { + int wins = popcount(ctfTargets & ctfPieces); + if (wins) + score += make_score(4000, 4000) * wins / (wins + dist * dist); + Bitboard current = ctfPieces & ~ctfTargets; + processed |= ctfPieces; + ctfPieces = onHold & ~processed; + onHold = onHold2 & ~processed; + onHold2 = 0; + while (current) + { + Square s = pop_lsb(¤t); + Bitboard attacks = ( (PseudoAttacks[Us][ptCtf][s] & pos.pieces()) + | (PseudoMoves[Us][ptCtf][s] & ~pos.pieces())) & ~processed & pos.board_bb(); + ctfPieces |= attacks & ~blocked; + onHold |= attacks & ~doubleBlocked; + onHold2 |= attacks & ~inaccessible; + } + } + } + + // nCheck + if (pos.check_counting()) + { + int remainingChecks = pos.checks_remaining(Us); + assert(remainingChecks > 0); + score += make_score(3600, 1000) / (remainingChecks * remainingChecks); + } + + // Extinction + if (pos.extinction_value() != VALUE_NONE) + { + for (PieceType pt : pos.extinction_piece_types()) + if (pt != ALL_PIECES) + { + int denom = std::max(pos.count(Us, pt) - pos.extinction_piece_count(), 1); + if (pos.count(Them, pt) >= pos.extinction_opponent_piece_count() || pos.two_boards()) + score += make_score(1000000 / (500 + PieceValue[MG][pt]), + 1000000 / (500 + PieceValue[EG][pt])) / (denom * denom) + * (pos.extinction_value() / VALUE_MATE); + } + else if (pos.extinction_value() == VALUE_MATE) + score += make_score(pos.non_pawn_material(Us), pos.non_pawn_material(Us)) / pos.count(Us); + } + + // Connect-n + if (pos.connect_n() > 0) + { + for (Direction d : {NORTH, NORTH_EAST, EAST, SOUTH_EAST}) + { + // Find sufficiently large gaps + Bitboard b = pos.board_bb() & ~pos.pieces(Them); + for (int i = 1; i < pos.connect_n(); i++) + b &= shift(d, b); + // Count number of pieces per gap + while (b) + { + Square s = pop_lsb(&b); + int c = 0; + for (int j = 0; j < pos.connect_n(); j++) + if (pos.pieces(Us) & (s - j * d)) + c++; + score += make_score(200, 200) * c / (pos.connect_n() - c) / (pos.connect_n() - c); + } + } + } + + // Potential piece flips + if (pos.flip_enclosed_pieces()) + { + // Stable pieces + if (pos.flip_enclosed_pieces() == REVERSI) + { + Bitboard edges = (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) & pos.board_bb(); + Bitboard edgePieces = pos.pieces(Us) & edges; + while (edgePieces) + { + Bitboard connectedEdge = attacks_bb(Us, ROOK, pop_lsb(&edgePieces), ~(pos.pieces(Us) & edges)) & edges; + if (!more_than_one(connectedEdge & ~pos.pieces(Us))) + score += make_score(300, 300); + else if (!(connectedEdge & ~pos.pieces())) + score += make_score(200, 200); + } + } + + // Unstable + Bitboard unstable = 0; + Bitboard drops = pos.drop_region(Them, IMMOBILE_PIECE); + while (drops) + { + Square s = pop_lsb(&drops); + if (pos.flip_enclosed_pieces() == REVERSI) + { + Bitboard b = attacks_bb(Them, QUEEN, s, ~pos.pieces(Us)) & ~PseudoAttacks[Them][KING][s] & pos.pieces(Them); + while(b) + unstable |= between_bb(s, pop_lsb(&b)); + } + else + unstable |= PseudoAttacks[Them][KING][s] & pos.pieces(Us); + } + score -= make_score(200, 200) * popcount(unstable); + } + + if (T) + Trace::add(VARIANT, Us, score); + + return score; + } + + // Evaluation::winnable() adjusts the mg and eg score components based on the - // known attacking/defending status of the players. - // A single value is derived from the mg and eg values and returned. + // known attacking/defending status of the players. A single value is derived + // by interpolation from the mg and eg values and returned. template Value Evaluation::winnable(Score score) const { @@@ -1207,19 -836,14 +1212,18 @@@ initialize(); initialize(); - // Pieces should be evaluated first (populate attack tables). + // Pieces evaluated first (also populates attackedBy, attackedBy2). - // Note that the order of evaluation of the terms is left unspecified. - score += pieces() - pieces() - + pieces() - pieces() - + pieces() - pieces() - + pieces() - pieces(); + // For unused piece types, we still need to set attack bitboard to zero. + for (PieceType pt = KNIGHT; pt < KING; ++pt) + if (pt != SHOGI_PAWN) + score += pieces(pt) - pieces(pt); + + // Evaluate pieces in hand once attack tables are complete + if (pos.piece_drops() || pos.seirawan_gating()) + for (PieceType pt = PAWN; pt < KING; ++pt) + score += hand(pt) - hand(pt); - score += mobility[WHITE] - mobility[BLACK]; + score += (mobility[WHITE] - mobility[BLACK]) * (1 + pos.captures_to_hand() + pos.must_capture() + pos.check_counting()); // More complex interactions that require fully populated attack bitboards score += king< WHITE>() - king< BLACK>() diff --cc src/material.cpp index 8afe7cc,bb25d3c..be30d86 --- a/src/material.cpp +++ b/src/material.cpp @@@ -88,10 -79,12 +88,12 @@@ namespace && pos.count(~us) >= 1; } + /// imbalance() calculates the imbalance by comparing the piece count of each /// piece type for both colors. + template - int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { + int imbalance(const Position& pos, const int pieceCount[][PIECE_TYPE_NB]) { constexpr Color Them = ~Us; @@@ -100,13 -93,13 +102,13 @@@ // Second-degree polynomial material imbalance, by Tord Romstad for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1) { - if (!pieceCount[Us][pt1]) + if (!pieceCount[Us][pt1] || (pos.extinction_value() == VALUE_MATE && pt1 != KNIGHT)) continue; - int v = 0; + int v = QuadraticOurs[pt1][pt1] * pieceCount[Us][pt1]; - for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2) + for (int pt2 = NO_PIECE_TYPE; pt2 < pt1; ++pt2) - v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2] + v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2] * (pos.must_capture() && pt1 == KNIGHT && pt2 == PAWN ? 2 : pos.check_counting() && pt1 <= BISHOP ? 0 : 1) + QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2]; bonus += pieceCount[Us][pt1] * v; diff --cc src/position.cpp index 895d79b,471ef01..dc58e08 --- a/src/position.cpp +++ b/src/position.cpp @@@ -119,26 -97,15 +119,25 @@@ std::ostream& operator<<(std::ostream& // https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf // First and second hash functions for indexing the cuckoo tables +#ifdef LARGEBOARDS +inline int H1(Key h) { return h & 0x7fff; } +inline int H2(Key h) { return (h >> 16) & 0x7fff; } +#else inline int H1(Key h) { return h & 0x1fff; } inline int H2(Key h) { return (h >> 16) & 0x1fff; } +#endif // Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves +#ifdef LARGEBOARDS +Key cuckoo[65536]; +Move cuckooMove[65536]; +#else Key cuckoo[8192]; Move cuckooMove[8192]; +#endif - /// Position::init() initializes at startup the various arrays used to compute - /// hash keys. + /// Position::init() initializes at startup the various arrays used to compute hash keys void Position::init() { diff --cc src/psqt.cpp index d7f4a08,c5da978..e765f31 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@@ -104,117 -99,25 +104,117 @@@ constexpr Score PBonus[RANK_NB][FILE_NB #undef S -Score psq[PIECE_NB][SQUARE_NB]; - +Score psq[PIECE_NB][SQUARE_NB + 1]; - // init() initializes piece-square tables: the white halves of the tables are - // copied from Bonus[] adding the piece value, then the black halves of the - // tables are initialized by flipping and changing the sign of the white scores. + // PSQT::init() initializes piece-square tables: the white halves of the tables are + // copied from Bonus[] and PBonus[], adding the piece value, then the black halves of + // the tables are initialized by flipping and changing the sign of the white scores. -void init() { +void init(const Variant* v) { + + PieceType strongestPiece = NO_PIECE_TYPE; + for (PieceType pt : v->pieceTypes) + if (PieceValue[MG][pt] > PieceValue[MG][strongestPiece]) + strongestPiece = pt; + + Value maxPromotion = VALUE_ZERO; + for (PieceType pt : v->promotionPieceTypes) + maxPromotion = std::max(maxPromotion, PieceValue[EG][pt]); - for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING}) + for (PieceType pt = PAWN; pt <= KING; ++pt) { + Piece pc = make_piece(WHITE, pt); + Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); - for (Square s = SQ_A1; s <= SQ_H8; ++s) + // Consider promotion types in pawn score + if (pt == PAWN) + score -= make_score(0, (QueenValueEg - maxPromotion) / 100); + + // Scale slider piece values with board size + const PieceInfo* pi = pieceMap.find(pt)->second; + bool isSlider = pi->sliderQuiet.size() || pi->sliderCapture.size() || pi->hopperQuiet.size() || pi->hopperCapture.size(); + bool isPawn = !isSlider && pi->stepsQuiet.size() && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return d < SOUTH / 2; }); + bool isSlowLeaper = !isSlider && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return dist(d) > 1; }); + + if (isSlider) + { + constexpr int lc = 5; + constexpr int rm = 5; + constexpr int r0 = rm + RANK_8; + int r1 = rm + (v->maxRank + v->maxFile) / 2; + int leaper = pi->stepsQuiet.size() + pi->stepsCapture.size(); + int slider = pi->sliderQuiet.size() + pi->sliderCapture.size() + pi->hopperQuiet.size() + pi->hopperCapture.size(); + score = make_score(mg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider), + eg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider)); + } + + // Increase leapers' value in makpong + if (v->makpongRule) + { + if (std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](Direction d) { return dist(d) > 1; }) + && !pi->lameLeaper) + score = make_score(mg_value(score) * 4200 / (3500 + mg_value(score)), + eg_value(score) * 4700 / (3500 + mg_value(score))); + } + + // For drop variants, halve the piece values + if (v->capturesToHand) + score = make_score(mg_value(score) * 3500 / (7000 + mg_value(score)), + eg_value(score) * 3500 / (7000 + eg_value(score))); + else if (!v->checking) + score = make_score(mg_value(score) * 2000 / (3500 + mg_value(score)), + eg_value(score) * 2200 / (3500 + eg_value(score))); + else if (v->twoBoards) + score = make_score(mg_value(score) * 7000 / (7000 + mg_value(score)), + eg_value(score) * 7000 / (7000 + eg_value(score))); + else if (v->checkCounting) + score = make_score(mg_value(score) * (40000 + mg_value(score)) / 41000, + eg_value(score) * (30000 + eg_value(score)) / 31000); + else if (pt == strongestPiece) + score += make_score(std::max(QueenValueMg - PieceValue[MG][pt], VALUE_ZERO) / 20, + std::max(QueenValueEg - PieceValue[EG][pt], VALUE_ZERO) / 20); + + // For antichess variants, use negative piece values + if ( v->extinctionValue == VALUE_MATE + && v->extinctionPieceTypes.find(ALL_PIECES) != v->extinctionPieceTypes.end()) + score = -make_score(mg_value(score) / 8, eg_value(score) / 8 / (1 + !pi->sliderCapture.size())); + + // Determine pawn rank + std::istringstream ss(v->startFen); + unsigned char token; + Rank rc = v->maxRank; + Rank pawnRank = RANK_2; + while ((ss >> token) && !isspace(token)) + { + if (token == '/') + --rc; + else if (token == v->pieceToChar[PAWN] || token == v->pieceToChar[SHOGI_PAWN]) + pawnRank = rc; + } + + for (Square s = SQ_A1; s <= SQ_MAX; ++s) { - File f = File(edge_distance(file_of(s))); - psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] - : Bonus[pc][rank_of(s)][f]); - psq[~pc][flip_rank(s)] = -psq[pc][s]; + File f = std::max(File(edge_distance(file_of(s), v->maxFile)), FILE_A); + Rank r = rank_of(s); - psq[ pc][ s] = score + ( pt == PAWN ? PBonus[std::min(r, RANK_8)][std::min(file_of(s), FILE_H)] - : pt == KING ? KingBonus[Utility::clamp(Rank(r - pawnRank + 1), RANK_1, RANK_8)][std::min(f, FILE_D)] * (1 + v->capturesToHand) - : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)] - : pt == HORSE ? Bonus[KNIGHT][std::min(r, RANK_8)][std::min(f, FILE_D)] - : isSlider ? make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile - 1) - : isPawn ? make_score(5, 5) * (2 * f - v->maxFile) - : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2)); ++ psq[ pc][s] = score + ( pt == PAWN ? PBonus[std::min(r, RANK_8)][std::min(file_of(s), FILE_H)] ++ : pt == KING ? KingBonus[Utility::clamp(Rank(r - pawnRank + 1), RANK_1, RANK_8)][std::min(f, FILE_D)] * (1 + v->capturesToHand) ++ : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)] ++ : pt == HORSE ? Bonus[KNIGHT][std::min(r, RANK_8)][std::min(f, FILE_D)] ++ : isSlider ? make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile - 1) ++ : isPawn ? make_score(5, 5) * (2 * f - v->maxFile) ++ : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2)); + if (pt == SOLDIER && r < v->soldierPromotionRank) + psq[pc][s] -= score * (v->soldierPromotionRank - r) / (4 + f); + if (v->enclosingDrop == REVERSI) + { + if (f == FILE_A && (r == RANK_1 || r == v->maxRank)) + psq[pc][s] += make_score(1000, 1000); + } + psq[~pc][rank_of(s) <= v->maxRank ? flip_rank(s, v->maxRank) : s] = -psq[pc][s]; } + // pieces in pocket + psq[ pc][SQ_NONE] = score + make_score(35, 10) * (1 + !isSlider); + psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE]; } } diff --cc src/search.cpp index 74181bf,1e2980c..93ec016 --- a/src/search.cpp +++ b/src/search.cpp @@@ -555,35 -525,7 +555,35 @@@ void Thread::search() double totalTime = rootMoves.size() == 1 ? 0 : Time.optimum() * fallingEval * reduction * bestMoveInstability; + if (completedDepth >= 8 && rootPos.two_boards() && Options["Protocol"] == "xboard") + { + if (Limits.time[us]) + Partner.ptell("time " + std::to_string((Limits.time[us] - Time.elapsed()) / 10)); + if (Limits.time[~us]) + Partner.ptell("otim " + std::to_string(Limits.time[~us] / 10)); + if (!Partner.weDead && bestValue <= VALUE_MATED_IN_MAX_PLY) + { + Partner.ptell("dead"); + Partner.weDead = true; + } + else if (Partner.weDead && bestValue > VALUE_MATED_IN_MAX_PLY) + { + Partner.ptell("x"); + Partner.weDead = false; + } + else if (!Partner.weWin && bestValue >= VALUE_MATE_IN_MAX_PLY && Limits.time[~us] < Partner.time * 10) + { + Partner.ptell("sit"); + Partner.weWin = true; + } + else if (Partner.weWin && (bestValue < VALUE_MATE_IN_MAX_PLY || Limits.time[~us] > Partner.time * 10)) + { + Partner.ptell("x"); + Partner.weWin = false; + } + } + - // Stop the search if we have exceeded the totalTime, at least 1ms search. + // Stop the search if we have exceeded the totalTime, at least 1ms search if (Time.elapsed() > totalTime) { // If we are allowed to ponder do not stop the search now but @@@ -680,15 -622,12 +680,15 @@@ namespace if (!rootNode) { + Value variantResult; + if (pos.is_game_end(variantResult, ss->ply)) + return variantResult; + // Step 2. Check for aborted search and immediate draw if ( Threads.stop.load(std::memory_order_relaxed) - || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) - : value_draw(pos.this_thread()); + : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because @@@ -1662,10 -1573,10 +1664,10 @@@ moves_loop: // When in check, search st } } - // All legal moves have been searched. A special case: If we're in check + // All legal moves have been searched. A special case: if we're in check // and no legal moves were found, it is checkmate. if (ss->inCheck && bestValue == -VALUE_INFINITE) - return mated_in(ss->ply); // Plies to mate from the root + return pos.checkmate_value(ss->ply); // Plies to mate from the root tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, bestValue >= beta ? BOUND_LOWER : diff --cc src/timeman.cpp index 936f44a,546eadd..5e70a10 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@@ -29,12 -28,13 +29,13 @@@ TimeManagement Time; // Our global time management object - /// init() is called at the beginning of the search and calculates the bounds - /// of time allowed for the current game ply. We currently support: - // 1) x basetime (+z increment) - // 2) x moves in y seconds (+z increment) + + /// TimeManagement::init() is called at the beginning of the search and calculates + /// the bounds of time allowed for the current game ply. We currently support: + // 1) x basetime (+ z increment) + // 2) x moves in y seconds (+ z increment) -void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { +void TimeManagement::init(const Position& pos, Search::LimitsType& limits, Color us, int ply) { TimePoint moveOverhead = TimePoint(Options["Move Overhead"]); TimePoint slowMover = TimePoint(Options["Slow Mover"]); diff --cc src/types.h index 8c5c28d,0c512f5..8d7c7d7 --- a/src/types.h +++ b/src/types.h @@@ -649,16 -349,16 +649,16 @@@ constexpr Color operator~(Color c) return Color(c ^ BLACK); // Toggle color } - constexpr Square flip_rank(Square s, Rank maxRank = RANK_8) { -constexpr Square flip_rank(Square s) { // Swap A1 <-> A8 - return Square(s ^ SQ_A8); ++constexpr Square flip_rank(Square s, Rank maxRank = RANK_8) { // Swap A1 <-> A8 + return Square(s + NORTH * (maxRank - 2 * (s / NORTH))); } - constexpr Square flip_file(Square s, File maxFile = FILE_H) { -constexpr Square flip_file(Square s) { // Swap A1 <-> H1 - return Square(s ^ SQ_H1); ++constexpr Square flip_file(Square s, File maxFile = FILE_H) { // Swap A1 <-> H1 + return Square(s + maxFile - 2 * (s % NORTH)); } constexpr Piece operator~(Piece pc) { - return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece BLACK KNIGHT -> WHITE KNIGHT - return Piece(pc ^ 8); // Swap color of piece B_KNIGHT <-> W_KNIGHT ++ return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece B_KNIGHT <-> W_KNIGHT } constexpr CastlingRights operator&(Color c, CastlingRights cr) {