No functional change.
}
+/// make_bitboard() returns a bitboard from a list of squares
+
+constexpr Bitboard make_bitboard() { return 0; }
+
+template<typename ...Squares>
+constexpr Bitboard make_bitboard(Square s, Squares... squares) {
+ return (Bitboard(1) << s) | make_bitboard(squares...);
+}
+
+
- /// shift() moves a bitboard one step along direction D (mainly for pawns)
+ /// shift() moves a bitboard one step along direction D
template<Direction D>
constexpr Bitboard shift(Bitboard b) {
S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7)
};
+ // KingProximity contains a penalty according to distance from king
+ constexpr Score KingProximity = S(2, 2);
+
// Assorted bonuses and penalties
constexpr Score BishopPawns = S( 3, 7);
- constexpr Score CloseEnemies = S( 8, 0);
constexpr Score CorneredBishop = S( 50, 50);
+ constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
constexpr Score KingProtector = S( 7, 8);
constexpr Score KnightOnQueen = S( 16, 12);
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH);
- constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
+ Bitboard LowRanks = rank_bb(relative_rank(Us, RANK_2, pos.max_rank())) | rank_bb(relative_rank(Us, RANK_3, pos.max_rank()));
- const Square ksq = pos.square<KING>(Us);
++ const Square ksq = pos.count<KING>(Us) ? pos.square<KING>(Us) : SQ_NONE;
+
// 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 or controlled by
+ // enemy pawns are excluded from the mobility area.
- mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | 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)));
- // Initialise attackedBy bitboards for kings and pawns
- attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from<KING>(Us, pos.square<KING>(Us)) : 0;
- attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
+ // 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>(Us, ksq) : 0;
+ attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
- attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
- attackedBy2[Us] = 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]);
// Init our king safety tables
kingRing[Us] = attackedBy[Us][KING];
- if (pos.count<KING>(Us) && relative_rank(Us, pos.square<KING>(Us), pos.max_rank()) == RANK_1)
- if (relative_rank(Us, ksq) == RANK_1)
++ if (pos.count<KING>(Us) && relative_rank(Us, ksq) == RANK_1)
kingRing[Us] |= shift<Up>(kingRing[Us]);
- if (pos.count<KING>(Us) && file_of(pos.square<KING>(Us)) == pos.max_file())
- if (file_of(ksq) == FILE_H)
++ if (pos.count<KING>(Us) && file_of(ksq) == pos.max_file())
kingRing[Us] |= shift<WEST>(kingRing[Us]);
- else if (pos.count<KING>(Us) && file_of(pos.square<KING>(Us)) == FILE_A)
- else if (file_of(ksq) == FILE_A)
++ else if (pos.count<KING>(Us) && file_of(ksq) == FILE_A)
kingRing[Us] |= shift<EAST>(kingRing[Us]);
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
- kingRing[Us] &= ~double_pawn_attacks_bb<Us>(pos.pieces(Us, PAWN));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
+
+ // Remove from kingRing[] the squares defended by two pawns
+ kingRing[Us] &= ~pawn_double_attacks_bb<Us>(pos.pieces(Us, PAWN));
++
+ kingRing[Us] &= pos.board_bb();
}
constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH);
constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
: Rank5BB | Rank4BB | Rank3BB);
- const Square* pl = pos.squares<Pt>(Us);
+ const Square* pl = pos.squares(Us, Pt);
Bitboard b, bb;
- Square s;
Score score = SCORE_ZERO;
attackedBy[Us][Pt] = 0;
Score Evaluation<T>::king() const {
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
- : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
+ Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank());
+ Bitboard Camp = AllSquares ^ forward_ranks_bb(Us, r);
+
+ if (!pos.count<KING>(Us) || !pos.checking_permitted())
+ return SCORE_ZERO;
- Bitboard weak, b, b1, b2, safe, unsafeChecks = 0;
++ Bitboard weak, b, b1, b2, safe, QueenCheck, unsafeChecks = 0;
+ int kingDanger = 0;
const Square ksq = pos.square<KING>(Us);
- Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks, QueenCheck;
- // King shelter and enemy pawns storm
+ // Init the score with king shelter and enemy pawns storm
Score score = pe->king_safety<Us>(pos);
- // Find the squares that opponent attacks in our king flank, and the squares
- // which are attacked twice in that flank but not defended by our pawns.
- File f = std::max(std::min(file_of(ksq), File(pos.max_file() - 1)), FILE_B);
- kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(f) | adjacent_files_bb(f);
- b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp;
- b2 = b1 & attackedBy2[Them];
-
- int tropism = popcount(b1) + popcount(b2);
-
- // Main king safety evaluation
- int kingDanger = 0;
- unsafeChecks = 0;
-
// Attacked squares defended at most once by our queen or king
weak = attackedBy[Them][ALL_PIECES]
& ~attackedBy2[Us]
// the square is in the attacker's mobility area.
unsafeChecks &= mobilityArea[Them];
++ File f = std::max(std::min(file_of(ksq), File(pos.max_file() - 1)), FILE_B);
++ Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(f) | adjacent_files_bb(f);
++
+ // Find the squares that opponent attacks in our king flank, and the squares
+ // which are attacked twice in that flank.
- b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
++ b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp;
+ b2 = b1 & attackedBy2[Them];
+
+ int kingFlankAttacks = popcount(b1) + popcount(b2);
+
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 69 * kingAttacksCount[Them]
- + 185 * popcount(kingRing[Us] & weak)
+ + 69 * kingAttacksCount[Them] * (1 + 2 * !!pos.max_check_count())
+ + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + !!pos.max_check_count())
- 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
+ 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
- + 5 * tropism * tropism / 16
- - 873 * !pos.count<QUEEN>(Them)
+ - 873 * !(pos.count<QUEEN>(Them) || pos.captures_to_hand()) / (1 + !!pos.max_check_count())
- 6 * mg_value(score) / 8
+ mg_value(mobility[Them] - mobility[Us])
+ + 5 * kingFlankAttacks * kingFlankAttacks / 16
- 25;
// Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 0)
- score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
+ score -= make_score(std::min(kingDanger * kingDanger / 4096, 3000), kingDanger / 16);
// Penalty when our king is on a pawnless flank
- if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)]))
+ if (!(pos.pieces(PAWN) & kingFlank))
score -= PawnlessFlank;
- // Penalty if king flank is under attack, potentially moving toward the king
- score -= FlankAttacks * kingFlankAttacks;
+ // King tropism bonus, to anticipate slow motion attacks on our king
- score -= CloseEnemies * tropism * (1 + pos.captures_to_hand() + !!pos.max_check_count());
++ score -= FlankAttacks * kingFlankAttacks * (1 + pos.captures_to_hand() + !!pos.max_check_count());
+
+ // For drop games, king danger is independent of game phase
+ if (pos.captures_to_hand())
+ score = make_score(mg_value(score), mg_value(score)) / (1 + !pos.shogi_doubled_pawn());
if (T)
Trace::add(KING, Us, 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;
+ Value v = mg_value(score) * int(me->game_phase())
+ + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL;
- v /= int(PHASE_MIDGAME);
+ v /= PHASE_MIDGAME;
// In case of tracing add all remaining individual evaluation terms
if (T)
{ S(-48,-51), S( -3,-40), S(-12,-39), S(-25,-20) }
},
{ // Rook
- { S(-24, -2), S(-13,-6), S( -7, -3), S( 2,-2) },
- { S(-18,-10), S(-10,-7), S( -5, 1), S( 9, 0) },
- { S(-21, 10), S( -7,-4), S( 3, 2), S(-1,-2) },
- { S(-13, -5), S( -5, 2), S( -4, -8), S(-6, 8) },
- { S(-24, -8), S(-12, 5), S( -1, 4), S( 6,-9) },
- { S(-24, 3), S( -4,-2), S( 4,-10), S(10, 7) },
- { S( -8, 1), S( 6, 2), S( 10, 17), S(12,-8) },
- { S(-22, 12), S(-24,-6), S( -6, 13), S( 4, 7) }
+ { S(-24, -2), S(-13,-6), S(-7, -3), S( 2,-2) },
+ { S(-18,-10), S(-10,-7), S(-5, 1), S( 9, 0) },
+ { S(-21, 10), S( -7,-4), S( 3, 2), S(-1,-2) },
+ { S(-13, -5), S( -5, 2), S(-4, -8), S(-6, 8) },
+ { S(-24, -8), S(-12, 5), S(-1, 4), S( 6,-9) },
+ { S(-24, 3), S( -4,-2), S( 4,-10), S(10, 7) },
+ { S( -8, 1), S( 6, 2), S(10, 17), S(12,-8) },
+ { S(-22, 12), S(-24,-6), S(-6, 13), S( 4, 7) }
},
{ // Queen
- { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) },
- { S( -3,-55), S( 5,-31), S( 8,-22), S(12, -4) },
- { S( -3,-39), S( 6,-18), S(13, -9), S( 7, 3) },
- { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) },
- { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) },
- { 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) }
+ { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) },
+ { S(-3,-55), S( 5,-31), S( 8,-22), S(12, -4) },
+ { S(-3,-39), S( 6,-18), S(13, -9), S( 7, 3) },
+ { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) },
+ { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) },
+ { 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(272, 0), S(325, 41), S(273, 80), S(190, 93) },
{ S(277, 57), S(305, 98), S(241,138), S(183,131) },
{ S(198, 86), S(253,138), S(168,165), S(120,173) },
{ S(169,103), S(191,152), S(136,168), S(108,169) },
- { S(145, 98), S(176,166), S(112,197), S(69, 194) },
- { S(122, 87), S(159,164), S(85, 174), S(36, 189) },
- { S(87, 40), S(120, 99), S(64, 128), S(25, 141) },
- { S(64, 5), S(87, 60), S(49, 75), S(0, 75) }
+ { S(145, 98), S(176,166), S(112,197), S( 69,194) },
+ { S(122, 87), S(159,164), S( 85,174), S( 36,189) },
+ { S( 87, 40), S(120, 99), S( 64,128), S( 25,141) },
+ { S( 64, 5), S( 87, 60), S( 49, 75), S( 0, 75) }
- }
};
constexpr Score PBonus[RANK_NB][FILE_NB] =
ss->staticEval = eval = pureStaticEval + bonus;
}
else
- ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo;
+ ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::tempo_value(pos);
- tte->save(posKey, VALUE_NONE, pvHit, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
+ tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
}
// Step 7. Razoring (~2 Elo)