Value Entry::shelter_storm(const Position& pos, Square ksq) { const Color Them = (Us == WHITE ? BLACK : WHITE); const Bitboard Edges = (FileABB | FileHBB) & (Rank2BB | Rank3BB); Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq)); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); Value safety = MaxSafetyBonus; File kf = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); for (File f = kf - File(1); f <= kf + File(1); ++f) { b = ourPawns & file_bb(f); Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; b = theirPawns & file_bb(f); Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; if ( (Edges & make_square(f, rkThem)) && file_of(ksq) == f && relative_rank(Us, ksq) == rkThem - 1) safety += 200; else safety -= ShelterWeakness[rkUs] + StormDanger[rkUs == RANK_1 ? 0 : rkThem != rkUs + 1 ? 1 : 2][rkThem]; } return safety; }
Value Entry::shelter_storm(const Position& pos, Square ksq) { const Color Them = (Us == WHITE ? BLACK : WHITE); enum { NoFriendlyPawn, Unblocked, BlockedByPawn, BlockedByKing }; Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq)); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); Value safety = MaxSafetyBonus; File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); for (File f = center - File(1); f <= center + File(1); ++f) { b = ourPawns & file_bb(f); Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; b = theirPawns & file_bb(f); Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; safety -= ShelterWeakness[std::min(f, FILE_H - f)][rkUs] + StormDanger [f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing : rkUs == RANK_1 ? NoFriendlyPawn : rkThem == rkUs + 1 ? BlockedByPawn : Unblocked] [std::min(f, FILE_H - f)][rkThem]; } return safety; }
Value Entry::evaluate_shelter(const Position& pos, Square ksq) { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard BlockRanks = (Us == WHITE ? Rank1BB | Rank2BB : Rank8BB | Rank7BB); Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); Value safety = (shift<Down>(theirPawns) & (FileABB | FileHBB) & BlockRanks & ksq) ? Value(374) : Value(5); File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); int ourRank = b ? relative_rank(Us, backmost_sq(Us, b)) : 0; b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; int d = std::min(f, ~f); safety += ShelterStrength[d][ourRank]; safety -= (ourRank && (ourRank == theirRank - 1)) ? BlockedStorm[theirRank] : UnblockedStorm[d][theirRank]; } return safety; }
Value Entry::shelter_storm(const Position& pos, Square ksq) { const Color Them = (Us == WHITE ? BLACK : WHITE); Value safety = MaxSafetyBonus; Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq)); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); Rank rkUs, rkThem; File kf = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); for (int f = kf - 1; f <= kf + 1; f++) { b = ourPawns & FileBB[f]; rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; safety -= ShelterWeakness[rkUs]; b = theirPawns & FileBB[f]; rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; safety -= StormDanger[rkUs == RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][rkThem]; } return safety; }
Value Eval::evaluate(const Position& pos) { assert(!pos.checkers()); EvalInfo ei; Score score, mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO }; // Initialize score by reading the incrementally updated scores included in // the position object (material + piece square tables). Score is computed // internally from the white point of view. score = pos.psq_score(); // Probe the material hash table ei.me = Material::probe(pos); score += ei.me->imbalance(); // If we have a specialized evaluation function for the current material // configuration, call it and return. if (ei.me->specialized_eval_exists()) return ei.me->evaluate(pos); // Probe the pawn hash table ei.pi = Pawns::probe(pos); score += ei.pi->pawns_score(); // Initialize attack and king safety bitboards ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0; eval_init<WHITE>(pos, ei); eval_init<BLACK>(pos, ei); // Pawns blocked or on ranks 2 and 3 will be excluded from the mobility area Bitboard blockedPawns[] = { pos.pieces(WHITE, PAWN) & (shift_bb<DELTA_S>(pos.pieces()) | Rank2BB | Rank3BB), pos.pieces(BLACK, PAWN) & (shift_bb<DELTA_N>(pos.pieces()) | Rank7BB | Rank6BB) }; // Do not include in mobility area squares protected by enemy pawns, or occupied // by our blocked pawns or king. Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | blockedPawns[WHITE] | pos.square<KING>(WHITE)), ~(ei.attackedBy[WHITE][PAWN] | blockedPawns[BLACK] | pos.square<KING>(BLACK)) }; // Evaluate all pieces but king and pawns score += evaluate_pieces<DoTrace>(pos, ei, mobility, mobilityArea); score += mobility[WHITE] - mobility[BLACK]; // Evaluate kings after all other pieces because we need full attack // information when computing the king safety evaluation. score += evaluate_king<WHITE, DoTrace>(pos, ei) - evaluate_king<BLACK, DoTrace>(pos, ei); // Evaluate tactical threats, we need full attack information including king score += evaluate_threats<WHITE, DoTrace>(pos, ei) - evaluate_threats<BLACK, DoTrace>(pos, ei); // Evaluate passed pawns, we need full attack information including king score += evaluate_passed_pawns<WHITE, DoTrace>(pos, ei) - evaluate_passed_pawns<BLACK, DoTrace>(pos, ei); // If both sides have only pawns, score for potential unstoppable pawns if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK)) { Bitboard b; if ((b = ei.pi->passed_pawns(WHITE)) != 0) score += Unstoppable * int(relative_rank(WHITE, frontmost_sq(WHITE, b))); if ((b = ei.pi->passed_pawns(BLACK)) != 0) score -= Unstoppable * int(relative_rank(BLACK, frontmost_sq(BLACK, b))); } // Evaluate space for both sides, only during opening if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222) score += evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei); // Evaluate position potential for the winning side score += evaluate_initiative(pos, ei.pi->pawn_asymmetry(), eg_value(score)); // Evaluate scale factor for the winning side ScaleFactor sf = evaluate_scale_factor(pos, ei, eg_value(score)); // Interpolate between a middlegame and a (scaled by 'sf') endgame score Value v = mg_value(score) * int(ei.me->game_phase()) + eg_value(score) * int(PHASE_MIDGAME - ei.me->game_phase()) * sf / SCALE_FACTOR_NORMAL; v /= int(PHASE_MIDGAME); // In case of tracing add all remaining individual evaluation terms if (DoTrace) { Trace::add(MATERIAL, pos.psq_score()); Trace::add(IMBALANCE, ei.me->imbalance()); Trace::add(PAWN, ei.pi->pawns_score()); Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]); Trace::add(SPACE, evaluate_space<WHITE>(pos, ei) , evaluate_space<BLACK>(pos, ei)); Trace::add(TOTAL, score); } return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view }