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; }
ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.non_pawn_material(weakerSide) == RookValueMidgame); assert(pos.piece_count(weakerSide, PAWN) == 1); Square wpsq1 = pos.piece_list(strongerSide, PAWN, 0); Square wpsq2 = pos.piece_list(strongerSide, PAWN, 1); Square bksq = pos.king_square(weakerSide); // Does the stronger side have a passed pawn? if ( pos.pawn_is_passed(strongerSide, wpsq1) || pos.pawn_is_passed(strongerSide, wpsq2)) return SCALE_FACTOR_NONE; Rank r = Max(relative_rank(strongerSide, wpsq1), relative_rank(strongerSide, wpsq2)); if ( file_distance(bksq, wpsq1) <= 1 && file_distance(bksq, wpsq2) <= 1 && relative_rank(strongerSide, bksq) > r) { switch (r) { case RANK_2: return ScaleFactor(10); case RANK_3: return ScaleFactor(10); case RANK_4: return ScaleFactor(15); case RANK_5: return ScaleFactor(20); case RANK_6: return ScaleFactor(40); default: assert(false); } } return SCALE_FACTOR_NONE; }
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::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 = file_of(ksq); kf = (kf == FILE_A) ? FILE_B : (kf == FILE_H) ? FILE_G : kf; for (int f = kf - 1; f <= kf + 1; f++) { b = ourPawns & FileBB[f]; rkUs = b ? relative_rank(Us, Us == WHITE ? lsb(b) : msb(b)) : RANK_1; safety -= ShelterWeakness[rkUs]; b = theirPawns & FileBB[f]; rkThem = b ? relative_rank(Us, Us == WHITE ? lsb(b) : msb(b)) : RANK_1; safety -= StormDanger[rkUs == RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][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; }
ScaleFactor ScalingFunction<KBPKB>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame); assert(pos.piece_count(weakerSide, BISHOP) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN, 0); Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP, 0); Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP, 0); Square weakerKingSq = pos.king_square(weakerSide); // Case 1: Defending king blocks the pawn, and cannot be driven away if ( square_file(weakerKingSq) == square_file(pawnSq) && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq) && ( !same_color_squares(weakerKingSq, strongerBishopSq) || relative_rank(strongerSide, weakerKingSq) <= RANK_6)) return SCALE_FACTOR_ZERO; // Case 2: Opposite colored bishops if (!same_color_squares(strongerBishopSq, weakerBishopSq)) { // We assume that the position is drawn in the following three situations: // // a. The pawn is on rank 5 or further back. // b. The defending king is somewhere in the pawn's path. // c. The defending bishop attacks some square along the pawn's path, // and is at least three squares away from the pawn. // // These rules are probably not perfect, but in practice they work // reasonably well. if (relative_rank(strongerSide, pawnSq) <= RANK_5) return SCALE_FACTOR_ZERO; else { Bitboard path = squares_in_front_of(strongerSide, pawnSq); if (path & pos.pieces(KING, weakerSide)) return SCALE_FACTOR_ZERO; if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & path) && square_distance(weakerBishopSq, pawnSq) >= 3) return SCALE_FACTOR_ZERO; } } return SCALE_FACTOR_NONE; }
void MovePicker::score<CAPTURES>() { // Winning and equal captures in the main search are ordered by MVV, preferring // captures near our home rank. Surprisingly, this appears to perform slightly // better than SEE-based move ordering: exchanging big pieces before capturing // a hanging piece probably helps to reduce the subtree size. // In the main search we want to push captures with negative SEE values to the // badCaptures[] array, but instead of doing it now we delay until the move // has been picked up, saving some SEE calls in case we get a cutoff. for (auto& m : *this) m.value = PieceValue[MG][pos.piece_on(to_sq(m))] - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); }
ScaleFactor ScalingFunction<KBPKN>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame); assert(pos.piece_count(weakerSide, KNIGHT) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN, 0); Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP, 0); Square weakerKingSq = pos.king_square(weakerSide); if ( square_file(weakerKingSq) == square_file(pawnSq) && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq) && ( !same_color_squares(weakerKingSq, strongerBishopSq) || relative_rank(strongerSide, weakerKingSq) <= RANK_6)) return SCALE_FACTOR_ZERO; return SCALE_FACTOR_NONE; }
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame); assert(pos.piece_count(strongerSide, QUEEN) == 1); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(weakerSide, ROOK) == 1); assert(pos.piece_count(weakerSide, PAWN) >= 1); Square kingSq = pos.king_square(weakerSide); if ( relative_rank(weakerSide, kingSq) <= RANK_2 && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 && (pos.pieces(ROOK, weakerSide) & relative_rank_bb(weakerSide, RANK_3)) && (pos.pieces(PAWN, weakerSide) & relative_rank_bb(weakerSide, RANK_2)) && (pos.attacks_from<KING>(kingSq) & pos.pieces(PAWN, weakerSide))) { Square rsq = pos.piece_list(weakerSide, ROOK, 0); if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(PAWN, weakerSide)) return SCALE_FACTOR_ZERO; } return SCALE_FACTOR_NONE; }
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 (File f = kf - File(1); f <= kf + File(1); ++f) { b = ourPawns & file_bb(f); rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; safety -= ShelterWeakness[rkUs]; b = theirPawns & file_bb(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; }
void MovePicker::score() { static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); for (auto& m : *this) if (Type == CAPTURES) { #ifdef ATOMIC if (pos.is_atomic()) m.value = pos.see<ATOMIC_VARIANT>(m); 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)))] / 8; 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)))] / 8; } else if (Type == QUIETS) { m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]; #ifdef ANTI if (pos.is_anti() && pos.attackers_to(to_sq(m), pos.pieces() ^ from_sq(m)) & pos.pieces(~pos.side_to_move())) { m.value += (1 << 28); if (!(pos.attackers_to(from_sq(m)) & pos.pieces(~pos.side_to_move()))) m.value += (1 << 27); } #endif } else // Type == EVASIONS { if (pos.capture(m)) m.value = PieceValue[pos.variant()][MG][pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m))); else m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] - (1 << 28); } }
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) >= 1); // No assertions about the material of weakerSide, because we want draws to // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(PAWN, strongerSide); File pawnFile = square_file(pos.piece_list(strongerSide, PAWN, 0)); // All pawns are on a single rook file ? if ( (pawnFile == FILE_A || pawnFile == FILE_H) && (pawns & ~file_bb(pawnFile)) == EmptyBoardBB) { Square bishopSq = pos.piece_list(strongerSide, BISHOP, 0); Square queeningSq = relative_square(strongerSide, make_square(pawnFile, RANK_8)); Square kingSq = pos.king_square(weakerSide); if ( !same_color_squares(queeningSq, bishopSq) && file_distance(square_file(kingSq), pawnFile) <= 1) { // The bishop has the wrong color, and the defending king is on the // file of the pawn(s) or the neighboring file. Find the rank of the // frontmost pawn. Rank rank; if (strongerSide == WHITE) { for (rank = RANK_7; (rank_bb(rank) & pawns) == EmptyBoardBB; rank--) {} assert(rank >= RANK_2 && rank <= RANK_7); } else { for (rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {} rank = Rank(rank ^ 7); // HACK to get the relative rank assert(rank >= RANK_2 && rank <= RANK_7); } // If the defending king has distance 1 to the promotion square or // is placed somewhere in front of the pawn, it's a draw. if ( square_distance(kingSq, queeningSq) <= 1 || relative_rank(strongerSide, kingSq) >= rank) return SCALE_FACTOR_ZERO; } } return SCALE_FACTOR_NONE; }
void MovePicker::score<CAPTURES>() { // Winning and equal captures in the main search are ordered by MVV. // Suprisingly, this appears to perform slightly better than SEE based // move ordering. The reason is probably that in a position with a winning // capture, capturing a valuable (but sufficiently defended) piece // first usually doesn't hurt. The opponent will have to recapture, and // the hanging piece will still be hanging (except in the unusual cases // where it is possible to recapture with the hanging piece). Exchanging // big pieces before capturing a hanging piece probably helps to reduce // the subtree size. // In main search we want to push captures with negative SEE values to the // badCaptures[] array, but instead of doing it now we delay until the move // has been picked up in pick_move_from_list(). This way we save some SEE // calls in case we get a cutoff. for (auto& m : *this) m.value = PieceValue[MG][pos.piece_on(to_sq(m))] - Value(200 * relative_rank(pos.side_to_move(), to_sq(m))); }
Score Entry::do_king_safety(const Position& pos, Square ksq) { kingSquares[Us] = ksq; castlingRights[Us] = pos.can_castle(Us); minKPdistance[Us] = 0; Bitboard pawns = pos.pieces(Us, PAWN); if (pawns) while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {} if (relative_rank(Us, ksq) > RANK_4) return make_score(0, -16 * minKPdistance[Us]); Value bonus = shelter_storm<Us>(pos, ksq); // If we can castle use the bonus after the castling if it is bigger if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right)) bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1))); if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right)) bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1))); return make_score(bonus, -16 * minKPdistance[Us]); }
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 }
ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame); assert(pos.piece_count(weakerSide, BISHOP) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square wbsq = pos.piece_list(strongerSide, BISHOP, 0); Square bbsq = pos.piece_list(weakerSide, BISHOP, 0); if (same_color_squares(wbsq, bbsq)) // Not opposite-colored bishops, no scaling return SCALE_FACTOR_NONE; Square ksq = pos.king_square(weakerSide); Square psq1 = pos.piece_list(strongerSide, PAWN, 0); Square psq2 = pos.piece_list(strongerSide, PAWN, 1); Rank r1 = square_rank(psq1); Rank r2 = square_rank(psq2); Square blockSq1, blockSq2; if (relative_rank(strongerSide, psq1) > relative_rank(strongerSide, psq2)) { blockSq1 = psq1 + pawn_push(strongerSide); blockSq2 = make_square(square_file(psq2), square_rank(psq1)); } else { blockSq1 = psq2 + pawn_push(strongerSide); blockSq2 = make_square(square_file(psq1), square_rank(psq2)); } switch (file_distance(psq1, psq2)) { case 0: // Both pawns are on the same file. Easy draw if defender firmly controls // some square in the frontmost pawn's path. if ( square_file(ksq) == square_file(blockSq1) && relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1) && !same_color_squares(ksq, wbsq)) return SCALE_FACTOR_ZERO; else return SCALE_FACTOR_NONE; case 1: // Pawns on neighboring files. Draw if defender firmly controls the square // in front of the frontmost pawn's path, and the square diagonally behind // this square on the file of the other pawn. if ( ksq == blockSq1 && !same_color_squares(ksq, wbsq) && ( bbsq == blockSq2 || (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide)) || rank_distance(r1, r2) >= 2)) return SCALE_FACTOR_ZERO; else if ( ksq == blockSq2 && !same_color_squares(ksq, wbsq) && ( bbsq == blockSq1 || (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide)))) return SCALE_FACTOR_ZERO; else return SCALE_FACTOR_NONE; default: // The pawns are not on the same file or adjacent files. No scaling. return SCALE_FACTOR_NONE; } }