S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
- // OutpostRank[Rank] contains a bonus according to the rank of the outpost
- constexpr Score OutpostRank[RANK_NB] = {
- S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19)
- };
-
+ // KingProximity contains a penalty according to distance from king
+ constexpr Score KingProximity = S(1, 3);
+
// Assorted bonuses and penalties
constexpr Score BishopPawns = S( 3, 7);
constexpr Score CorneredBishop = S( 50, 50);
// Find our pawns that are blocked or on the first two ranks
Bitboard b = pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | LowRanks);
- // Squares occupied by those pawns, by our king or queen or controlled by
- // enemy pawns are excluded from the mobility area.
+ // Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king
+ // or controlled by enemy pawns are excluded from the mobility area.
- mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));
+ if (pos.must_capture())
+ mobilityArea[Us] = AllSquares;
+ else
- mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them) | shift<Down>(pos.pieces(Them, SHOGI_PAWN, SOLDIER)));
++ mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them) | shift<Down>(pos.pieces(Them, SHOGI_PAWN, SOLDIER)));
// Initialize attackedBy[] for king and pawns
- attackedBy[Us][KING] = pos.attacks_from<KING>(ksq);
+ attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from<KING>(ksq, Us) : Bitboard(0);
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
- attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
- attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]);
+ attackedBy[Us][SHOGI_PAWN] = shift<Up>(pos.pieces(Us, SHOGI_PAWN));
+ attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN];
+ attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN])
+ | (attackedBy[Us][KING] & attackedBy[Us][SHOGI_PAWN])
+ | (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN])
+ | dblAttackByPawn;
// Init our king safety tables
- Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G),
- clamp(rank_of(ksq), RANK_2, RANK_7));
- kingRing[Us] = PseudoAttacks[KING][s] | s;
+ if (!pos.count<KING>(Us))
+ kingRing[Us] = Bitboard(0);
+ else
+ {
- Square s = make_square(clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1)),
- clamp(rank_of(ksq), RANK_2, Rank(pos.max_rank() - 1)));
- kingRing[Us] = s | PseudoAttacks[Us][KING][s];
++ Square s = make_square(clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1)),
++ clamp(rank_of(ksq), RANK_2, Rank(pos.max_rank() - 1)));
++ kingRing[Us] = PseudoAttacks[Us][KING][s] | s;
+ }
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
int kingFlankDefense = popcount(b3);
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 185 * popcount(kingRing[Us] & weak)
+ + kingAttackersCountInHand[Them] * kingAttackersWeight[Them]
+ + kingAttackersCount[Them] * kingAttackersWeightInHand[Them]
+ + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + pos.check_counting())
+ 148 * popcount(unsafeChecks)
+ 98 * popcount(pos.blockers_for_king(Us))
- + 69 * kingAttacksCount[Them]
+ + 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2
- + 4 * (kingFlankAttack - kingFlankDefense)
+ 3 * kingFlankAttack * kingFlankAttack / 8
+ mg_value(mobility[Them] - mobility[Us])
- - 873 * !pos.count<QUEEN>(Them)
+ - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand() || pos.king_type() == WAZIR) / (1 + pos.check_counting())
- 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
- - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING])
- 6 * mg_value(score) / 8
- - 7;
+ - 4 * kingFlankDefense
+ + 37;
// Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 100)
int w = 5 * r - 13;
Square blockSq = s + Up;
- // Adjust bonus based on the king's proximity
- bonus += make_score(0, ( (king_proximity(Them, blockSq) * 19) / 4
- - king_proximity(Us, blockSq) * 2) * w);
+ // Skip bonus for antichess variants
+ if (pos.extinction_value() != VALUE_MATE)
+ {
+ // Adjust bonus based on the king's proximity
- bonus += make_score(0, ( king_proximity(Them, blockSq) * 5
- - king_proximity(Us, blockSq) * 2) * w);
++ bonus += make_score(0, ( (king_proximity(Them, blockSq) * 19) / 4
++ - king_proximity(Us, blockSq) * 2) * w);
- // If blockSq is not the queening square then consider also a second push
- if (r != RANK_7)
- bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
+ // If blockSq is not the queening square then consider also a second push
+ if (r != RANK_7)
+ bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
+ }
// If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
{
if ( pos.opposite_bishops()
&& pos.non_pawn_material() == 2 * BishopValueMg)
- sf = 16 + 4 * pe->passed_count();
+ sf = 22 ;
else
- sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count<PAWN>(strongSide));
+ sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * (pos.count<PAWN>(strongSide) + pos.count<SOLDIER>(strongSide)));
sf = std::max(0, sf - (pos.rule50_count() - 12) / 4);
}
{ S(-4,-38), S(10,-18), S( 6,-12), S( 8, 1) },
{ S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) },
{ S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) }
- },
- { // King
+ }
+};
+
+constexpr Score KingBonus[RANK_NB][int(FILE_NB) / 2] = {
- { S(271, 1), S(327, 45), S(270, 85), S(192, 76) },
- { S(278, 53), S(303,100), S(230,133), S(174,135) },
+ { S(271, 1), S(327, 45), S(271, 85), S(198, 76) },
+ { S(278, 53), S(303,100), S(234,133), S(179,135) },
{ S(195, 88), S(258,130), S(169,169), S(120,175) },
{ S(164,103), S(190,156), S(138,172), S( 98,172) },
{ S(154, 96), S(179,166), S(105,199), S( 70,199) },
&& eval <= alpha - RazorMargin)
return qsearch<NT>(pos, ss, alpha, beta);
- improving = ss->staticEval >= (ss-2)->staticEval
- || (ss-2)->staticEval == VALUE_NONE;
+ improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval >= (ss-4)->staticEval
+ || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval >= (ss-2)->staticEval;
+ // Skip early pruning in case of mandatory capture
+ if (pos.must_capture() && MoveList<CAPTURES>(pos).size())
+ goto moves_loop;
+
// Step 8. Futility pruning: child node (~30 Elo)
if ( !PvNode
&& depth < 7
&& bestValue > VALUE_MATED_IN_MAX_PLY)
{
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
- moveCountPruning = moveCount >= futility_move_count(improving, depth);
+ moveCountPruning = moveCount >= futility_move_count(improving, depth)
+ || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move))));
if ( !captureOrPromotion
- && !givesCheck)
+ && !givesCheck
- && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us))
- && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count<ALL_PIECES>(us) == pos.count<PAWN>(us)))
++ && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us)))
{
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0);
&& ( !captureOrPromotion
|| moveCountPruning
|| ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
- || cutNode)
+ || cutNode
- || thisThread->ttHitAverage < 384 * ttHitAverageResolution * ttHitAverageWindow / 1024))
++ || thisThread->ttHitAverage < 384 * ttHitAverageResolution * ttHitAverageWindow / 1024)
+ && !(pos.must_capture() && MoveList<CAPTURES>(pos).size()))
{
Depth r = reduction(improving, depth, moveCount);