Rev 154 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
96 | pmbaty | 1 | /* |
2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 |
||
3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) |
||
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
||
5 | Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
||
6 | |||
7 | Stockfish is free software: you can redistribute it and/or modify |
||
8 | it under the terms of the GNU General Public License as published by |
||
9 | the Free Software Foundation, either version 3 of the License, or |
||
10 | (at your option) any later version. |
||
11 | |||
12 | Stockfish is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
19 | */ |
||
20 | |||
21 | #include <algorithm> |
||
22 | #include <cassert> |
||
23 | #include <cstring> // For std::memset |
||
24 | #include <iomanip> |
||
25 | #include <sstream> |
||
26 | |||
27 | #include "bitcount.h" |
||
28 | #include "evaluate.h" |
||
29 | #include "material.h" |
||
30 | #include "pawns.h" |
||
31 | |||
32 | namespace { |
||
33 | |||
34 | namespace Trace { |
||
35 | |||
36 | enum Term { // The first 8 entries are for PieceType |
||
37 | MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB |
||
38 | }; |
||
39 | |||
40 | double scores[TERM_NB][COLOR_NB][PHASE_NB]; |
||
41 | |||
42 | double to_cp(Value v) { return double(v) / PawnValueEg; } |
||
43 | |||
44 | void add(int idx, Color c, Score s) { |
||
45 | scores[idx][c][MG] = to_cp(mg_value(s)); |
||
46 | scores[idx][c][EG] = to_cp(eg_value(s)); |
||
47 | } |
||
48 | |||
49 | void add(int idx, Score w, Score b = SCORE_ZERO) { |
||
50 | add(idx, WHITE, w); add(idx, BLACK, b); |
||
51 | } |
||
52 | |||
53 | std::ostream& operator<<(std::ostream& os, Term t) { |
||
54 | |||
55 | if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL) |
||
56 | os << " --- --- | --- --- | "; |
||
57 | else |
||
58 | os << std::setw(5) << scores[t][WHITE][MG] << " " |
||
59 | << std::setw(5) << scores[t][WHITE][EG] << " | " |
||
60 | << std::setw(5) << scores[t][BLACK][MG] << " " |
||
61 | << std::setw(5) << scores[t][BLACK][EG] << " | "; |
||
62 | |||
63 | os << std::setw(5) << scores[t][WHITE][MG] - scores[t][BLACK][MG] << " " |
||
64 | << std::setw(5) << scores[t][WHITE][EG] - scores[t][BLACK][EG] << " \n"; |
||
65 | |||
66 | return os; |
||
67 | } |
||
68 | } |
||
69 | |||
70 | using namespace Trace; |
||
71 | |||
72 | // Struct EvalInfo contains various information computed and collected |
||
73 | // by the evaluation functions. |
||
74 | struct EvalInfo { |
||
75 | |||
76 | // attackedBy[color][piece type] is a bitboard representing all squares |
||
77 | // attacked by a given color and piece type (can be also ALL_PIECES). |
||
78 | Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; |
||
79 | |||
80 | // kingRing[color] is the zone around the king which is considered |
||
81 | // by the king safety evaluation. This consists of the squares directly |
||
82 | // adjacent to the king, and the three (or two, for a king on an edge file) |
||
83 | // squares two ranks in front of the king. For instance, if black's king |
||
84 | // is on g8, kingRing[BLACK] is a bitboard containing the squares f8, h8, |
||
85 | // f7, g7, h7, f6, g6 and h6. |
||
86 | Bitboard kingRing[COLOR_NB]; |
||
87 | |||
88 | // kingAttackersCount[color] is the number of pieces of the given color |
||
89 | // which attack a square in the kingRing of the enemy king. |
||
90 | int kingAttackersCount[COLOR_NB]; |
||
91 | |||
92 | // kingAttackersWeight[color] is the sum of the "weights" of the pieces of the |
||
93 | // given color which attack a square in the kingRing of the enemy king. The |
||
94 | // weights of the individual piece types are given by the elements in the |
||
95 | // KingAttackWeights array. |
||
96 | int kingAttackersWeight[COLOR_NB]; |
||
97 | |||
98 | // kingAdjacentZoneAttacksCount[color] is the number of attacks by the given |
||
99 | // color to squares directly adjacent to the enemy king. Pieces which attack |
||
100 | // more than one square are counted multiple times. For instance, if there is |
||
101 | // a white knight on g5 and black's king is on g8, this white knight adds 2 |
||
102 | // to kingAdjacentZoneAttacksCount[WHITE]. |
||
103 | int kingAdjacentZoneAttacksCount[COLOR_NB]; |
||
104 | |||
105 | Bitboard pinnedPieces[COLOR_NB]; |
||
106 | Material::Entry* me; |
||
107 | Pawns::Entry* pi; |
||
108 | }; |
||
109 | |||
110 | #define V(v) Value(v) |
||
111 | #define S(mg, eg) make_score(mg, eg) |
||
112 | |||
113 | // MobilityBonus[PieceType][attacked] contains bonuses for middle and end |
||
114 | // game, indexed by piece type and number of attacked squares in the MobilityArea. |
||
115 | const Score MobilityBonus[][32] = { |
||
116 | {}, {}, |
||
117 | { S(-75,-76), S(-56,-54), S(- 9,-26), S( -2,-10), S( 6, 5), S( 15, 11), // Knights |
||
118 | S( 22, 26), S( 30, 28), S( 36, 29) }, |
||
119 | { S(-48,-58), S(-21,-19), S( 16, -2), S( 26, 12), S( 37, 22), S( 51, 42), // Bishops |
||
120 | S( 54, 54), S( 63, 58), S( 65, 63), S( 71, 70), S( 79, 74), S( 81, 86), |
||
121 | S( 92, 90), S( 97, 94) }, |
||
122 | { S(-56,-78), S(-25,-18), S(-11, 26), S( -5, 55), S( -4, 70), S( -1, 81), // Rooks |
||
123 | S( 8,109), S( 14,120), S( 21,128), S( 23,143), S( 31,154), S( 32,160), |
||
124 | S( 43,165), S( 49,168), S( 59,169) }, |
||
125 | { S(-40,-35), S(-25,-12), S( 2, 7), S( 4, 19), S( 14, 37), S( 24, 55), // Queens |
||
126 | S( 25, 62), S( 40, 76), S( 43, 79), S( 47, 87), S( 54, 94), S( 56,102), |
||
127 | S( 60,111), S( 70,116), S( 72,118), S( 73,122), S( 75,128), S( 77,130), |
||
128 | S( 85,133), S( 94,136), S( 99,140), S(108,157), S(112,158), S(113,161), |
||
129 | S(118,174), S(119,177), S(123,191), S(128,199) } |
||
130 | }; |
||
131 | |||
132 | // Outpost[knight/bishop][supported by pawn] contains bonuses for knights and |
||
133 | // bishops outposts, bigger if outpost piece is supported by a pawn. |
||
134 | const Score Outpost[][2] = { |
||
135 | { S(42,11), S(63,17) }, // Knights |
||
136 | { S(18, 5), S(27, 8) } // Bishops |
||
137 | }; |
||
138 | |||
139 | // ReachableOutpost[knight/bishop][supported by pawn] contains bonuses for |
||
140 | // knights and bishops which can reach an outpost square in one move, bigger |
||
141 | // if outpost square is supported by a pawn. |
||
142 | const Score ReachableOutpost[][2] = { |
||
143 | { S(21, 5), S(31, 8) }, // Knights |
||
144 | { S( 8, 2), S(13, 4) } // Bishops |
||
145 | }; |
||
146 | |||
147 | // RookOnFile[semiopen/open] contains bonuses for each rook when there is no |
||
148 | // friendly pawn on the rook file. |
||
149 | const Score RookOnFile[2] = { S(19, 10), S(43, 21) }; |
||
150 | |||
151 | // ThreatBySafePawn[PieceType] contains bonuses according to which piece |
||
152 | // type is attacked by a pawn which is protected or is not attacked. |
||
153 | const Score ThreatBySafePawn[PIECE_TYPE_NB] = { |
||
154 | S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) }; |
||
155 | |||
156 | // Threat[by minor/by rook][attacked PieceType] contains |
||
157 | // bonuses according to which piece type attacks which one. |
||
158 | // Attacks on lesser pieces which are pawn-defended are not considered. |
||
159 | const Score Threat[][PIECE_TYPE_NB] = { |
||
160 | { S(0, 0), S(0, 33), S(45, 43), S(46, 47), S(72,107), S(48,118) }, // by Minor |
||
161 | { S(0, 0), S(0, 25), S(40, 62), S(40, 59), S( 0, 34), S(35, 48) } // by Rook |
||
162 | }; |
||
163 | |||
164 | // ThreatByKing[on one/on many] contains bonuses for King attacks on |
||
165 | // pawns or pieces which are not pawn-defended. |
||
166 | const Score ThreatByKing[2] = { S(3, 62), S(9, 138) }; |
||
167 | |||
168 | // Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns. |
||
169 | // We don't use a Score because we process the two components independently. |
||
170 | const Value Passed[][RANK_NB] = { |
||
171 | { V(0), V( 1), V(26), V(68), V(161), V(247) }, |
||
172 | { V(7), V(14), V(38), V(64), V(137), V(193) } |
||
173 | }; |
||
174 | |||
175 | // PassedFile[File] contains a bonus according to the file of a passed pawn |
||
176 | const Score PassedFile[FILE_NB] = { |
||
177 | S( 9, 10), S( 2, 10), S( 1, -8), S(-20,-12), |
||
178 | S(-20,-12), S( 1, -8), S( 2, 10), S( 9, 10) |
||
179 | }; |
||
180 | |||
181 | // Assorted bonuses and penalties used by evaluation |
||
182 | const Score MinorBehindPawn = S(16, 0); |
||
183 | const Score BishopPawns = S( 8, 12); |
||
184 | const Score RookOnPawn = S( 7, 27); |
||
185 | const Score TrappedRook = S(92, 0); |
||
186 | const Score Checked = S(20, 20); |
||
187 | const Score ThreatByHangingPawn = S(70, 63); |
||
188 | const Score Hanging = S(48, 28); |
||
189 | const Score ThreatByPawnPush = S(31, 19); |
||
190 | const Score Unstoppable = S( 0, 20); |
||
191 | |||
192 | // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by |
||
193 | // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only |
||
194 | // happen in Chess960 games. |
||
195 | const Score TrappedBishopA1H1 = S(50, 50); |
||
196 | |||
197 | #undef S |
||
198 | #undef V |
||
199 | |||
200 | // King danger constants and variables. The king danger scores are looked-up |
||
201 | // in KingDanger[]. Various little "meta-bonuses" measuring the strength |
||
202 | // of the enemy attack are added up into an integer, which is used as an |
||
203 | // index to KingDanger[]. |
||
204 | Score KingDanger[512]; |
||
205 | |||
206 | // KingAttackWeights[PieceType] contains king attack weights by piece type |
||
207 | const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 7, 5, 4, 1 }; |
||
208 | |||
209 | // Penalties for enemy's safe checks |
||
210 | const int QueenContactCheck = 89; |
||
211 | const int QueenCheck = 50; |
||
212 | const int RookCheck = 45; |
||
213 | const int BishopCheck = 6; |
||
214 | const int KnightCheck = 14; |
||
215 | |||
216 | |||
217 | // eval_init() initializes king and attack bitboards for a given color |
||
218 | // adding pawn attacks. To be done at the beginning of the evaluation. |
||
219 | |||
220 | template<Color Us> |
||
221 | void eval_init(const Position& pos, EvalInfo& ei) { |
||
222 | |||
223 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
224 | const Square Down = (Us == WHITE ? DELTA_S : DELTA_N); |
||
225 | |||
226 | ei.pinnedPieces[Us] = pos.pinned_pieces(Us); |
||
227 | Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.square<KING>(Them)); |
||
228 | ei.attackedBy[Them][ALL_PIECES] |= b; |
||
229 | ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); |
||
230 | |||
231 | // Init king safety tables only if we are going to use them |
||
232 | if (pos.non_pawn_material(Us) >= QueenValueMg) |
||
233 | { |
||
234 | ei.kingRing[Them] = b | shift_bb<Down>(b); |
||
235 | b &= ei.attackedBy[Us][PAWN]; |
||
236 | ei.kingAttackersCount[Us] = b ? popcount<Max15>(b) : 0; |
||
237 | ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0; |
||
238 | } |
||
239 | else |
||
240 | ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0; |
||
241 | } |
||
242 | |||
243 | |||
244 | // evaluate_pieces() assigns bonuses and penalties to the pieces of a given |
||
245 | // color and type. |
||
246 | |||
247 | template<bool DoTrace, Color Us = WHITE, PieceType Pt = KNIGHT> |
||
248 | Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, |
||
249 | const Bitboard* mobilityArea) { |
||
250 | Bitboard b, bb; |
||
251 | Square s; |
||
252 | Score score = SCORE_ZERO; |
||
253 | |||
254 | const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1)); |
||
255 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
256 | const Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB |
||
257 | : Rank5BB | Rank4BB | Rank3BB); |
||
258 | const Square* pl = pos.squares<Pt>(Us); |
||
259 | |||
260 | ei.attackedBy[Us][Pt] = 0; |
||
261 | |||
262 | while ((s = *pl++) != SQ_NONE) |
||
263 | { |
||
264 | // Find attacked squares, including x-ray attacks for bishops and rooks |
||
265 | b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN)) |
||
266 | : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN)) |
||
267 | : pos.attacks_from<Pt>(s); |
||
268 | |||
269 | if (ei.pinnedPieces[Us] & s) |
||
270 | b &= LineBB[pos.square<KING>(Us)][s]; |
||
271 | |||
272 | ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b; |
||
273 | |||
274 | if (b & ei.kingRing[Them]) |
||
275 | { |
||
276 | ei.kingAttackersCount[Us]++; |
||
277 | ei.kingAttackersWeight[Us] += KingAttackWeights[Pt]; |
||
278 | bb = b & ei.attackedBy[Them][KING]; |
||
279 | if (bb) |
||
280 | ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb); |
||
281 | } |
||
282 | |||
283 | if (Pt == QUEEN) |
||
284 | b &= ~( ei.attackedBy[Them][KNIGHT] |
||
285 | | ei.attackedBy[Them][BISHOP] |
||
286 | | ei.attackedBy[Them][ROOK]); |
||
287 | |||
288 | int mob = popcount<Pt == QUEEN ? Full : Max15>(b & mobilityArea[Us]); |
||
289 | |||
290 | mobility[Us] += MobilityBonus[Pt][mob]; |
||
291 | |||
292 | if (Pt == BISHOP || Pt == KNIGHT) |
||
293 | { |
||
294 | // Bonus for outpost squares |
||
295 | bb = OutpostRanks & ~ei.pi->pawn_attacks_span(Them); |
||
296 | if (bb & s) |
||
297 | score += Outpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & s)]; |
||
298 | else |
||
299 | { |
||
300 | bb &= b & ~pos.pieces(Us); |
||
301 | if (bb) |
||
302 | score += ReachableOutpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & bb)]; |
||
303 | } |
||
304 | |||
305 | // Bonus when behind a pawn |
||
306 | if ( relative_rank(Us, s) < RANK_5 |
||
307 | && (pos.pieces(PAWN) & (s + pawn_push(Us)))) |
||
308 | score += MinorBehindPawn; |
||
309 | |||
310 | // Penalty for pawns on the same color square as the bishop |
||
311 | if (Pt == BISHOP) |
||
312 | score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s); |
||
313 | |||
314 | // An important Chess960 pattern: A cornered bishop blocked by a friendly |
||
315 | // pawn diagonally in front of it is a very serious problem, especially |
||
316 | // when that pawn is also blocked. |
||
317 | if ( Pt == BISHOP |
||
318 | && pos.is_chess960() |
||
319 | && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) |
||
320 | { |
||
321 | Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W); |
||
322 | if (pos.piece_on(s + d) == make_piece(Us, PAWN)) |
||
323 | score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4 |
||
324 | : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2 |
||
325 | : TrappedBishopA1H1; |
||
326 | } |
||
327 | } |
||
328 | |||
329 | if (Pt == ROOK) |
||
330 | { |
||
331 | // Bonus for aligning with enemy pawns on the same rank/file |
||
332 | if (relative_rank(Us, s) >= RANK_5) |
||
333 | { |
||
334 | Bitboard alignedPawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]; |
||
335 | if (alignedPawns) |
||
336 | score += RookOnPawn * popcount<Max15>(alignedPawns); |
||
337 | } |
||
338 | |||
339 | // Bonus when on an open or semi-open file |
||
340 | if (ei.pi->semiopen_file(Us, file_of(s))) |
||
341 | score += RookOnFile[!!ei.pi->semiopen_file(Them, file_of(s))]; |
||
342 | |||
343 | // Penalize when trapped by the king, even more if the king cannot castle |
||
344 | else if (mob <= 3) |
||
345 | { |
||
346 | Square ksq = pos.square<KING>(Us); |
||
347 | |||
348 | if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq))) |
||
349 | && (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1) |
||
350 | && !ei.pi->semiopen_side(Us, file_of(ksq), file_of(s) < file_of(ksq))) |
||
351 | score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us)); |
||
352 | } |
||
353 | } |
||
354 | } |
||
355 | |||
356 | if (DoTrace) |
||
357 | Trace::add(Pt, Us, score); |
||
358 | |||
359 | // Recursively call evaluate_pieces() of next piece type until KING is excluded |
||
360 | return score - evaluate_pieces<DoTrace, Them, NextPt>(pos, ei, mobility, mobilityArea); |
||
361 | } |
||
362 | |||
363 | template<> |
||
364 | Score evaluate_pieces<false, WHITE, KING>(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; } |
||
365 | template<> |
||
366 | Score evaluate_pieces< true, WHITE, KING>(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; } |
||
367 | |||
368 | |||
369 | // evaluate_king() assigns bonuses and penalties to a king of a given color |
||
370 | |||
371 | template<Color Us, bool DoTrace> |
||
372 | Score evaluate_king(const Position& pos, const EvalInfo& ei) { |
||
373 | |||
374 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
375 | |||
376 | Bitboard undefended, b, b1, b2, safe; |
||
377 | int attackUnits; |
||
378 | const Square ksq = pos.square<KING>(Us); |
||
379 | |||
380 | // King shelter and enemy pawns storm |
||
381 | Score score = ei.pi->king_safety<Us>(pos, ksq); |
||
382 | |||
383 | // Main king safety evaluation |
||
384 | if (ei.kingAttackersCount[Them]) |
||
385 | { |
||
386 | // Find the attacked squares around the king which have no defenders |
||
387 | // apart from the king itself. |
||
388 | undefended = ei.attackedBy[Them][ALL_PIECES] |
||
389 | & ei.attackedBy[Us][KING] |
||
390 | & ~( ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] |
||
391 | | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK] |
||
392 | | ei.attackedBy[Us][QUEEN]); |
||
393 | |||
394 | // Initialize the 'attackUnits' variable, which is used later on as an |
||
395 | // index into the KingDanger[] array. The initial value is based on the |
||
396 | // number and types of the enemy's attacking pieces, the number of |
||
397 | // attacked and undefended squares around our king and the quality of |
||
398 | // the pawn shelter (current 'score' value). |
||
399 | attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) |
||
400 | + 9 * ei.kingAdjacentZoneAttacksCount[Them] |
||
401 | + 27 * popcount<Max15>(undefended) |
||
402 | + 11 * !!ei.pinnedPieces[Us] |
||
403 | - 64 * !pos.count<QUEEN>(Them) |
||
404 | - mg_value(score) / 8; |
||
405 | |||
406 | // Analyse the enemy's safe queen contact checks. Firstly, find the |
||
407 | // undefended squares around the king reachable by the enemy queen... |
||
408 | b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them); |
||
409 | if (b) |
||
410 | { |
||
411 | // ...and then remove squares not supported by another enemy piece |
||
412 | b &= ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT] |
||
413 | | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK] |
||
414 | | ei.attackedBy[Them][KING]; |
||
415 | |||
416 | if (b) |
||
417 | attackUnits += QueenContactCheck * popcount<Max15>(b); |
||
418 | } |
||
419 | |||
420 | // Analyse the enemy's safe distance checks for sliders and knights |
||
421 | safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them)); |
||
422 | |||
423 | b1 = pos.attacks_from<ROOK >(ksq) & safe; |
||
424 | b2 = pos.attacks_from<BISHOP>(ksq) & safe; |
||
425 | |||
426 | // Enemy queen safe checks |
||
427 | b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; |
||
428 | if (b) |
||
429 | { |
||
430 | attackUnits += QueenCheck * popcount<Max15>(b); |
||
431 | score -= Checked; |
||
432 | } |
||
433 | |||
434 | // Enemy rooks safe checks |
||
435 | b = b1 & ei.attackedBy[Them][ROOK]; |
||
436 | if (b) |
||
437 | { |
||
438 | attackUnits += RookCheck * popcount<Max15>(b); |
||
439 | score -= Checked; |
||
440 | } |
||
441 | |||
442 | // Enemy bishops safe checks |
||
443 | b = b2 & ei.attackedBy[Them][BISHOP]; |
||
444 | if (b) |
||
445 | { |
||
446 | attackUnits += BishopCheck * popcount<Max15>(b); |
||
447 | score -= Checked; |
||
448 | } |
||
449 | |||
450 | // Enemy knights safe checks |
||
451 | b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe; |
||
452 | if (b) |
||
453 | { |
||
454 | attackUnits += KnightCheck * popcount<Max15>(b); |
||
455 | score -= Checked; |
||
456 | } |
||
457 | |||
458 | // Finally, extract the king danger score from the KingDanger[] |
||
459 | // array and subtract the score from the evaluation. |
||
460 | score -= KingDanger[std::max(std::min(attackUnits, 399), 0)]; |
||
461 | } |
||
462 | |||
463 | if (DoTrace) |
||
464 | Trace::add(KING, Us, score); |
||
465 | |||
466 | return score; |
||
467 | } |
||
468 | |||
469 | |||
470 | // evaluate_threats() assigns bonuses according to the types of the attacking |
||
471 | // and the attacked pieces. |
||
472 | |||
473 | template<Color Us, bool DoTrace> |
||
474 | Score evaluate_threats(const Position& pos, const EvalInfo& ei) { |
||
475 | |||
476 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
477 | const Square Up = (Us == WHITE ? DELTA_N : DELTA_S); |
||
478 | const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE); |
||
479 | const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW); |
||
480 | const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); |
||
481 | const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); |
||
482 | |||
483 | enum { Minor, Rook }; |
||
484 | |||
485 | Bitboard b, weak, defended, safeThreats; |
||
486 | Score score = SCORE_ZERO; |
||
487 | |||
488 | // Non-pawn enemies attacked by a pawn |
||
489 | weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN]; |
||
490 | |||
491 | if (weak) |
||
492 | { |
||
493 | b = pos.pieces(Us, PAWN) & ( ~ei.attackedBy[Them][ALL_PIECES] |
||
494 | | ei.attackedBy[Us][ALL_PIECES]); |
||
495 | |||
496 | safeThreats = (shift_bb<Right>(b) | shift_bb<Left>(b)) & weak; |
||
497 | |||
498 | if (weak ^ safeThreats) |
||
499 | score += ThreatByHangingPawn; |
||
500 | |||
501 | while (safeThreats) |
||
502 | score += ThreatBySafePawn[type_of(pos.piece_on(pop_lsb(&safeThreats)))]; |
||
503 | } |
||
504 | |||
505 | // Non-pawn enemies defended by a pawn |
||
506 | defended = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Them][PAWN]; |
||
507 | |||
508 | // Enemies not defended by a pawn and under our attack |
||
509 | weak = pos.pieces(Them) |
||
510 | & ~ei.attackedBy[Them][PAWN] |
||
511 | & ei.attackedBy[Us][ALL_PIECES]; |
||
512 | |||
513 | // Add a bonus according to the kind of attacking pieces |
||
514 | if (defended | weak) |
||
515 | { |
||
516 | b = (defended | weak) & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]); |
||
517 | while (b) |
||
518 | score += Threat[Minor][type_of(pos.piece_on(pop_lsb(&b)))]; |
||
519 | |||
520 | b = (pos.pieces(Them, QUEEN) | weak) & ei.attackedBy[Us][ROOK]; |
||
521 | while (b) |
||
522 | score += Threat[Rook ][type_of(pos.piece_on(pop_lsb(&b)))]; |
||
523 | |||
524 | b = weak & ~ei.attackedBy[Them][ALL_PIECES]; |
||
525 | if (b) |
||
526 | score += Hanging * popcount<Max15>(b); |
||
527 | |||
528 | b = weak & ei.attackedBy[Us][KING]; |
||
529 | if (b) |
||
530 | score += ThreatByKing[more_than_one(b)]; |
||
531 | } |
||
532 | |||
533 | // Bonus if some pawns can safely push and attack an enemy piece |
||
534 | b = pos.pieces(Us, PAWN) & ~TRank7BB; |
||
535 | b = shift_bb<Up>(b | (shift_bb<Up>(b & TRank2BB) & ~pos.pieces())); |
||
536 | |||
537 | b &= ~pos.pieces() |
||
538 | & ~ei.attackedBy[Them][PAWN] |
||
539 | & (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]); |
||
540 | |||
541 | b = (shift_bb<Left>(b) | shift_bb<Right>(b)) |
||
542 | & pos.pieces(Them) |
||
543 | & ~ei.attackedBy[Us][PAWN]; |
||
544 | |||
545 | if (b) |
||
546 | score += ThreatByPawnPush * popcount<Max15>(b); |
||
547 | |||
548 | if (DoTrace) |
||
549 | Trace::add(THREAT, Us, score); |
||
550 | |||
551 | return score; |
||
552 | } |
||
553 | |||
554 | |||
555 | // evaluate_passed_pawns() evaluates the passed pawns of the given color |
||
556 | |||
557 | template<Color Us, bool DoTrace> |
||
558 | Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) { |
||
559 | |||
560 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
561 | |||
562 | Bitboard b, squaresToQueen, defendedSquares, unsafeSquares; |
||
563 | Score score = SCORE_ZERO; |
||
564 | |||
565 | b = ei.pi->passed_pawns(Us); |
||
566 | |||
567 | while (b) |
||
568 | { |
||
569 | Square s = pop_lsb(&b); |
||
570 | |||
571 | assert(pos.pawn_passed(Us, s)); |
||
572 | |||
573 | int r = relative_rank(Us, s) - RANK_2; |
||
574 | int rr = r * (r - 1); |
||
575 | |||
576 | Value mbonus = Passed[MG][r], ebonus = Passed[EG][r]; |
||
577 | |||
578 | if (rr) |
||
579 | { |
||
580 | Square blockSq = s + pawn_push(Us); |
||
581 | |||
582 | // Adjust bonus based on the king's proximity |
||
583 | ebonus += distance(pos.square<KING>(Them), blockSq) * 5 * rr |
||
584 | - distance(pos.square<KING>(Us ), blockSq) * 2 * rr; |
||
585 | |||
586 | // If blockSq is not the queening square then consider also a second push |
||
587 | if (relative_rank(Us, blockSq) != RANK_8) |
||
588 | ebonus -= distance(pos.square<KING>(Us), blockSq + pawn_push(Us)) * rr; |
||
589 | |||
590 | // If the pawn is free to advance, then increase the bonus |
||
591 | if (pos.empty(blockSq)) |
||
592 | { |
||
593 | // If there is a rook or queen attacking/defending the pawn from behind, |
||
594 | // consider all the squaresToQueen. Otherwise consider only the squares |
||
595 | // in the pawn's path attacked or occupied by the enemy. |
||
596 | defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s); |
||
597 | |||
598 | Bitboard bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s); |
||
599 | |||
600 | if (!(pos.pieces(Us) & bb)) |
||
601 | defendedSquares &= ei.attackedBy[Us][ALL_PIECES]; |
||
602 | |||
603 | if (!(pos.pieces(Them) & bb)) |
||
604 | unsafeSquares &= ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them); |
||
605 | |||
606 | // If there aren't any enemy attacks, assign a big bonus. Otherwise |
||
607 | // assign a smaller bonus if the block square isn't attacked. |
||
608 | int k = !unsafeSquares ? 18 : !(unsafeSquares & blockSq) ? 8 : 0; |
||
609 | |||
610 | // If the path to the queen is fully defended, assign a big bonus. |
||
611 | // Otherwise assign a smaller bonus if the block square is defended. |
||
612 | if (defendedSquares == squaresToQueen) |
||
613 | k += 6; |
||
614 | |||
615 | else if (defendedSquares & blockSq) |
||
616 | k += 4; |
||
617 | |||
618 | mbonus += k * rr * 3 / 4, ebonus += k * rr; |
||
619 | } |
||
620 | else if (pos.pieces(Us) & blockSq) |
||
621 | mbonus += (rr * 3 + r * 2 + 3) * 3 / 4, ebonus += rr + r * 2; |
||
622 | } // rr != 0 |
||
623 | |||
624 | if (pos.count<PAWN>(Us) < pos.count<PAWN>(Them)) |
||
625 | ebonus += ebonus / 4; |
||
626 | |||
627 | score += make_score(mbonus, ebonus) + PassedFile[file_of(s)]; |
||
628 | } |
||
629 | |||
630 | if (DoTrace) |
||
631 | Trace::add(PASSED, Us, score); |
||
632 | |||
633 | // Add the scores to the middlegame and endgame eval |
||
634 | return score; |
||
635 | } |
||
636 | |||
637 | |||
638 | // evaluate_space() computes the space evaluation for a given side. The |
||
639 | // space evaluation is a simple bonus based on the number of safe squares |
||
640 | // available for minor pieces on the central four files on ranks 2--4. Safe |
||
641 | // squares one, two or three squares behind a friendly pawn are counted |
||
642 | // twice. Finally, the space bonus is multiplied by a weight. The aim is to |
||
643 | // improve play on game opening. |
||
644 | template<Color Us> |
||
645 | Score evaluate_space(const Position& pos, const EvalInfo& ei) { |
||
646 | |||
647 | const Color Them = (Us == WHITE ? BLACK : WHITE); |
||
648 | const Bitboard SpaceMask = |
||
649 | Us == WHITE ? (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank2BB | Rank3BB | Rank4BB) |
||
650 | : (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB); |
||
651 | |||
652 | // Find the safe squares for our pieces inside the area defined by |
||
653 | // SpaceMask. A square is unsafe if it is attacked by an enemy |
||
654 | // pawn, or if it is undefended and attacked by an enemy piece. |
||
655 | Bitboard safe = SpaceMask |
||
656 | & ~pos.pieces(Us, PAWN) |
||
657 | & ~ei.attackedBy[Them][PAWN] |
||
658 | & (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]); |
||
659 | |||
660 | // Find all squares which are at most three squares behind some friendly pawn |
||
661 | Bitboard behind = pos.pieces(Us, PAWN); |
||
662 | behind |= (Us == WHITE ? behind >> 8 : behind << 8); |
||
663 | behind |= (Us == WHITE ? behind >> 16 : behind << 16); |
||
664 | |||
665 | // Since SpaceMask[Us] is fully on our half of the board... |
||
666 | assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0); |
||
667 | |||
668 | // ...count safe + (behind & safe) with a single popcount |
||
669 | int bonus = popcount<Full>((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe)); |
||
670 | int weight = pos.count<KNIGHT>(Us) + pos.count<BISHOP>(Us) |
||
671 | + pos.count<KNIGHT>(Them) + pos.count<BISHOP>(Them); |
||
672 | |||
673 | return make_score(bonus * weight * weight * 2 / 11, 0); |
||
674 | } |
||
675 | |||
676 | |||
677 | // evaluate_initiative() computes the initiative correction value for the |
||
678 | // position, i.e., second order bonus/malus based on the known attacking/defending |
||
679 | // status of the players. |
||
680 | Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) { |
||
681 | |||
682 | int kingDistance = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK)); |
||
683 | int pawns = pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK); |
||
684 | |||
685 | // Compute the initiative bonus for the attacking side |
||
686 | int initiative = 8 * (pawns + asymmetry + kingDistance - 15); |
||
687 | |||
688 | // Now apply the bonus: note that we find the attacking side by extracting |
||
689 | // the sign of the endgame value, and that we carefully cap the bonus so |
||
690 | // that the endgame score will never be divided by more than two. |
||
691 | int value = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg / 2)); |
||
692 | |||
693 | return make_score(0, value); |
||
694 | } |
||
695 | |||
696 | |||
697 | // evaluate_scale_factor() computes the scale factor for the winning side |
||
698 | ScaleFactor evaluate_scale_factor(const Position& pos, const EvalInfo& ei, Score score) { |
||
699 | |||
700 | Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK; |
||
701 | ScaleFactor sf = ei.me->scale_factor(pos, strongSide); |
||
702 | |||
703 | // If we don't already have an unusual scale factor, check for certain |
||
704 | // types of endgames, and use a lower scale for those. |
||
705 | if ( ei.me->game_phase() < PHASE_MIDGAME |
||
706 | && (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN)) |
||
707 | { |
||
708 | if (pos.opposite_bishops()) |
||
709 | { |
||
710 | // Endgame with opposite-colored bishops and no other pieces (ignoring pawns) |
||
711 | // is almost a draw, in case of KBP vs KB, it is even more a draw. |
||
712 | if ( pos.non_pawn_material(WHITE) == BishopValueMg |
||
713 | && pos.non_pawn_material(BLACK) == BishopValueMg) |
||
714 | sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(31) : ScaleFactor(9); |
||
715 | |||
716 | // Endgame with opposite-colored bishops, but also other pieces. Still |
||
717 | // a bit drawish, but not as drawish as with only the two bishops. |
||
718 | else |
||
719 | sf = ScaleFactor(46 * sf / SCALE_FACTOR_NORMAL); |
||
720 | } |
||
721 | // Endings where weaker side can place his king in front of the opponent's |
||
722 | // pawns are drawish. |
||
723 | else if ( abs(eg_value(score)) <= BishopValueEg |
||
724 | && ei.pi->pawn_span(strongSide) <= 1 |
||
725 | && !pos.pawn_passed(~strongSide, pos.square<KING>(~strongSide))) |
||
726 | sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(51) : ScaleFactor(37); |
||
727 | } |
||
728 | |||
729 | return sf; |
||
730 | } |
||
731 | |||
732 | } // namespace |
||
733 | |||
734 | |||
735 | /// evaluate() is the main evaluation function. It returns a static evaluation |
||
736 | /// of the position from the point of view of the side to move. |
||
737 | |||
738 | template<bool DoTrace> |
||
739 | Value Eval::evaluate(const Position& pos) { |
||
740 | |||
741 | assert(!pos.checkers()); |
||
742 | |||
743 | EvalInfo ei; |
||
744 | Score score, mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO }; |
||
745 | |||
746 | // Initialize score by reading the incrementally updated scores included in |
||
747 | // the position object (material + piece square tables). Score is computed |
||
748 | // internally from the white point of view. |
||
749 | score = pos.psq_score(); |
||
750 | |||
751 | // Probe the material hash table |
||
752 | ei.me = Material::probe(pos); |
||
753 | score += ei.me->imbalance(); |
||
754 | |||
755 | // If we have a specialized evaluation function for the current material |
||
756 | // configuration, call it and return. |
||
757 | if (ei.me->specialized_eval_exists()) |
||
758 | return ei.me->evaluate(pos); |
||
759 | |||
760 | // Probe the pawn hash table |
||
761 | ei.pi = Pawns::probe(pos); |
||
762 | score += ei.pi->pawns_score(); |
||
763 | |||
764 | // Initialize attack and king safety bitboards |
||
765 | ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0; |
||
766 | eval_init<WHITE>(pos, ei); |
||
767 | eval_init<BLACK>(pos, ei); |
||
768 | |||
769 | // Pawns blocked or on ranks 2 and 3 will be excluded from the mobility area |
||
770 | Bitboard blockedPawns[] = { |
||
771 | pos.pieces(WHITE, PAWN) & (shift_bb<DELTA_S>(pos.pieces()) | Rank2BB | Rank3BB), |
||
772 | pos.pieces(BLACK, PAWN) & (shift_bb<DELTA_N>(pos.pieces()) | Rank7BB | Rank6BB) |
||
773 | }; |
||
774 | |||
775 | // Do not include in mobility area squares protected by enemy pawns, or occupied |
||
776 | // by our blocked pawns or king. |
||
777 | Bitboard mobilityArea[] = { |
||
778 | ~(ei.attackedBy[BLACK][PAWN] | blockedPawns[WHITE] | pos.square<KING>(WHITE)), |
||
779 | ~(ei.attackedBy[WHITE][PAWN] | blockedPawns[BLACK] | pos.square<KING>(BLACK)) |
||
780 | }; |
||
781 | |||
782 | // Evaluate all pieces but king and pawns |
||
783 | score += evaluate_pieces<DoTrace>(pos, ei, mobility, mobilityArea); |
||
784 | score += mobility[WHITE] - mobility[BLACK]; |
||
785 | |||
786 | // Evaluate kings after all other pieces because we need full attack |
||
787 | // information when computing the king safety evaluation. |
||
788 | score += evaluate_king<WHITE, DoTrace>(pos, ei) |
||
789 | - evaluate_king<BLACK, DoTrace>(pos, ei); |
||
790 | |||
791 | // Evaluate tactical threats, we need full attack information including king |
||
792 | score += evaluate_threats<WHITE, DoTrace>(pos, ei) |
||
793 | - evaluate_threats<BLACK, DoTrace>(pos, ei); |
||
794 | |||
795 | // Evaluate passed pawns, we need full attack information including king |
||
796 | score += evaluate_passed_pawns<WHITE, DoTrace>(pos, ei) |
||
797 | - evaluate_passed_pawns<BLACK, DoTrace>(pos, ei); |
||
798 | |||
799 | // If both sides have only pawns, score for potential unstoppable pawns |
||
800 | if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK)) |
||
801 | { |
||
802 | Bitboard b; |
||
803 | if ((b = ei.pi->passed_pawns(WHITE)) != 0) |
||
804 | score += Unstoppable * int(relative_rank(WHITE, frontmost_sq(WHITE, b))); |
||
805 | |||
806 | if ((b = ei.pi->passed_pawns(BLACK)) != 0) |
||
807 | score -= Unstoppable * int(relative_rank(BLACK, frontmost_sq(BLACK, b))); |
||
808 | } |
||
809 | |||
810 | // Evaluate space for both sides, only during opening |
||
811 | if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222) |
||
812 | score += evaluate_space<WHITE>(pos, ei) |
||
813 | - evaluate_space<BLACK>(pos, ei); |
||
814 | |||
815 | // Evaluate position potential for the winning side |
||
816 | score += evaluate_initiative(pos, ei.pi->pawn_asymmetry(), eg_value(score)); |
||
817 | |||
818 | // Evaluate scale factor for the winning side |
||
819 | ScaleFactor sf = evaluate_scale_factor(pos, ei, score); |
||
820 | |||
821 | // Interpolate between a middlegame and a (scaled by 'sf') endgame score |
||
822 | Value v = mg_value(score) * int(ei.me->game_phase()) |
||
823 | + eg_value(score) * int(PHASE_MIDGAME - ei.me->game_phase()) * sf / SCALE_FACTOR_NORMAL; |
||
824 | |||
825 | v /= int(PHASE_MIDGAME); |
||
826 | |||
827 | // In case of tracing add all remaining individual evaluation terms |
||
828 | if (DoTrace) |
||
829 | { |
||
830 | Trace::add(MATERIAL, pos.psq_score()); |
||
831 | Trace::add(IMBALANCE, ei.me->imbalance()); |
||
832 | Trace::add(PAWN, ei.pi->pawns_score()); |
||
833 | Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]); |
||
834 | Trace::add(SPACE, evaluate_space<WHITE>(pos, ei) |
||
835 | , evaluate_space<BLACK>(pos, ei)); |
||
836 | Trace::add(TOTAL, score); |
||
837 | } |
||
838 | |||
839 | return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view |
||
840 | } |
||
841 | |||
842 | // Explicit template instantiations |
||
843 | template Value Eval::evaluate<true >(const Position&); |
||
844 | template Value Eval::evaluate<false>(const Position&); |
||
845 | |||
846 | |||
847 | /// trace() is like evaluate(), but instead of returning a value, it returns |
||
848 | /// a string (suitable for outputting to stdout) that contains the detailed |
||
849 | /// descriptions and values of each evaluation term. Useful for debugging. |
||
850 | |||
851 | std::string Eval::trace(const Position& pos) { |
||
852 | |||
853 | std::memset(scores, 0, sizeof(scores)); |
||
854 | |||
855 | Value v = evaluate<true>(pos); |
||
856 | v = pos.side_to_move() == WHITE ? v : -v; // White's point of view |
||
857 | |||
858 | std::stringstream ss; |
||
859 | ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2) |
||
860 | << " Eval term | White | Black | Total \n" |
||
861 | << " | MG EG | MG EG | MG EG \n" |
||
862 | << "----------------+-------------+-------------+-------------\n" |
||
863 | << " Material | " << Term(MATERIAL) |
||
864 | << " Imbalance | " << Term(IMBALANCE) |
||
865 | << " Pawns | " << Term(PAWN) |
||
866 | << " Knights | " << Term(KNIGHT) |
||
867 | << " Bishop | " << Term(BISHOP) |
||
868 | << " Rooks | " << Term(ROOK) |
||
869 | << " Queens | " << Term(QUEEN) |
||
870 | << " Mobility | " << Term(MOBILITY) |
||
871 | << " King safety | " << Term(KING) |
||
872 | << " Threats | " << Term(THREAT) |
||
873 | << " Passed pawns | " << Term(PASSED) |
||
874 | << " Space | " << Term(SPACE) |
||
875 | << "----------------+-------------+-------------+-------------\n" |
||
876 | << " Total | " << Term(TOTAL); |
||
877 | |||
878 | ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n"; |
||
879 | |||
880 | return ss.str(); |
||
881 | } |
||
882 | |||
883 | |||
884 | /// init() computes evaluation weights, usually at startup |
||
885 | |||
886 | void Eval::init() { |
||
887 | |||
888 | const int MaxSlope = 322; |
||
889 | const int Peak = 47410; |
||
890 | int t = 0; |
||
891 | |||
892 | for (int i = 0; i < 400; ++i) |
||
893 | { |
||
894 | t = std::min(Peak, std::min(i * i - 16, t + MaxSlope)); |
||
895 | KingDanger[i] = make_score(t * 268 / 7700, 0); |
||
896 | } |
||
897 | } |