diff --git a/AUTHORS b/AUTHORS index 7e7b4868..8f532344 100644 --- a/AUTHORS +++ b/AUTHORS @@ -25,6 +25,7 @@ Bill Henry (VoyagerOne) braich Brian Sheppard (SapphireBrand) Bryan Cross (crossbr) +Bujun Guo (noobpwnftw) Chris Cain (ceebo) Dan Schmidt Dariusz Orzechowski @@ -85,10 +86,10 @@ Michel Van den Bergh (vdbergh) Mikael Bäckman (mbootsector) Mike Whiteley (protonspring) Miroslav Fontán (Hexik) +Moez Jellouli (MJZ1977) Mohammed Li (tthsqe12) Nathan Rugg (nmrugg) Nicklas Persson (NicklasPersson) -noobpwnftw Oskar Werkelin Ahlin Pablo Vazquez Pascal Romaret diff --git a/src/Makefile b/src/Makefile index a1cf2ced..b5f8b205 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,7 +22,11 @@ ### ========================================================================== ### Executable name +ifeq ($(COMP),mingw) +EXE = stockfish.exe +else EXE = stockfish +endif ### Installation dir definitions PREFIX = /usr/local @@ -262,7 +266,7 @@ ifneq ($(comp),mingw) endif ### 3.2.1 Debugging -CXXFLAGS += -DANTI -DATOMIC -DBUGHOUSE -DCRAZYHOUSE -DDISPLACEDGRID -DEXTINCTION -DGRID -DHORDE -DKOTH -DLOOP -DLOSERS -DRACE -DSKILL -DSLIPPEDGRID -DSUICIDE -DTHREECHECK -DTWOKINGS -DTWOKINGSSYMMETRIC -DUSELONGESTPV +CXXFLAGS += -DANTI -DATOMIC -DBUGHOUSE -DCRAZYHOUSE -DDISPLACEDGRID -DEXTINCTION -DGRID -DHORDE -DKOTH -DLOOP -DLOSERS -DRACE -DSLIPPEDGRID -DSUICIDE -DTHREECHECK -DTWOKINGS -DTWOKINGSSYMMETRIC -DUSELONGESTPV ifneq (,$(filter -DBUGHOUSE,$(CXXFLAGS))) ifeq (,$(filter -DCRAZYHOUSE,$(CXXFLAGS))) $(error Crazyhouse (-DCRAZYHOUSE) is required for subvariant bughouse chess) @@ -468,7 +472,7 @@ clean: objclean profileclean # clean binaries and objects objclean: - @rm -f $(EXE) $(EXE).exe *.o ./syzygy/*.o + @rm -f $(EXE) *.o ./syzygy/*.o # clean auxiliary profiling files profileclean: diff --git a/src/bitboard.h b/src/bitboard.h index d095ae5a..cf02c6d6 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -112,14 +112,17 @@ extern Magic BishopMagics[SQUARE_NB]; /// whether a given bit is set in a bitboard, and for setting and clearing bits. inline Bitboard operator&(Bitboard b, Square s) { + assert(s >= SQ_A1 && s <= SQ_H8); return b & SquareBB[s]; } inline Bitboard operator|(Bitboard b, Square s) { + assert(s >= SQ_A1 && s <= SQ_H8); return b | SquareBB[s]; } inline Bitboard operator^(Bitboard b, Square s) { + assert(s >= SQ_A1 && s <= SQ_H8); return b ^ SquareBB[s]; } @@ -128,10 +131,12 @@ inline Bitboard operator-(Bitboard b, Square s) { } inline Bitboard& operator|=(Bitboard& b, Square s) { + assert(s >= SQ_A1 && s <= SQ_H8); return b |= SquareBB[s]; } inline Bitboard& operator^=(Bitboard& b, Square s) { + assert(s >= SQ_A1 && s <= SQ_H8); return b ^= SquareBB[s]; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 778cd99e..4bcd91a6 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -452,11 +452,11 @@ namespace { constexpr Score ThreatByKing[] = { S(3, 65), S(9, 145) }; #ifdef ATOMIC - const Score ThreatByBlast = S(80, 80); + constexpr Score ThreatByBlast = S(80, 80); #endif #ifdef THREECHECK - const Score ChecksGivenBonus[CHECKS_NB] = { + constexpr Score ChecksGivenBonus[CHECKS_NB] = { S(0, 0), S(444, 181), S(2425, 603), @@ -465,16 +465,16 @@ namespace { #endif #ifdef KOTH - const Score KothDistanceBonus[6] = { + constexpr Score KothDistanceBonus[6] = { S(1949, 1934), S(454, 364), S(151, 158), S(75, 85), S(42, 49), S(0, 0) }; - const Score KothSafeCenter = S(163, 207); + constexpr Score KothSafeCenter = S(163, 207); #endif #ifdef ANTI - const Score PieceCountAnti = S(119, 123); - const Score ThreatsAnti[] = { S(192, 203), S(411, 322) }; - const Score AttacksAnti[2][2][PIECE_TYPE_NB] = { + constexpr Score PieceCountAnti = S(119, 123); + constexpr Score ThreatsAnti[] = { S(192, 203), S(411, 322) }; + constexpr Score AttacksAnti[2][2][PIECE_TYPE_NB] = { { { S( 30, 141), S( 26, 94), S(161, 105), S( 70, 123), S( 61, 72), S( 78, 12), S(139, 115) }, { S( 56, 89), S( 82, 107), S(114, 93), S(110, 115), S(188, 112), S( 73, 59), S(122, 59) } @@ -487,8 +487,8 @@ namespace { #endif #ifdef LOSERS - const Score ThreatsLosers[] = { S(216, 279), S(441, 341) }; - const Score AttacksLosers[2][2][PIECE_TYPE_NB] = { + constexpr Score ThreatsLosers[] = { S(216, 279), S(441, 341) }; + constexpr Score AttacksLosers[2][2][PIECE_TYPE_NB] = { { { S( 27, 140), S( 23, 95), S(160, 112), S( 78, 129), S( 65, 75), S( 70, 13), S(146, 123) }, { S( 58, 82), S( 80, 112), S(124, 87), S(103, 110), S(185, 107), S( 72, 60), S(126, 62) } @@ -501,15 +501,15 @@ namespace { #endif #ifdef CRAZYHOUSE - const int KingDangerInHand[PIECE_TYPE_NB] = { + constexpr int KingDangerInHand[PIECE_TYPE_NB] = { 79, 16, 200, 61, 138, 152 }; - const Score DropMobilityBonus = S(30, 30); + constexpr Score DropMobilityBonus = S(30, 30); #endif #ifdef RACE // Bonus for distance of king from 8th rank - const Score KingRaceBonus[RANK_NB] = { + constexpr Score KingRaceBonus[RANK_NB] = { S(14282, 14493), S(6369, 5378), S(4224, 3557), S(2633, 2219), S( 1614, 1456), S( 975, 885), S( 528, 502), S( 0, 0) }; @@ -568,7 +568,7 @@ namespace { constexpr Score KingProtector[] = { S(3, 5), S(4, 3), S(3, 0), S(1, -1) }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 8, 12); + constexpr Score BishopPawns = S( 3, 5); constexpr Score CloseEnemies[VARIANT_NB] = { S( 7, 0), #ifdef ANTI @@ -700,7 +700,7 @@ namespace { // Find our pawns that are blocked or on the first two ranks Bitboard b = pos.pieces(Us, PAWN) & (shift(pos.pieces()) | LowRanks); - // Squares occupied by those pawns, by our king, or controlled by enemy pawns + // Squares occupied by those pawns, by our king or queen, or controlled by enemy pawns // are excluded from the mobility area. #ifdef ANTI if (pos.is_anti()) @@ -712,7 +712,7 @@ namespace { mobilityArea[Us] = ~(b | pe->pawn_attacks(Them)); else #endif - mobilityArea[Us] = ~(b | pos.square(Us) | pe->pawn_attacks(Them)); + mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); // Initialise attackedBy bitboards for kings and pawns #ifdef ANTI @@ -784,7 +784,8 @@ namespace { template template Score Evaluation::pieces() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); const Square* pl = pos.squares(Us); @@ -792,7 +793,6 @@ namespace { Bitboard b, bb; Square s; Score score = SCORE_ZERO; - int mob; attackedBy[Us][Pt] = 0; @@ -821,8 +821,7 @@ namespace { kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } - mob = (Pt == KNIGHT || Pt == BISHOP) ? popcount(b & mobilityArea[Us] & ~pos.pieces(Us, QUEEN)) - : popcount(b & mobilityArea[Us]); + int mob = popcount(b & mobilityArea[Us]); mobility[Us] += MobilityBonus[pos.variant()][Pt - 2][mob]; @@ -854,8 +853,12 @@ namespace { if (Pt == BISHOP) { - // Penalty according to number of pawns on the same color square as the bishop - score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s); + // Penalty according to number of pawns on the same color square as the + // bishop, bigger when the center files are blocked with pawns. + Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); + + score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s) + * (1 + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(Center & (attacks_bb(s, pos.pieces(PAWN)) | s))) @@ -1021,7 +1024,7 @@ namespace { // Enemy pawn checks if (pos.is_house()) { - const Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); b = pos.attacks_from(ksq, Us); h = pos.count_in_hand(Them) ? ~pos.pieces() : 0; Bitboard pawn_moves = (attackedBy[Them][PAWN] & pos.pieces(Us)) | (shift(pos.pieces(Them, PAWN)) & ~pos.pieces()); @@ -1128,7 +1131,7 @@ namespace { #ifdef ANTI if (pos.is_anti()) { - const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); + constexpr Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); bool weCapture = attackedBy[Us][ALL_PIECES] & pos.pieces(Them); bool theyCapture = attackedBy[Them][ALL_PIECES] & pos.pieces(Us); @@ -1186,10 +1189,13 @@ namespace { } else #endif +#ifdef GRID + if (pos.is_grid()) {} else +#endif #ifdef LOSERS if (pos.is_losers()) { - const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); + constexpr Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); bool weCapture = attackedBy[Us][ALL_PIECES] & pos.pieces(Them); bool theyCapture = attackedBy[Them][ALL_PIECES] & pos.pieces(Us); @@ -1432,7 +1438,7 @@ namespace { } // w != 0 // Scale down bonus for candidate passers which need more than one - // pawn push to become passed or have a pawn in front of them. + // pawn push to become passed, or have a pawn in front of them. if ( !pos.pawn_passed(Us, s + Up) || (pos.pieces(PAWN) & forward_file_bb(Us, s))) bonus = bonus / 2; @@ -1465,9 +1471,7 @@ namespace { if (pos.non_pawn_material() < SpaceThreshold[pos.variant()]) return SCORE_ZERO; - // Find the safe squares for our pieces inside the area defined by - // SpaceMask. A square is unsafe if it is attacked by an enemy - // pawn, or if it is undefended and attacked by an enemy piece. + // Find the available squares for our pieces inside the area defined by SpaceMask Bitboard safe = SpaceMask & ~pos.pieces(Us, PAWN) & ~attackedBy[Them][PAWN]; @@ -1615,8 +1619,6 @@ namespace { Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK; int sf = me->scale_factor(pos, strongSide); - // If we don't already have an unusual scale factor, check for certain - // types of endgames, and use a lower scale for those. #ifdef ATOMIC if (pos.is_atomic()) {} else #endif @@ -1628,13 +1630,14 @@ namespace { } else #endif - if (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN) - { #ifdef GRID - if (pos.is_grid() && pos.non_pawn_material(strongSide) <= RookValueMg) - sf = 10; - else + if (pos.is_grid() && pos.non_pawn_material(strongSide) <= RookValueMg) + sf = 10; + else #endif + // If scale is not already specific, scale down the endgame via general heuristics + if (sf == SCALE_FACTOR_NORMAL) + { if (pos.opposite_bishops()) { // Endgame with opposite-colored bishops and no other pieces is almost a draw @@ -1647,12 +1650,8 @@ namespace { else sf = 46; } - // Endings where weaker side can place his king in front of the enemy's - // pawns are drawish. - else if ( abs(eg) <= BishopValueEg - && pos.count(strongSide) <= 2 - && !pos.pawn_passed(~strongSide, pos.square(~strongSide))) - sf = 37 + 7 * pos.count(strongSide); + else + sf = std::min(40 + 7 * pos.count(strongSide), sf); } return ScaleFactor(sf); diff --git a/src/material.cpp b/src/material.cpp index ce4fd940..0959ce26 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -570,12 +570,6 @@ Entry* probe(const Position& pos) { if (!pos.count(BLACK) && npm_b - npm_w <= BishopValueMg) e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW : npm_w <= BishopValueMg ? 4 : 14); - - if (pos.count(WHITE) == 1 && npm_w - npm_b <= BishopValueMg) - e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN; - - if (pos.count(BLACK) == 1 && npm_b - npm_w <= BishopValueMg) - e->factor[BLACK] = (uint8_t) SCALE_FACTOR_ONEPAWN; } // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder diff --git a/src/movepick.cpp b/src/movepick.cpp index 27a97ad8..9a9e0744 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -121,18 +121,18 @@ void MovePicker::score() { m.value = PieceValue[pos.variant()][MG][pos.piece_on(to_sq(m))] - Value(200 * std::min(distance(to_sq(m), pos.square(~pos.side_to_move())), distance(to_sq(m), pos.square( pos.side_to_move())))) - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 16; else #endif #ifdef RACE if (pos.is_race()) m.value = PieceValue[pos.variant()][MG][pos.piece_on(to_sq(m))] - Value(200 * relative_rank(BLACK, to_sq(m))) - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 16; else #endif m.value = PieceValue[pos.variant()][MG][pos.piece_on(to_sq(m))] - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 16; } else if (Type == QUIETS) diff --git a/src/movepick.h b/src/movepick.h index 19348ab4..54eedf51 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -33,7 +33,7 @@ /// be a move or even a nested history. We use a class instead of naked value /// to directly call history update operator<<() on the entry so to use stats /// tables at caller sites as simple multi-dim arrays. -template +template class StatsEntry { static const bool IsInt = std::is_integral::value; @@ -47,23 +47,22 @@ class StatsEntry { operator TT() const { return entry; } void operator<<(int bonus) { + assert(abs(bonus) <= D); // Ensure range is [-D, D] + static_assert(D <= std::numeric_limits::max(), "D overflows T"); - assert(abs(bonus) <= D); // Ensure range is [-W * D, W * D] - assert(W * D < std::numeric_limits::max()); // Ensure we don't overflow + entry += bonus - entry * abs(bonus) / D; - entry += bonus * W - entry * abs(bonus) / D; - - assert(abs(entry) <= W * D); + assert(abs(entry) <= D); } }; /// Stats is a generic N-dimensional array used to store various statistics. -/// The first template T parameter is the base type of the array, the W parameter -/// is the weight applied to the bonuses when we update values with the << operator, -/// the D parameter limits the range of updates (range is [-W * D, W * D]), and -/// the last parameters (Size and Sizes) encode the dimensions of the array. -template -struct Stats : public std::array, Size> +/// The first template parameter T is the base type of the array, the second +/// template parameter D limits the range of updates in [-D, D] when we update +/// values with the << operator, while the last parameters (Size and Sizes) +/// encode the dimensions of the array. +template +struct Stats : public std::array, Size> { T* get() { return this->at(0).get(); } @@ -73,38 +72,39 @@ struct Stats : public std::array, Size> } }; -template -struct Stats : public std::array, Size> { +template +struct Stats : public std::array, Size> { T* get() { return this->at(0).get(); } }; -/// Different tables use different W/D parameter, name them to ease readibility -enum StatsParams { W2 = 2, W32 = 32, D324 = 324, D936 = 936, NOT_USED = 0 }; +/// In stats table, D=0 means that the template parameter is not used +enum StatsParams { NOT_USED = 0 }; + /// ButterflyHistory records how often quiet moves have been successful or /// unsuccessful during the current search, and is used for reduction and move /// ordering decisions. It uses 2 tables (one for each color) indexed by /// the move's from and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards #ifdef CRAZYHOUSE -typedef Stats ButterflyHistory; +typedef Stats ButterflyHistory; #else -typedef Stats ButterflyHistory; +typedef Stats ButterflyHistory; #endif /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// move, see chessprogramming.wikispaces.com/Countermove+Heuristic -typedef Stats CounterMoveHistory; +typedef Stats CounterMoveHistory; /// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] -typedef Stats CapturePieceToHistory; +typedef Stats CapturePieceToHistory; /// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] -typedef Stats PieceToHistory; +typedef Stats PieceToHistory; /// ContinuationHistory is the combined history of a given pair of moves, usually /// the current one given a previous one. The nested history table is based on /// PieceToHistory instead of ButterflyBoards. -typedef Stats ContinuationHistory; +typedef Stats ContinuationHistory; /// MovePicker class is used to pick one pseudo legal move at a time from the diff --git a/src/pawns.cpp b/src/pawns.cpp index 2abdca15..1980df2a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -148,44 +148,32 @@ namespace { #endif }; - // Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank]. - // RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king. - constexpr Value ShelterWeakness[VARIANT_NB][2][int(FILE_NB) / 2][RANK_NB] = { + // Strength of pawn shelter for our king by [distance from edge][rank]. + // RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king. + constexpr Value ShelterStrength[VARIANT_NB][int(FILE_NB) / 2][RANK_NB] = { { - { { V( 98), V(20), V(11), V(42), V( 83), V( 84), V(101) }, // Not On King file - { V(103), V( 8), V(33), V(86), V( 87), V(105), V(113) }, - { V(100), V( 2), V(65), V(95), V( 59), V( 89), V(115) }, - { V( 72), V( 6), V(52), V(74), V( 83), V( 84), V(112) } }, - { { V(105), V(19), V( 3), V(27), V( 85), V( 93), V( 84) }, // On King file - { V(121), V( 7), V(33), V(95), V(112), V( 86), V( 72) }, - { V(121), V(26), V(65), V(90), V( 65), V( 76), V(117) }, - { V( 79), V( 0), V(45), V(65), V( 94), V( 92), V(105) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #ifdef ANTI {}, #endif #ifdef ATOMIC { - { { V( 88), V(34), V( 5), V(44), V( 89), V( 90), V( 94) }, // Not On King file - { V(116), V(61), V(-4), V(80), V( 95), V(101), V(104) }, - { V( 97), V(68), V(34), V(82), V( 62), V(104), V(110) }, - { V(103), V(44), V(44), V(77), V(103), V( 66), V(118) } }, - { { V( 88), V(34), V( 5), V(44), V( 89), V( 90), V( 94) }, // On King file - { V(116), V(61), V(-4), V(80), V( 95), V(101), V(104) }, - { V( 97), V(68), V(34), V(82), V( 62), V(104), V(110) }, - { V(103), V(44), V(44), V(77), V(103), V( 66), V(118) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif #ifdef CRAZYHOUSE { - { { V(148), V( 7), V( 84), V(141), V(156), V(177), V(326) }, // Not On King file - { V(288), V( -3), V(141), V(216), V(182), V(213), V(162) }, - { V(190), V( 48), V(140), V(167), V(254), V(186), V(247) }, - { V(142), V(129), V( 90), V(164), V(141), V(116), V(289) } }, - { { V(145), V(-56), V( 20), V(134), V(126), V(166), V(309) }, // On King file - { V(290), V( 0), V(144), V(222), V(177), V(210), V(161) }, - { V(205), V( 46), V(118), V(163), V(235), V(165), V(244) }, - { V(154), V( 84), V( 87), V(188), V(105), V(177), V(275) } } + { V(-48), V(138), V(80), V( 48), V( 5), V( -7), V( 9) }, + { V(-78), V(116), V(20), V( -2), V(14), V( 6), V(-36) }, + { V(-69), V( 99), V(12), V(-19), V(38), V( 22), V(-50) }, + { V( -6), V( 95), V( 9), V( 4), V(-2), V( 2), V(-37) } }, #endif #ifdef EXTINCTION @@ -193,41 +181,34 @@ namespace { #endif #ifdef GRID { - { { V( 97), V(17), V( 9), V(44), V( 84), V( 87), V( 99) }, // Not On King file - { V(106), V( 6), V(33), V(86), V( 87), V(104), V(112) }, - { V(101), V( 2), V(65), V(98), V( 58), V( 89), V(115) }, - { V( 73), V( 7), V(54), V(73), V( 84), V( 83), V(111) } }, - { { V(104), V(20), V( 6), V(27), V( 86), V( 93), V( 82) }, // On King file - { V(123), V( 9), V(34), V(96), V(112), V( 88), V( 75) }, - { V(120), V(25), V(65), V(91), V( 66), V( 78), V(117) }, - { V( 81), V( 2), V(47), V(63), V( 94), V( 93), V(104) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif #ifdef HORDE - {}, + { + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } + }, #endif #ifdef KOTH { - { { V(100), V(20), V(10), V(46), V(82), V( 86), V( 98) }, // Not On King file - { V(116), V( 4), V(28), V(87), V(94), V(108), V(104) }, - { V(109), V( 1), V(59), V(87), V(62), V( 91), V(116) }, - { V( 75), V(12), V(43), V(59), V(90), V( 84), V(112) } }, - { { V(100), V(20), V(10), V(46), V(82), V( 86), V( 98) }, // On King file - { V(116), V( 4), V(28), V(87), V(94), V(108), V(104) }, - { V(109), V( 1), V(59), V(87), V(62), V( 91), V(116) }, - { V( 75), V(12), V(43), V(59), V(90), V( 84), V(112) } }, + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif #ifdef LOSERS { - { { V(100), V(20), V(10), V(46), V(82), V( 86), V( 98) }, // Not On King file - { V(116), V( 4), V(28), V(87), V(94), V(108), V(104) }, - { V(109), V( 1), V(59), V(87), V(62), V( 91), V(116) }, - { V( 75), V(12), V(43), V(59), V(90), V( 84), V(112) } }, - { { V(100), V(20), V(10), V(46), V(82), V( 86), V( 98) }, // On King file - { V(116), V( 4), V(28), V(87), V(94), V(108), V(104) }, - { V(109), V( 1), V(59), V(87), V(62), V( 91), V(116) }, - { V( 75), V(12), V(43), V(59), V(90), V( 84), V(112) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif #ifdef RACE @@ -235,26 +216,18 @@ namespace { #endif #ifdef THREECHECK { - { { V(140), V( 11), V(38), V( 26), V( 99), V( 94), V( 95) }, // Not On King file - { V(104), V( 14), V(28), V(128), V( 86), V(107), V(115) }, - { V(144), V( 59), V(89), V( 97), V( 39), V( 85), V(114) }, - { V(103), V( 24), V(76), V( 96), V(115), V( 98), V(127) } }, - { { V(115), V(-16), V(13), V( 38), V(115), V( 76), V( 92) }, // On King file - { V(166), V( 20), V(51), V(111), V( 98), V(113), V(114) }, - { V(102), V( 29), V(76), V( 75), V( 60), V( 99), V( 96) }, - { V( 89), V( 18), V(44), V(112), V( 77), V(114), V(115) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif #ifdef TWOKINGS { - { { V( 97), V(17), V( 9), V(44), V( 84), V( 87), V( 99) }, // Not On King file - { V(106), V( 6), V(33), V(86), V( 87), V(104), V(112) }, - { V(101), V( 2), V(65), V(98), V( 58), V( 89), V(115) }, - { V( 73), V( 7), V(54), V(73), V( 84), V( 83), V(111) } }, - { { V(104), V(20), V( 6), V(27), V( 86), V( 93), V( 82) }, // On King file - { V(123), V( 9), V(34), V(96), V(112), V( 88), V( 75) }, - { V(120), V(25), V(65), V(91), V( 66), V( 78), V(117) }, - { V( 81), V( 2), V(47), V(63), V( 94), V( 93), V(104) } } + { V( -9), V(64), V(77), V( 44), V( 4), V( -1), V(-11) }, + { V(-15), V(83), V(51), V(-10), V( 1), V(-10), V(-28) }, + { V(-18), V(84), V(27), V(-12), V(21), V( -7), V(-36) }, + { V( 12), V(79), V(25), V( 19), V( 9), V( -6), V(-33) } }, #endif }; @@ -262,12 +235,8 @@ namespace { // Danger of enemy pawns moving toward our king by [type][distance from edge][rank]. // For the unopposed and unblocked cases, RANK_1 = 0 is used when opponent has // no pawn on the given file, or their pawn is behind our king. - constexpr Value StormDanger[VARIANT_NB][4][4][RANK_NB] = { + constexpr Value StormDanger[VARIANT_NB][3][4][RANK_NB] = { { - { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing - { V( 0), V( 60), V( 144), V(39), V(13) }, - { V( 0), V( 65), V( 141), V(41), V(34) }, - { V( 0), V( 53), V( 127), V(56), V(14) } }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed { V( 1), V( 64), V( 143), V(26), V(13) }, { V( 1), V( 47), V( 110), V(44), V(24) }, @@ -286,10 +255,6 @@ namespace { #endif #ifdef ATOMIC { - { { V(-25), V(-332), V(-235), V( 79), V( 41) }, // BlockedByKing - { V(-17), V( 35), V( 206), V(-21), V(-11) }, - { V(-31), V( 52), V( 103), V( 42), V( 94) }, - { V( -5), V( 101), V( 67), V( 29), V( 64) } }, { { V(-47), V( 62), V( 114), V( 16), V( 13) }, // Unopposed { V( 82), V( 41), V( 161), V( 48), V( 35) }, { V( 44), V( 56), V( 115), V( 17), V( 48) }, @@ -306,10 +271,6 @@ namespace { #endif #ifdef CRAZYHOUSE { - { { V( -54), V(-364), V(-273), V( -2), V( 72) }, // BlockedByKing - { V( -35), V( 99), V( 123), V( 85), V(-25) }, - { V( 4), V( 51), V( 136), V(111), V(149) }, - { V( -55), V( 26), V( 164), V( 74), V( 67) } }, { { V( 106), V( 88), V( 213), V( 68), V( 47) }, // Unopposed { V( -82), V( 122), V( 92), V(148), V( 6) }, { V( 25), V( 3), V( 120), V(141), V( 22) }, @@ -329,10 +290,6 @@ namespace { #endif #ifdef GRID { - { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing - { V( 0), V( 60), V( 144), V(39), V(13) }, - { V( 0), V( 65), V( 141), V(41), V(34) }, - { V( 0), V( 53), V( 127), V(56), V(14) } }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed { V( 1), V( 64), V( 143), V(26), V(13) }, { V( 1), V( 47), V( 110), V(44), V(24) }, @@ -349,10 +306,6 @@ namespace { #endif #ifdef HORDE { - { { V(-11), V(-364), V(-337), V( 43), V( 69) }, // BlockedByKing - { V(-24), V( 2), V( 133), V(-33), V(-73) }, - { V( 9), V( 72), V( 152), V( 99), V( 66) }, - { V( 71), V( 18), V( 38), V( 30), V( 69) } }, { { V( 18), V( -11), V( 131), V( 42), V(114) }, // Unopposed { V( -4), V( 63), V( -77), V( 62), V( 28) }, { V( 66), V( 82), V( 43), V( 11), V( 95) }, @@ -369,10 +322,6 @@ namespace { #endif #ifdef KOTH { - { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing - { V( 0), V( 60), V( 144), V(39), V(13) }, - { V( 0), V( 65), V( 141), V(41), V(34) }, - { V( 0), V( 53), V( 127), V(56), V(14) } }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed { V( 1), V( 64), V( 143), V(26), V(13) }, { V( 1), V( 47), V( 110), V(44), V(24) }, @@ -389,10 +338,6 @@ namespace { #endif #ifdef LOSERS { - { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing - { V( 0), V( 60), V( 144), V(39), V(13) }, - { V( 0), V( 65), V( 141), V(41), V(34) }, - { V( 0), V( 53), V( 127), V(56), V(14) } }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed { V( 1), V( 64), V( 143), V(26), V(13) }, { V( 1), V( 47), V( 110), V(44), V(24) }, @@ -412,10 +357,6 @@ namespace { #endif #ifdef THREECHECK { - { { V(-40), V(-310), V(-236), V( 86), V(107) }, // BlockedByKing - { V( 24), V( 80), V( 168), V( 38), V( -4) }, - { V( 16), V( -41), V( 171), V( 63), V( 19) }, - { V( 12), V( 80), V( 182), V( 36), V(-16) } }, { { V( 27), V( -18), V( 175), V( 31), V( 29) }, // Unopposed { V(106), V( 81), V( 106), V( 86), V( 19) }, { V( 42), V( 62), V( 96), V( 84), V( 40) }, @@ -432,10 +373,6 @@ namespace { #endif #ifdef TWOKINGS { - { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing - { V( 0), V( 60), V( 144), V(39), V(13) }, - { V( 0), V( 65), V( 141), V(41), V(34) }, - { V( 0), V( 53), V( 127), V(56), V(14) } }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed { V( 1), V( 64), V( 143), V(26), V(13) }, { V( 1), V( 47), V( 110), V(44), V(24) }, @@ -452,12 +389,8 @@ namespace { #endif }; - // Max bonus for king safety. Corresponds to start position with all the pawns - // in front of the king and no enemy pawn on the horizon. - constexpr Value MaxSafetyBonus = V(258); - #ifdef HORDE - const Score ImbalancedHorde = S(49, 39); + constexpr Score ImbalancedHorde = S(49, 39); #endif #undef S @@ -604,7 +537,7 @@ namespace Pawns { void init() { static constexpr int Seed[VARIANT_NB][RANK_NB] = { - { 0, 13, 24, 18, 76, 100, 175, 330 }, + { 0, 13, 24, 18, 65, 100, 175, 330 }, #ifdef ANTI { 0, 8, 19, 13, 71, 94, 169, 324 }, #endif @@ -615,10 +548,10 @@ void init() { { 0, 8, 19, 13, 71, 94, 169, 324 }, #endif #ifdef EXTINCTION - { 0, 13, 24, 18, 76, 100, 175, 330 }, + { 0, 13, 24, 18, 65, 100, 175, 330 }, #endif #ifdef GRID - { 0, 13, 24, 18, 76, 100, 175, 330 }, + { 0, 13, 24, 18, 65, 100, 175, 330 }, #endif #ifdef HORDE { 37, 29, 3, 1, 105, 99, 343, 350 }, @@ -636,7 +569,7 @@ void init() { { 0, 8, 19, 13, 71, 94, 169, 324 }, #endif #ifdef TWOKINGS - { 0, 13, 24, 18, 76, 100, 175, 330 }, + { 0, 13, 24, 18, 65, 100, 175, 330 }, #endif }; @@ -683,21 +616,25 @@ Entry* probe(const Position& pos) { } -/// Entry::shelter_storm() calculates shelter and storm penalties for the file -/// the king is on, as well as the two closest files. +/// Entry::evaluate_shelter() calculates the shelter bonus and the storm +/// penalty for a king, looking at the king file and the two closest files. template -Value Entry::shelter_storm(const Position& pos, Square ksq) { +Value Entry::evaluate_shelter(const Position& pos, Square ksq) { + enum { Unopposed, BlockedByPawn, Unblocked }; constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); - - enum { BlockedByKing, Unopposed, BlockedByPawn, Unblocked }; + constexpr Bitboard BlockRanks = (Us == WHITE ? Rank1BB | Rank2BB : Rank8BB | Rank7BB); Bitboard b = pos.pieces(PAWN) & (forward_ranks_bb(Us, ksq) | rank_bb(ksq)); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); - Value safety = MaxSafetyBonus; + + Value safety = (ourPawns & file_bb(ksq)) ? Value(5) : Value(-5); + + if ((shift(theirPawns) & (FileABB | FileHBB) & BlockRanks) & ksq) + safety += 374; File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); for (File f = File(center - 1); f <= File(center + 1); ++f) @@ -709,12 +646,10 @@ Value Entry::shelter_storm(const Position& pos, Square ksq) { Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; int d = std::min(f, ~f); - safety -= ShelterWeakness[pos.variant()][f == file_of(ksq)][d][rkUs] - + StormDanger[pos.variant()] - [(shift(b) & ksq) ? BlockedByKing : - rkUs == RANK_1 ? Unopposed : - rkThem == (rkUs + 1) ? BlockedByPawn : Unblocked] - [d][rkThem]; + safety += ShelterStrength[pos.variant()][d][rkUs] + - StormDanger[pos.variant()][rkUs == RANK_1 ? Unopposed : + rkUs == rkThem - 1 ? BlockedByPawn : Unblocked] + [d][rkThem]; } return safety; @@ -735,14 +670,14 @@ Score Entry::do_king_safety(const Position& pos, Square ksq) { if (pawns) while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {} - Value bonus = shelter_storm(pos, ksq); + Value bonus = evaluate_shelter(pos, ksq); // If we can castle use the bonus after the castling if it is bigger if (pos.can_castle(MakeCastling::right)) - bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_G1))); + bonus = std::max(bonus, evaluate_shelter(pos, relative_square(Us, SQ_G1))); if (pos.can_castle(MakeCastling::right)) - bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_C1))); + bonus = std::max(bonus, evaluate_shelter(pos, relative_square(Us, SQ_C1))); #ifdef CRAZYHOUSE if (pos.is_house()) diff --git a/src/pawns.h b/src/pawns.h index f36168c9..ec926a42 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -59,7 +59,7 @@ struct Entry { Score do_king_safety(const Position& pos, Square ksq); template - Value shelter_storm(const Position& pos, Square ksq); + Value evaluate_shelter(const Position& pos, Square ksq); Key key; Score scores[COLOR_NB]; diff --git a/src/psqt.cpp b/src/psqt.cpp index 0ac47a6b..a4ae5a34 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -867,7 +867,7 @@ constexpr Score Bonus[VARIANT_NB][PIECE_TYPE_NB][RANK_NB][int(FILE_NB) / 2] = { #ifdef CRAZYHOUSE Score psq[VARIANT_NB][PIECE_NB][SQUARE_NB+1]; -const Score inHandBonus[PIECE_TYPE_NB] = { +constexpr Score inHandBonus[PIECE_TYPE_NB] = { S(0, 0), S(52, 13), S(66, 30), S(4, 4), S(13, 3), S(25, 9) }; #else diff --git a/src/search.cpp b/src/search.cpp index 64befce1..4474b5cb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -104,7 +104,7 @@ namespace { {0, 603, 604}, #endif }; - const int FutilityMarginFactor[VARIANT_NB] = { + constexpr int FutilityMarginFactor[VARIANT_NB] = { 175, #ifdef ANTI 611, @@ -140,7 +140,7 @@ namespace { 175, #endif }; - const int FutilityMarginParent[VARIANT_NB][2] = { + constexpr int FutilityMarginParent[VARIANT_NB][2] = { { 256, 200 }, #ifdef ANTI { 331, 372 }, @@ -176,7 +176,7 @@ namespace { { 256, 200 }, #endif }; - const int ProbcutMargin[VARIANT_NB] = { + constexpr int ProbcutMargin[VARIANT_NB] = { 216, #ifdef ANTI 200, @@ -237,10 +237,9 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth depth) { int d = depth / ONE_PLY; - return d > 17 ? 0 : d * d + 2 * d - 2; + return d > 17 ? 0 : 32 * d * d + 64 * d - 64; } -#ifdef SKILL // Skill structure is used to implement strength limit struct Skill { explicit Skill(int l) : level(l) {} @@ -251,7 +250,6 @@ namespace { int level; Move best = MOVE_NONE; }; -#endif template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning); @@ -434,9 +432,7 @@ void MainThread::search() { #endif if ( Options["MultiPV"] == 1 && !Limits.depth -#ifdef SKILL && !Skill(Options["Skill Level"]).enabled() -#endif && rootMoves[0].pv[0] != MOVE_NONE) { for (Thread* th : Threads) @@ -543,18 +539,16 @@ void Thread::search() { mainThread->bestMoveChanges = 0, mainThread->failedLow = false; size_t multiPV = Options["MultiPV"]; -#ifdef SKILL Skill skill(Options["Skill Level"]); // When playing with strength handicap enable MultiPV search that we will // use behind the scenes to retrieve a set of possible moves. if (skill.enabled()) multiPV = std::max(multiPV, (size_t)4); -#endif multiPV = std::min(multiPV, rootMoves.size()); - int ct = Options["Contempt"] * PawnValueEg / 100; // From centipawns + int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns // In analysis mode, adjust contempt in accordance with user preference if (Limits.infinite || Options["UCI_AnalyseMode"]) @@ -616,7 +610,7 @@ void Thread::search() { beta = std::min(previousScore + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + int(std::round(48 * atan(float(previousScore) / 128))); + int dct = ct + 88 * previousScore / (abs(previousScore) + 200); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -699,11 +693,9 @@ void Thread::search() { if (!mainThread) continue; -#ifdef SKILL // If skill level is enabled and time is up, pick a sub-optimal best move if (skill.enabled() && skill.time_to_pick(rootDepth)) skill.pick_best(multiPV); -#endif // Do we have time for the next iteration? Can we stop searching now? if ( Limits.use_time_management() @@ -744,12 +736,10 @@ void Thread::search() { mainThread->previousTimeReduction = timeReduction; -#ifdef SKILL // If skill level is enabled, swap best PV line with the sub-optimal one if (skill.enabled()) std::swap(rootMoves[0], *std::find(rootMoves.begin(), rootMoves.end(), skill.best ? skill.best : skill.pick_best(multiPV))); -#endif } @@ -1056,12 +1046,11 @@ namespace { // Step 11. Internal iterative deepening (skipped when in check, ~2 Elo) #ifdef CRAZYHOUSE - if ( depth >= (pos.is_house() ? 4 : 6) * ONE_PLY + if ( depth >= (pos.is_house() ? 6 : 8) * ONE_PLY #else - if ( depth >= 6 * ONE_PLY + if ( depth >= 8 * ONE_PLY #endif - && !ttMove - && (PvNode || ss->staticEval + 128 >= beta)) + && !ttMove) { Depth d = 3 * depth / 4 - 2 * ONE_PLY; search(pos, ss, alpha, beta, d, cutNode, true); @@ -1076,7 +1065,11 @@ namespace { const PieceToHistory* contHist[] = { (ss-1)->contHistory, (ss-2)->contHistory, nullptr, (ss-4)->contHistory }; Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; - MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, countermove, ss->killers); + MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, + &thisThread->captureHistory, + contHist, + countermove, + ss->killers); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc skipQuiets = false; @@ -1200,6 +1193,9 @@ namespace { // Futility pruning: parent node (~2 Elo) #ifdef LOSERS if (pos.is_losers()) {} else +#endif +#ifdef RACE + if (pos.is_race()) {} else #endif if ( lmrDepth < 7 && !inCheck @@ -1561,7 +1557,9 @@ namespace { // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will // be generated. - MovePicker mp(pos, ttMove, depth, &pos.this_thread()->mainHistory, &pos.this_thread()->captureHistory, to_sq((ss-1)->currentMove)); + MovePicker mp(pos, ttMove, depth, &pos.this_thread()->mainHistory, + &pos.this_thread()->captureHistory, + to_sq((ss-1)->currentMove)); // Loop through the moves until no moves remain or a beta cutoff occurs while ((move = mp.next_move()) != MOVE_NONE) @@ -1778,7 +1776,6 @@ namespace { } } -#ifdef SKILL // When playing with strength handicap, choose best move among a set of RootMoves // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. @@ -1811,7 +1808,6 @@ namespace { return best; } -#endif } // namespace diff --git a/src/thread.cpp b/src/thread.cpp index 58aaf460..5b9fa882 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -138,7 +138,7 @@ void Thread::idle_loop() { } /// ThreadPool::set() creates/destroys threads to match the requested number. -/// Created and launced threads wil go immediately to sleep in idle_loop. +/// Created and launched threads wil go immediately to sleep in idle_loop. /// Upon resizing, threads are recreated to allow for binding if necessary. void ThreadPool::set(size_t requested) { diff --git a/src/types.h b/src/types.h index afd770ed..806e8150 100644 --- a/src/types.h +++ b/src/types.h @@ -312,7 +312,6 @@ enum Phase { enum ScaleFactor { SCALE_FACTOR_DRAW = 0, - SCALE_FACTOR_ONEPAWN = 48, SCALE_FACTOR_NORMAL = 64, SCALE_FACTOR_MAX = 128, SCALE_FACTOR_NONE = 255 diff --git a/src/uci.cpp b/src/uci.cpp index faa02cb2..c3ca5927 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -261,7 +261,7 @@ string UCI::value(Value v) { if (abs(v) < VALUE_MATE - MAX_PLY) ss << "cp " << v * 100 / PawnValueEg; else - ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; + ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v - 1) / 2; return ss.str(); } diff --git a/src/uci.h b/src/uci.h index 2a38864f..47d32a5a 100644 --- a/src/uci.h +++ b/src/uci.h @@ -51,12 +51,12 @@ class Option { Option(bool v, OnChange = nullptr); Option(const char* v, OnChange = nullptr); Option(const char* v, const std::vector& variants, OnChange = nullptr); - Option(int v, int minv, int maxv, OnChange = nullptr); + Option(double v, int minv, int maxv, OnChange = nullptr); Option(const char* v, const char *cur, OnChange = nullptr); Option& operator=(const std::string&); void operator<<(const Option&); - operator int() const; + operator double() const; operator std::string() const; bool operator==(const char*); diff --git a/src/ucioption.cpp b/src/ucioption.cpp index eadf4a16..356e6e20 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -63,9 +63,7 @@ void init(OptionsMap& o) { o["Clear Hash"] << Option(on_clear_hash); o["Ponder"] << Option(false); o["MultiPV"] << Option(1, 1, 500); -#ifdef SKILL o["Skill Level"] << Option(20, 0, 20); -#endif o["Move Overhead"] << Option(30, 0, 5000); o["Minimum Thinking Time"] << Option(20, 0, 5000); o["Slow Mover"] << Option(84, 10, 1000); @@ -88,7 +86,7 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { const Option& o = it.second; os << "\noption name " << it.first << " type " << o.type; - if (o.type != "button") + if (o.type == "string" || o.type == "check" || o.type == "combo") os << " default " << o.defaultValue; if (o.type == "combo") @@ -96,7 +94,9 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { os << " var " << value; if (o.type == "spin") - os << " min " << o.min << " max " << o.max; + os << " default " << int(stof(o.defaultValue)) + << " min " << o.min + << " max " << o.max; break; } @@ -119,15 +119,15 @@ Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f) Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f) {} -Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f) +Option::Option(double v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f) { defaultValue = currentValue = std::to_string(v); } Option::Option(const char* v, const char* cur, OnChange f) : type("combo"), min(0), max(0), on_change(f) { defaultValue = v; currentValue = cur; } -Option::operator int() const { +Option::operator double() const { assert(type == "check" || type == "spin"); - return (type == "spin" ? stoi(currentValue) : currentValue == "true"); + return (type == "spin" ? stof(currentValue) : currentValue == "true"); } Option::operator std::string() const { @@ -164,7 +164,7 @@ Option& Option::operator=(const string& v) { if ( (type != "button" && v.empty()) || (type == "check" && v != "true" && v != "false") || (type == "combo" && (std::find(comboValues.begin(), comboValues.end(), v) == comboValues.end())) - || (type == "spin" && (stoi(v) < min || stoi(v) > max))) + || (type == "spin" && (stof(v) < min || stof(v) > max))) return *this; if (type != "button")