From: Fabian Fichter Date: Thu, 3 Sep 2020 21:43:11 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=dfa501bf1029ffa40d677f6bcc7e33a70baf581d;p=fairystockfish.git Merge official-stockfish/master --- dfa501bf1029ffa40d677f6bcc7e33a70baf581d diff --cc src/evaluate.cpp index 9904d7a,12a4c7b..771ec3e --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -35,8 -34,8 +35,8 @@@ namespace Trace enum Tracing { NO_TRACE, TRACE }; - enum Term { // The first 8 entries are reserved for PieceType - MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB + enum Term { // The first PIECE_TYPE_NB entries are reserved for PieceType - MATERIAL = PIECE_TYPE_NB, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, VARIANT, TOTAL, TERM_NB ++ MATERIAL = PIECE_TYPE_NB, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, VARIANT, WINNABLE, TOTAL, TERM_NB }; Score scores[TERM_NB][COLOR_NB]; @@@ -183,9 -173,7 +183,8 @@@ namespace template Score threats() const; template Score passed() const; template Score space() const; + template Score variant() const; - ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score) const; + Value winnable(Score score) const; const Position& pos; Material::Entry* me; @@@ -933,173 -716,28 +932,173 @@@ } + // 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::initiative() computes the initiative correction value - // for the position. It is a second order bonus/malus based on the + // 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. template - Score Evaluation::initiative(Score score) const { + Value Evaluation::winnable(Score score) const { - int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - - distance(pos.square(WHITE), pos.square(BLACK)); + // No initiative bonus for extinction variants - if (pos.extinction_value() != VALUE_NONE || pos.captures_to_hand() || pos.connect_n()) - return SCORE_ZERO; - ++ int complexity = 0; ++ if (pos.extinction_value() == VALUE_NONE && !pos.captures_to_hand() && !pos.connect_n()) ++ { + int outflanking = !pos.count(WHITE) || !pos.count(BLACK) ? 0 + : distance(pos.square(WHITE), pos.square(BLACK)) + - distance(pos.square(WHITE), pos.square(BLACK)); bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); bool almostUnwinnable = outflanking < 0 + && pos.stalemate_value() == VALUE_DRAW && !pawnsOnBothFlanks; - bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 - || rank_of(pos.square(BLACK)) < RANK_5; + bool infiltration = (pos.count(WHITE) && rank_of(pos.square(WHITE)) > RANK_4) + || (pos.count(BLACK) && rank_of(pos.square(BLACK)) < RANK_5); // Compute the initiative bonus for the attacking side -- int complexity = 9 * pe->passed_count() ++ complexity = 9 * pe->passed_count() + 12 * pos.count() + + 15 * pos.count() + 9 * outflanking + 21 * pawnsOnBothFlanks + 24 * infiltration @@@ -1107,6 -745,6 +1106,7 @@@ - 43 * almostUnwinnable - 2 * pos.rule50_count() -110 ; ++ } Value mg = mg_value(score); Value eg = eg_value(score); @@@ -1144,10 -775,21 +1137,21 @@@ sf = 22 + 3 * pos.count(strongSide); } else - sf = std::min(sf, 36 + 7 * pos.count(strongSide)); + sf = std::min(sf, 36 + 7 * (pos.count(strongSide) + pos.count(strongSide))); } - return ScaleFactor(sf); + // Interpolate between the middlegame and (scaled by 'sf') endgame score + v = mg * int(me->game_phase()) + + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL; + v /= PHASE_MIDGAME; + + if (T) + { + Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score))); + Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL)); + } + + return Value(v); } @@@ -1208,17 -842,10 +1212,11 @@@ score += king< WHITE>() - king< BLACK>() + threats() - threats() + passed< WHITE>() - passed< BLACK>() - + space< WHITE>() - space< BLACK>(); + + space< WHITE>() - space< BLACK>() + + variant() - variant(); - score += initiative(score); - - // Interpolate between a middlegame and a (scaled by 'sf') endgame score - ScaleFactor sf = scale_factor(eg_value(score)); - v = mg_value(score) * int(me->game_phase()) - + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; - - v /= PHASE_MIDGAME; + // Derive single value from mg and eg parts of score + v = winnable(score); // In case of tracing add all remaining individual evaluation terms if (T) @@@ -1285,8 -905,7 +1282,8 @@@ std::string Eval::trace(const Position << " Threats | " << Term(THREAT) << " Passed | " << Term(PASSED) << " Space | " << Term(SPACE) - << " Initiative | " << Term(INITIATIVE) + << " Variant | " << Term(VARIANT) + << " Winnable | " << Term(WINNABLE) << " ------------+-------------+-------------+------------\n" << " Total | " << Term(TOTAL);