2 Copyright (c) Scott Gasch
10 Position evaluation routines.
18 $Id: eval.c 357 2008-07-03 16:18:11Z scott $
24 typedef void (*PEVAL_HELPER)(POSITION *, COOR, PAWN_HASH_ENTRY *);
25 typedef FLAG (FASTCALL *PMOBILITY_HELPER)(POSITION *, COOR, ULONG *, ULONG *);
28 // To simplify code / maintenance I use the same loop for both colors
29 // in some places. These globals coorespond to "ahead of the piece"
30 // or "behind the piece" for each color.
32 const int g_iAhead[2] = { +1, -1 };
33 const int g_iBehind[2] = { -1, +1 };
37 // ---------------------------------------------------------------------------
39 static SCORE TRADE_PIECES[3][17] =
40 {// 0 1 2 3 4 5 6 7 8 | 9..15 -- down piece count
41 { -1, 90, 81, 73, 67, 62, 57, 52, 50, 50,50,50,50,50,50,50,-1},
42 { -1, 125, 117, 109, 100, 91, 84, 78, 71, 66,66,66,66,66,66,66,-1},
43 { -1, 150, 132, 124, 116, 109, 102, 94, 87, 77,77,77,77,77,77,77,-1},
46 static SCORE DONT_TRADE_PAWNS[3][9] =
47 {// 0 1 2 3 4 5 6 7 8 -- up pawn count
48 { -43, -15, 0, +3, +6, +10, +15, +21, +28 }, // 0
49 { -63, -25, 0, +4, +9, +14, +19, +25, +32 }, // 1
50 { -10, 0, 0, +7, +15, +20, +24, +29, +36 }, // 2
53 static ULONG REDUCED_MATERIAL_DOWN_SCALER[32] =
55 // none na na m na R 2m na
56 0, 0, 0, 0, 0, 0, 0, 0,
58 // Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
59 0, 1, 1, 1, 1, 1, 2, 3,
61 // 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
63 4, 5, 6, 6, 7, 7, 7, 7,
65 // na Q2R2m QR4m na Q2R3m na na full
66 8, 8, 8, 8, 8, 8, 8, 8,
69 static ULONG REDUCED_MATERIAL_UP_SCALER[32] =
71 // none na na m na R 2m na
72 8, 8, 8, 8, 8, 8, 8, 8,
74 // Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
75 8, 7, 7, 7, 7, 6, 6, 5,
77 // 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
79 4, 3, 3, 3, 2, 2, 2, 1,
81 // na Q2R2m QR4m na Q2R3m na na full
82 1, 1, 0, 0, 0, 0, 0, 0,
85 static ULONG PASSER_MATERIAL_UP_SCALER[32] =
87 // none na na m na R 2m na
88 8, 8, 8, 8, 8, 8, 7, 7,
90 // Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
91 7, 6, 7, 5, 4, 5, 4, 3,
93 // 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
95 2, 2, 1, 1, 0, 0, 0, 0,
97 // na Q2R2m QR4m na Q2R3m na na full
98 0, 0, 0, 0, 0, 0, 0, 0,
101 COOR QUEENING_RANK[2] = { 1, 8 };
102 COOR JUMPING_RANK[2] = { 7, 2 };
106 // ---------------------------------------------------------------------------
108 // "There is one case which can be treated as positional or material,
109 // namely the rook's pawn, which differs from other pawns in that it
110 // can only capture one way instead of two. Since this handicap cannot
111 // be corrected without the opponent's help, I teach my students to
112 // regard the rook's pawn as a different piece type, a crippled
113 // pawn. Database statistics indicate that it is on average worth
114 // about 15% less than a normal pawn. The difference is enough so that
115 // it is usually advantageous to make a capture with a rook's pawn,
116 // promoting it to a knights pawn, even if that produces doubled pawns
117 // and even if there is no longer a rook on the newly opened rook's
119 // --Larry Kaufman, IM
120 // "Evaluation of Material Imbalance"
122 static SCORE PAWN_CENTRALITY_BONUS[128] =
124 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,
125 -8, 0, 0, 0, 0, 0, 0, -8, 0,0,0,0,0,0,0,0,
126 -8, 0, 5, 5, 5, 5, 0, -8, 0,0,0,0,0,0,0,0,
127 -8, 0, 5, 9, 9, 5, 0, -8, 0,0,0,0,0,0,0,0,
128 // -------------------------------------------------------------------
129 -8, 0, 5, 9, 9, 5, 0, -8, 0,0,0,0,0,0,0,0,
130 -8, 0, 5, 5, 5, 5, 0, -8, 0,0,0,0,0,0,0,0,
131 -8, 0, 0, 0, 0, 0, 0, -8, 0,0,0,0,0,0,0,0,
132 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0
135 static SCORE BACKWARD_SHIELDED_BY_LOCATION[128] =
137 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
138 -7, -5, -5, -7, -7, -5, -5, -7, 0,0,0,0,0,0,0,0,
139 -5, -4, -4, -5, -5, -4, -4, -5, 0,0,0,0,0,0,0,0,
140 -4, -3, -3, -4, -4, -3, -3, -4, 0,0,0,0,0,0,0,0,
141 // -------------------------------------------------------------------
142 -4, -3, -3, -4, -4, -3, -3, -4, 0,0,0,0,0,0,0,0,
143 -5, -4, -4, -5, -5, -4, -4, -5, 0,0,0,0,0,0,0,0,
144 -7, -5, -5, -7, -7, -5, -5, -7, 0,0,0,0,0,0,0,0,
145 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
148 static SCORE BACKWARD_EXPOSED_BY_LOCATION[128] =
150 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
151 -12, -9, -9, -11, -11, -9, -9, -12, 0,0,0,0,0,0,0,0,
152 -9, -7, -7, -9, -9, -7, -7, -9, 0,0,0,0,0,0,0,0,
153 -7, -6, -6, -7, -7, -6, -6, -7, 0,0,0,0,0,0,0,0,
154 // -------------------------------------------------------------------
155 -7, -6, -6, -7, -7, -6, -6, -7, 0,0,0,0,0,0,0,0,
156 -9, -7, -7, -9, -9, -7, -7, -9, 0,0,0,0,0,0,0,0,
157 -12, -9, -9, -11, -11, -9, -9, -12, 0,0,0,0,0,0,0,0,
158 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
162 // "The first statement I can confirm is that doubled pawns are indeed
163 // on average undesirable. However this statistic needs to be broken
164 // down to be useful. Doubled pawns themselves are really more
165 // serious than this generally, but when your pawns are doubled you
166 // automatically get an extra half-open file for your rooks (or queen,
167 // but the queen can also use diagonals). So it follows logically
168 // that the net cost of doubled pawns is much greater in the absence
169 // of major pieces. The database shows that with all rooks present,
170 // doubled pawns "cost" only about 1/16th of a pawn on average. With
171 // one rook each the cost rises to 1/4th of a pawn and with no rooks
172 // present to 3/8ths of a pawn. With the queens present the cost is
173 // again only 1/16th of a pawn; without them it's a quarter pawn. So
174 // the lessons are clear; beware of doubled pawns when major pieces
175 // have been exchanged, and beware of exchanging major pieces when you
176 // are the one with the doubled pawns."
177 // --Larry Kaufman, IM
178 // "All About Doubled Pawns"
180 // Note: indexed by number of files with 1+ pawn on them.
181 static SCORE DOUBLED_PAWN_PENALTY_BY_COUNT[4][9] =
182 { // ------------ count of doubled+ pawns ------------
183 {// 0 1 2 3 4 5 6 7 8 : no majors alive
184 +0, -32, -65, -99, -134, -170, -207, -222, -250
187 +0, -23, -47, -76, -108, -144, -184, -200, -216
189 {// : 2 rooks or 1 queen
190 +0, -13, -23, -34, -46, -64, -86, -111, -138
192 {// : all majors alive
193 +0, -7, -13, -25, -39, -55, -73, -95, -121
197 static SCORE ISOLATED_PAWN_PENALTY_BY_COUNT[9] =
198 {// 0 1 2 3 4 5 6 7 8
199 +0, -3, -7, -9, -16, -35, -50, -85, -100
202 static SCORE ISOLATED_PAWN_BY_PAWNFILE[9] =
204 0, -7, -8, -9, -10, -10, -9, -8, -7
207 static SCORE ISOLATED_EXPOSED_PAWN = -5;
209 static SCORE ISOLATED_DOUBLED_PAWN = -11;
212 // Note: -25% to -33% if the enemy occupies or controls the next sq.
214 static SCORE PASSER_BY_RANK[2][9] =
215 {// 0 1 2 3 4 5 6 7 8
216 { +0, +0,+162,+111, +62, +36, +18, +13, +0 }, // black
217 { +0, +0, +13, +18, +36, +62,+111,+162, +0 } // white
220 static SCORE CANDIDATE_PASSER_BY_RANK[2][9] =
221 {// 0 1 2 3 4 5 6 7 8
222 { +0, +0, +0, +48, +34, +22, +13, +9, +0 }, // black
223 { +0, +0, +9, +13, +22, +34, +48, +0, +0 } // white
227 static SCORE CONNECTED_PASSERS_BY_RANK[2][9] =
228 {// 0 1 2 3 4 5 6 7 8
229 { +0, +0, +96, +74, +48, +21, +10, +5, +0 }, // black
230 { +0, +0, +5, +10, +21, +48, +74, +96, +0 } // white
233 static SCORE SUPPORTED_PASSER_BY_RANK[2][9] =
234 {// 0 1 2 3 4 5 6 7 8
235 { +0, +0, +60, +40, +13, +6, +3, +1, +0 }, // black
236 { +0, +0, +1, +3, +6, +13, +40, +60, +0 } // white
239 static SCORE OUTSIDE_PASSER_BY_DISTANCE[9] =
240 {// 0 1 2 3 4 5 6 7 8
241 +0, +0, +7, +14, +21, +28, +34, +41, +55
244 static SCORE PASSER_BONUS_AS_MATERIAL_COMES_OFF[32] =
246 // none na na m na R 2m na
247 +60, -1, -1, +37, -1, +43, +19, -1,
249 // Rm 3m/Q 2R R2m 4m/Qm 2Rm R3m/QR Q2m
250 +14, +9, +20, +4, +3, +3, 0, 0,
252 // 2R2m R4m/QRm Q3m 2R3m/ QR2m Q4m 2R4m/ QR3m
254 0, 0, 0, 0, 0, 0, 0, 0,
256 // na Q2R2m QR4m na Q2R3m na na full
257 0, 0, 0, 0, 0, 0, 0, 0,
260 SCORE RACER_WINS_RACE = +800;
262 static SCORE UNDEVELOPED_MINORS_IN_OPENING[5] =
269 // ---------------------------------------------------------------------------
271 static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +33;
274 // "The bishop pair has an average value of half a pawn (more when the
275 // opponent has no minor pieces to exchange for one of the bishops),
276 // enough to regard it as part of the material evaluation of the
277 // position, and enough to overwhelm most positional considerations.
278 // Moreover, this substantial bishop pair value holds up in all
279 // situations tested, regardless of what else is on the board...
281 // ...One rule which I often teach to students is that if you have the
282 // bishop pair, and your opponent's single bishop is a bad bishop
283 // (hemmed in by his own pawns), you already have full compensation
284 // for a pawn... Kasparov has said something similar...
286 // As noted before, the bishop pair is worth more with fewer pawns on
287 // the board. Aside from this factor, the half pawn value of the
288 // bishop pair is remarkably constant, applying even when there are no
289 // pieces on the board except two minors each."
290 // --Larry Kaufman, IM
291 // "Evaluation of Material Imbalance"
292 static SCORE BISHOP_PAIR[2][17] =
294 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
295 { 53, 52, 51, 50, 49, 48, 47, 45, 43, 41, 40, 40, 40, 40, 40, 40, 40 }
298 static SCORE STATIONARY_PAWN_ON_BISHOP_COLOR[128] =
300 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
301 -4, -6, -7, -7, -7, -7, -6, -4, 0,0,0,0,0,0,0,0,
302 -6, -7, -9, -8, -8, -9, -7, -6, 0,0,0,0,0,0,0,0,
303 -7, -8, -10, -11, -11, -10, -8, -7, 0,0,0,0,0,0,0,0,
304 // -------------------------------------------------------------------
305 -7, -8, -10, -11, -11, -10, -8, -7, 0,0,0,0,0,0,0,0,
306 -6, -7, -9, -8, -8, -9, -7, -6, 0,0,0,0,0,0,0,0,
307 -4, -6, -7, -7, -7, -7, -6, -4, 0,0,0,0,0,0,0,0,
308 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
311 static SCORE TRANSIENT_PAWN_ON_BISHOP_COLOR[128] =
313 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
314 -1, -1, -2, -2, -2, -2, -1, -1, 0,0,0,0,0,0,0,0,
315 -3, -4, -4, -4, -4, -4, -4, -3, 0,0,0,0,0,0,0,0,
316 -4, -5, -7, -8, -8, -7, -5, -4, 0,0,0,0,0,0,0,0,
317 // -------------------------------------------------------------------
318 -4, -5, -7, -8, -8, -7, -5, -4, 0,0,0,0,0,0,0,0,
319 -3, -4, -4, -4, -4, -4, -4, -3, 0,0,0,0,0,0,0,0,
320 -1, -1, -2, -2, -2, -2, -1, -1, 0,0,0,0,0,0,0,0,
321 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
325 // A bishop can move to between 0..13 squares.
327 static SCORE BISHOP_MOBILITY_BY_SQUARES[14] =
328 {// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
329 -22, -14, -10, -5, -1, 0, +1, +3, +4, +5, +6, +7, +8, +9
332 static SCORE BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
334 -10, -4, +1, +3, +4, +5, +5, +5
337 static SCORE BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING[9] =
338 {// 0 1 2 3 4 5 6 7 8
339 +0, +33, +28, +18, +8, +4, +0, -10, -16
342 static SCORE BISHOP_IN_CLOSED_POSITION[33] =
343 {// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
344 10, 10, 10, 9, 9, 8, 8, 7, 7, 6, 5, 4, 3, 2, 1, 0,
345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
346 // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
351 // ---------------------------------------------------------------------------
353 static SCORE KNIGHT_CENTRALITY_BONUS[128] =
355 -12, -8, -8, -8, -8, -8, -8, -12, 0,0,0,0,0,0,0,0,
356 -8, -2, -2, 0, 0, -2, -2, -8, 0,0,0,0,0,0,0,0,
357 -8, -2, +4, +5, +5, +4, -2, -8, 0,0,0,0,0,0,0,0,
358 -8, -2, +5, +8, +8, +5, -2, -8, 0,0,0,0,0,0,0,0,
359 // -------------------------------------------------------------------
360 -8, -2, +5, +8, +8, +5, -2, -8, 0,0,0,0,0,0,0,0,
361 -8, -2, +4, +5, +5, +4, -2, -8, 0,0,0,0,0,0,0,0,
362 -8, -2, -2, 0, 0, -2, -2, -8, 0,0,0,0,0,0,0,0,
363 -12, -8, -8, -8, -8, -8, -8, -12, 0,0,0,0,0,0,0,0
366 static SCORE KNIGHT_KING_TROPISM_BONUS[9] =
367 {// 0 1 2 3 4 5 6 7 8
368 0, +15, +12, +9, +4, +0, +0, +0, +0
372 static SCORE KNIGHT_UNASSAILABLE_BY_DIST_FROM_EKING[9] =
373 {// 0 1 2 3 4 5 6 7 8
374 +0, +25, +19, +14, +6, +0, +0, +0, +0
377 static SCORE KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[2][9] =
378 {// 0 1 2 3 4 5 6 7 8
379 { +0, +12, +11, +9, +6, +3, +0, +0, +0 }, // black
380 { +0, +0, +0, +0, +3, +6, +9, +11, +12 } // white
384 // A knight can move to between 0..8 squares
385 // -----------------------------------------
386 // 0 = supported enemy pawn
387 // 1 = unsupported enemy pawn, friend pawn, enemy B/N
388 // enemy controlled empty sq.
389 // 2 = enemy >B, friend controlled empty sq, no one controlled empty sq
391 // Total: 16 mobility max
393 static SCORE KNIGHT_MOBILITY_BY_COUNT[9] =
394 {// 0 1 2 3 4 5 6 7 8
395 -17, -10, -6, 0, +3, +5, +7, +8, +8
398 static SCORE KNIGHT_WITH_N_PAWNS_SUPPORTING[3] =
403 static SCORE KNIGHT_IN_CLOSED_POSITION[33] =
404 {// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 11,
406 12, 13, 15, 17, 19, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27
407 // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
412 // ---------------------------------------------------------------------------
414 static SCORE ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING[8] =
416 +24, +22, +17, +14, +13, +13, +12, +12
419 static SCORE ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[8] =
421 +12, +11, +9, +9, +8, +8, +8, +7
424 static SCORE ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING[8] =
426 +13, +12, +11, +11, +9, +9, +9, +8
429 static SCORE ROOK_BEHIND_PASSER_BY_PASSER_RANK[2][9] =
430 {// 0 1 2 3 4 5 6 7 8
431 { +0, +0, +25, +17, +12, +6, +1, +0, +0 }, // black
432 { +0, +0, +0, +1, +6, +12, +17, +25, +0 } // white
435 static SCORE ROOK_LEADS_PASSER_BY_PASSER_RANK[2][9] =
436 {// 0 1 2 3 4 5 6 7 8
437 { +0, +0, -22, -16, -13, -9, -5, -3, +0 }, // black
438 { +0, +0, -3, -5, -9, -13, -16, -22, +0 } // white
441 static SCORE KING_TRAPPING_ROOK = -40;
443 static SCORE ROOK_TRAPPING_EKING = +22;
445 static SCORE ROOK_VALUE_AS_PAWNS_COME_OFF[17] =
446 {// 0 1 2 3 4 5 6 7 8
447 +55, +51, +44, +38, +33, +27, +22, +16, +7,
448 // 9 10 11 12 13 14 15 16
449 +1, -3, -6, -9, -12, -18, -22, -25
453 // Note: these are multiplied by two (one per rook).
455 static SCORE ROOK_CONNECTED_VERT = +7; // x2
456 static SCORE ROOK_CONNECTED_HORIZ = +4; // x2
459 // A rook can move to between 0..14 squares
460 // ----------------------------------------
461 // 0 = supported enemy P/N/B, friend piece
462 // 1 = unsupported enemy piece, enemy controlled empty sq, enemy R
463 // 2 = enemy >R, friend controlled empty sq, no one controlled empty sq
465 // Total: 28 mobility max
467 static SCORE ROOK_MOBILITY_BY_SQUARES[15] =
468 {// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
469 -28, -24, -20, -14, -7, -2, +0, +4, +8, +12, +15, +17, +19, +21, +22
472 static SCORE ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
474 -15, -6, +0, +4, +8, +8, +8, +8
479 // ---------------------------------------------------------------------------
484 // A queen can move to between 0..27 squares
485 // -----------------------------------------
486 // 0 = supported enemy P/N/B/R, friend piece
487 // 1 = unsupported enemy piece, enemy controlled empty sq, enemy Q
488 // 2 = enemy K, no one controlled empty sq, friend controlled empty sq
490 // Total: 54 mobility max
492 static SCORE QUEEN_MOBILITY_BY_SQUARES[28] =
493 {// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
494 -30, -26, -22, -17, -11, -8, -4, -2, -1, +2, +4, +7, +10, +12, +14,
497 //15 16 17 18 19 20 21 22 23 24 25 26 27
498 +15, +16, +17, +18, +19, +20, +20, +21, +21, +22, +22, +23, +23
501 static SCORE QUEEN_OUT_EARLY[5] =
502 {// 0 1 2 3 4 : num unmoved minors
503 0, -14, -22, -26, -33
507 // In "Evaluation of Material Imbalance", IM Larry Kaufman makes the
508 // point that queens are worth more then the standard nine "points".
509 // Thus, this scale is biased upwards by about 0.15 pawn.
511 static SCORE QUEEN_KING_TROPISM[8] =
513 0, +34, +28, +22, +19, +17, +16, +15
516 static SCORE QUEEN_ATTACKS_SQ_NEXT_TO_KING = 8; // x #sq_attacked
520 // ---------------------------------------------------------------------------
522 static ULONG KING_INITIAL_COUNTER_BY_LOCATION[2][128] =
525 1, 0, 0, 0, 1, 0, 0, 1, 0,0,0,0,0,0,0,0,
526 1, 1, 1, 1, 1, 1, 1, 1, 0,0,0,0,0,0,0,0,
527 3, 3, 3, 3, 3, 3, 3, 3, 0,0,0,0,0,0,0,0,
528 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
529 // -------------------------------------------------------------------
530 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
531 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
532 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
533 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0
536 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
537 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
538 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
539 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
540 // -------------------------------------------------------------------
541 4, 4, 4, 4, 4, 4, 4, 4, 0,0,0,0,0,0,0,0,
542 3, 3, 3, 3, 3, 3, 3, 3, 0,0,0,0,0,0,0,0,
543 1, 1, 1, 1, 1, 1, 1, 1, 0,0,0,0,0,0,0,0,
544 1, 0, 0, 0, 1, 0, 0, 1, 0,0,0,0,0,0,0,0
548 static SCORE KING_TO_CENTER[128] =
550 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0,
551 +1, +3, +5, +7, +7, +5, +3, +1, 0,0,0,0,0,0,0,0,
552 +3, +5, +13, +15, +15, +13, +5, +3, 0,0,0,0,0,0,0,0,
553 +5, +7, +17, +23, +23, +17, +7, +5, 0,0,0,0,0,0,0,0,
554 // ------------------------------------------------------------------
555 +5, +7, +17, +23, +23, +17, +7, +5, 0,0,0,0,0,0,0,0,
556 +3, +5, +13, +15, +15, +13, +5, +3, 0,0,0,0,0,0,0,0,
557 +1, +3, +5, +7, +7, +5, +3, +1, 0,0,0,0,0,0,0,0,
558 +0, +0, +0, +0, +0, +0, +0, +0, 0,0,0,0,0,0,0,0
562 // If a side has less than this much material we don't bother scoring
563 // the other side's king safety. Note: this doesn't incl pawn
566 #define DO_KING_SAFETY_THRESHOLD \
567 (VALUE_ROOK + VALUE_BISHOP + VALUE_KING + 1)
570 // If a side has less than this much material the other side's king
571 // can come out. Note: this doesn't incl pawn material.
573 #define KEEP_KING_AT_HOME_THRESHOLD \
574 (VALUE_ROOK + VALUE_ROOK + VALUE_BISHOP + VALUE_KING + 1)
576 static ULONG KING_COUNTER_BY_ATTACK_PATTERN[32] =
578 //p 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
579 //m 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
580 //r 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
581 //q 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
582 //k 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
583 0,0,2,2,1,1,3,3,1,1,3,3,2,2,4,4,2,2,3,3,2,2,4,4,2,2,4,4,3,4,5,5
586 static SCORE KING_SAFETY_BY_COUNTER[42] =
588 -0, -4, -8, -12, -16, -20, -25, -31, -38, -50, -63, -76, -90,
589 -105,-120,-135,-150,-165,-180,-195,-210,-225,-240,-255,-270,-290,
590 -310,-330,-350,-370,-390,-410,-440,-470,-500,-500,-500,-500,-500,
594 static SCORE KING_MISSING_ONE_CASTLE_OPTION = -23;
595 typedef struct _DNA_BASE_SIZE {
600 #define DNA_VAR(x) {(SCORE *)&(x), 1}
601 #define DNA_ARRAY(x) {(SCORE *)(x), ARRAY_LENGTH(x)}
602 #define DNA_MATRIX(x) {(SCORE *)(x), ARRAY_LENGTH(x) * ARRAY_LENGTH((x)[0])}
603 static DNA_BASE_SIZE g_EvalDNA[] = {
604 DNA_MATRIX(TRADE_PIECES),
605 DNA_MATRIX(DONT_TRADE_PAWNS),
606 DNA_ARRAY(REDUCED_MATERIAL_DOWN_SCALER),
607 DNA_ARRAY(REDUCED_MATERIAL_UP_SCALER),
608 DNA_ARRAY(PASSER_MATERIAL_UP_SCALER),
609 DNA_ARRAY(PAWN_CENTRALITY_BONUS),
610 DNA_ARRAY(BACKWARD_SHIELDED_BY_LOCATION),
611 DNA_ARRAY(BACKWARD_EXPOSED_BY_LOCATION),
612 DNA_MATRIX(DOUBLED_PAWN_PENALTY_BY_COUNT),
613 DNA_ARRAY(ISOLATED_PAWN_PENALTY_BY_COUNT),
614 DNA_ARRAY(ISOLATED_PAWN_BY_PAWNFILE),
615 DNA_VAR(ISOLATED_EXPOSED_PAWN),
616 DNA_VAR(ISOLATED_DOUBLED_PAWN),
617 DNA_MATRIX(PASSER_BY_RANK),
618 DNA_MATRIX(CANDIDATE_PASSER_BY_RANK),
619 DNA_MATRIX(CONNECTED_PASSERS_BY_RANK),
620 DNA_MATRIX(SUPPORTED_PASSER_BY_RANK),
621 DNA_ARRAY(OUTSIDE_PASSER_BY_DISTANCE),
622 DNA_ARRAY(PASSER_BONUS_AS_MATERIAL_COMES_OFF),
623 DNA_VAR(RACER_WINS_RACE),
624 DNA_ARRAY(UNDEVELOPED_MINORS_IN_OPENING),
625 DNA_VAR(BISHOP_OVER_KNIGHT_IN_ENDGAME),
626 DNA_MATRIX(BISHOP_PAIR),
627 DNA_ARRAY(STATIONARY_PAWN_ON_BISHOP_COLOR),
628 DNA_ARRAY(TRANSIENT_PAWN_ON_BISHOP_COLOR),
629 DNA_ARRAY(BISHOP_MOBILITY_BY_SQUARES),
630 DNA_ARRAY(BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS),
631 DNA_ARRAY(BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING),
632 DNA_ARRAY(BISHOP_IN_CLOSED_POSITION),
633 DNA_ARRAY(KNIGHT_CENTRALITY_BONUS),
634 DNA_ARRAY(KNIGHT_KING_TROPISM_BONUS),
635 DNA_ARRAY(KNIGHT_UNASSAILABLE_BY_DIST_FROM_EKING),
636 DNA_MATRIX(KNIGHT_ON_INTERESTING_SQUARE_BY_RANK),
637 DNA_ARRAY(KNIGHT_MOBILITY_BY_COUNT),
638 DNA_ARRAY(KNIGHT_WITH_N_PAWNS_SUPPORTING),
639 DNA_ARRAY(KNIGHT_IN_CLOSED_POSITION),
640 DNA_ARRAY(ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING),
641 DNA_ARRAY(ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING),
642 DNA_ARRAY(ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING),
643 DNA_MATRIX(ROOK_BEHIND_PASSER_BY_PASSER_RANK),
644 DNA_MATRIX(ROOK_LEADS_PASSER_BY_PASSER_RANK),
645 DNA_VAR(KING_TRAPPING_ROOK),
646 DNA_VAR(ROOK_TRAPPING_EKING),
647 DNA_ARRAY(ROOK_VALUE_AS_PAWNS_COME_OFF),
648 DNA_VAR(ROOK_CONNECTED_VERT),
649 DNA_VAR(ROOK_CONNECTED_HORIZ),
650 DNA_ARRAY(ROOK_MOBILITY_BY_SQUARES),
651 DNA_ARRAY(ROOK_MAX_MOBILITY_IN_A_ROW_BONUS),
652 DNA_ARRAY(QUEEN_MOBILITY_BY_SQUARES),
653 DNA_ARRAY(QUEEN_OUT_EARLY),
654 DNA_ARRAY(QUEEN_KING_TROPISM),
655 DNA_VAR(QUEEN_ATTACKS_SQ_NEXT_TO_KING),
656 DNA_MATRIX(KING_INITIAL_COUNTER_BY_LOCATION),
657 DNA_ARRAY(KING_TO_CENTER),
658 DNA_ARRAY(KING_SAFETY_BY_COUNTER),
659 DNA_VAR(KING_MISSING_ONE_CASTLE_OPTION)
667 for (u = 0; u < ARRAY_LENGTH(g_EvalDNA); u++) {
668 uSize += 10 * g_EvalDNA[u].uCount;
677 ULONG uSize = DNABufferSizeBytes();
678 char *p = malloc(uSize);
684 for (u = 0; u < ARRAY_LENGTH(g_EvalDNA); u++) {
685 q = g_EvalDNA[u].pBase;
686 for (v = 0; v < g_EvalDNA[u].uCount; v++) {
688 sprintf(p, "%s,%d", p, *q);
690 sprintf(p, "%s%d", p, *q);
698 return p; // caller must free
702 WriteEvalDNA(char *szFilename)
708 if (SystemDoesFileExist(szFilename)) goto end;
709 p = fopen(szFilename, "a+b");
722 ImportEvalDNA(char *p)
726 for (u = 0; u < ARRAY_LENGTH(g_EvalDNA); u++) {
727 for (v = 0; v < g_EvalDNA[u].uCount; v++) {
728 while(*p && (!isdigit(*p) && (*p != '-'))) p++;
729 if (*p == '\0') return FALSE;
730 *(g_EvalDNA[u].pBase + v) = atoi(p);
731 while(*p && (isdigit(*p) || (*p == '-'))) p++;
738 ReadEvalDNA(char *szFilename)
741 ULONG uSize = DNABufferSizeBytes();
742 char *q = malloc(uSize);
744 static char line[1024];
749 p = fopen(szFilename, "rb");
751 Trace("Failed to open file \"%s\"\n", szFilename);
754 while(fgets(line, 1024, p) != NULL) {
755 c = strchr(line, '#');
760 fRet = ImportEvalDNA(q);
771 // ---------------------------------------------------------------------------
775 // The three ranks "around" a rank (indexed by rank, used in eval.c)
777 BITBOARD BBADJACENT_RANKS[9] =
781 BBRANK11 | BBRANK22 | BBRANK33,
782 BBRANK22 | BBRANK33 | BBRANK44,
783 BBRANK33 | BBRANK44 | BBRANK55,
784 BBRANK44 | BBRANK55 | BBRANK66,
785 BBRANK55 | BBRANK66 | BBRANK77,
786 BBRANK66 | BBRANK77 | BBRANK88,
792 // The files "around" one, indexed by file (used in eval.c)
794 BITBOARD BBADJACENT_FILES[8] =
822 // The ranks preceeding one, indexed by rank/color of pawn (used in
825 BITBOARD BBPRECEEDING_RANKS[8][2] =
857 _IsSquareSafeFromEnemyPawn(IN POSITION *pos,
864 Determine if a piece in square c is "outposted". A piece is
865 outposted if no enemy pawns can advance to attack it / drive
870 POSITION *pos : the board
871 COOR c : the square (must not be empty!)
872 BITBOARD bb : the bitboard of pawns you want to consider
876 FLAG : TRUE if the piece is safe/outposted, FALSE otherwise
880 ULONG uColor = GET_COLOR(pos->rgSquare[c].pPiece);
884 PIECE p = pos->rgSquare[c].pPiece;
887 ASSERT(IS_ON_BOARD(c));
888 ASSERT(p && (IS_BISHOP(p) || IS_KNIGHT(p) || IS_PAWN(p)));
889 ASSERT(IS_VALID_COLOR(uColor));
894 bb &= BBADJACENT_FILES[uFile];
896 ASSERT(((c & 0x70) >> 4) == (c >> 4));
899 bb &= BBPRECEEDING_RANKS[uRank][uColor];
904 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&dbb)))
906 ASSERT(pos->rgSquare[cSquare].pPiece);
907 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
908 if ((FILE(cSquare) == (FILE(c) - 1)) ||
909 (FILE(cSquare) == (FILE(c) + 1)))
914 if (RANK(cSquare) > RANK(c))
920 if (RANK(cSquare) < RANK(c))
933 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&dbb)))
935 ASSERT(pos->rgSquare[cSquare].pPiece);
936 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
937 if ((FILE(cSquare) == (FILE(c) - 1)) ||
938 (FILE(cSquare) == (FILE(c) + 1)))
943 if (RANK(cSquare) > RANK(c))
949 if (RANK(cSquare) < RANK(c))
964 _WhoControlsSquareFast(IN POSITION *pos,
970 Determine which side controls a board square.
974 POSITION *pos : the board
975 COOR c : the square in question
979 static ULONG : (ULONG)-1 if neither side controls it or the sides
980 control it evenly, WHITE if white controls the square, or BLACK if
981 black controls the square.
983 TODO: fix this to use counts / xrays
987 ULONG uWhite = pos->rgSquare[c|8].bvAttacks[WHITE].uSmall |
988 pos->rgSquare[c|8].bvAttacks[WHITE].uXray;
989 ULONG uBlack = pos->rgSquare[c|8].bvAttacks[BLACK].uSmall |
990 pos->rgSquare[c|8].bvAttacks[BLACK].uXray;
995 ASSERT((c + 8) == (c | 8));
996 ASSERT((uWhite & 0xFFFFFF00) == 0);
997 ASSERT((uBlack & 0xFFFFFF00) == 0);
999 // TODO: keep these and update the table to use them
1003 p = pos->rgSquare[c].pPiece;
1005 ch = g_SwapTable[p][uWhite][uBlack];
1011 ASSERT(((u == 1) && (ch < 0)) ||
1012 ((u == 0) && (ch > 0)));
1020 Routine description:
1022 Zero out the attack table before building it.
1033 #define CLEAR_A_SQ \
1034 pos->rgSquare[c].bvAttacks[0].uWholeThing = 0; \
1035 pos->rgSquare[c].bvAttacks[1].uWholeThing = 0;
1037 #define CLEAR_A_RANK \
1047 #define CLEAR_SHORT_RANK \
1054 CLEAR_A_SQ; c += 10;
1057 _ClearAttackTables(IN OUT POSITION *pos)
1059 register COOR c = 8;
1061 CLEAR_A_SQ; c += 16;
1062 CLEAR_A_SQ; c += 16;
1063 CLEAR_A_SQ; c += 16;
1064 CLEAR_A_SQ; c += 16;
1065 CLEAR_A_SQ; c += 16;
1066 CLEAR_A_SQ; c += 16;
1067 CLEAR_A_SQ; c += 16;
1091 _InitializePawnHashEntry(IN OUT PAWN_HASH_ENTRY *pHash,
1095 Routine description:
1099 PAWN_HASH_ENTRY *pHash,
1108 memset(pHash, 0, sizeof(PAWN_HASH_ENTRY));
1109 pHash->u64Key = pos->u64PawnSig;
1114 _EvaluateCandidatePasser(IN POSITION *pos,
1115 IN OUT PAWN_HASH_ENTRY *pHash,
1119 Routine description:
1124 PAWN_HASH_ENTRY *pHash,
1134 PIECE pSentry, pHelper;
1135 ULONG uPawnFile = FILE(c) + 1;
1137 ULONG uSentries, uHelpers;
1142 ULONG uVerifySentries;
1145 ASSERT(IS_ON_BOARD(c));
1146 ASSERT(RANK(c) >= 2);
1147 ASSERT(RANK(c) <= 7);
1148 pHelper = pos->rgSquare[c].pPiece;
1149 ASSERT(IS_PAWN(pHelper));
1150 uColor = GET_COLOR(pHelper);
1151 ASSERT(IS_VALID_COLOR(uColor));
1153 if (pHash->uCountPerFile[FLIP(uColor)][uPawnFile] != 0)
1155 ASSERT((pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[FILE(c)]) != 0);
1158 // The only way a pawn can be a passer/candidate if the other
1159 // side has a pawn on its same file is if that enemy pawn is
1160 // behind it. This is a corner case but it is important to
1161 // detect all passers.
1166 bb = pHash->bbPawnLocations[BLACK] & BBFILE[FILE(c)];
1168 while(IS_ON_BOARD(c1 = CoorFromBitBoardRank8ToRank1(&bb)))
1170 ASSERT(FILE(c1) == FILE(c));
1175 bb = pHash->bbPawnLocations[WHITE] & BBFILE[FILE(c)];
1177 while(IS_ON_BOARD(c1 = CoorFromBitBoardRank1ToRank8(&bb)))
1179 ASSERT(FILE(c1) == FILE(c));
1187 // Count FLIP(uColor)'s sentries and determine the location of the
1188 // critical square. Note if there are no sentries then this
1189 // pawn (on square c) is a passer already, not a candidate.
1191 bb = pHash->bbPawnLocations[FLIP(uColor)] & BBADJACENT_FILES[FILE(c)];
1192 bb &= BBPRECEEDING_RANKS[(c & 0x70) >> 4][uColor];
1195 ASSERT(CountBits(bb) == 0);
1198 // There are no sentries so this pawn is a passer.
1200 pHash->bbPasserLocations[uColor] |= COOR_TO_BB(c);
1201 ASSERT(CountBits(pHash->bbPasserLocations[uColor]) > 0);
1202 ASSERT(CountBits(pHash->bbPasserLocations[uColor]) <= 8);
1206 pHash->iScore[uColor],
1207 PASSER_BY_RANK[uColor][RANK(c)],
1211 // However, don't give doubled passers such a big bonus.
1213 if (IS_PAWN(pos->rgSquare[c - 16 * g_iAhead[uColor]].pPiece))
1218 pHash->iScore[uColor],
1219 -(PASSER_BY_RANK[uColor][RANK(c)] / 2),
1224 uSentries = CountBits(bb);
1227 // There's one or more sentry pawns so we'll look for helpers to
1228 // decide if this pawn is a candidate passer.
1230 if (uColor == WHITE)
1232 pSentry = BLACK_PAWN;
1233 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
1238 pSentry = WHITE_PAWN;
1239 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
1244 ASSERT(IS_ON_BOARD(cSquare));
1245 ASSERT(FILE(cSquare) == FILE(c));
1248 uVerifySentries = 0;
1250 d1 = 16 * g_iAhead[uColor];
1254 if (IS_ON_BOARD(c1 - 1))
1256 if (pos->rgSquare[c1 - 1].pPiece == pSentry)
1259 if (0 == cVerifySquare)
1261 cVerifySquare = c1 - d1;
1262 ASSERT(cVerifySquare == cSquare);
1266 if (IS_ON_BOARD(c1 + 1))
1268 if (pos->rgSquare[c1 + 1].pPiece == pSentry)
1271 if (0 == cVerifySquare)
1273 cVerifySquare = c1 - d1;
1274 ASSERT(cVerifySquare == cSquare);
1280 while(!RANK8(c1) && !RANK1(c1));
1281 ASSERT(uVerifySentries == uSentries);
1285 // Note: we don't do this with bitboards because we want to not
1286 // consider a pawn to be a potential passer if it can't safely
1287 // advance to get into helper position.
1289 // IDEA: scale the candidate passer bonus based on rank AND on
1290 // the distance the helper(s) have to go to get into position.
1293 d1 = 16 * g_iAhead[uColor];
1294 ASSERT(-d1 == 16 * g_iBehind[uColor]);
1295 c1 = cSquare + 1 - d1;
1296 if ((IS_ON_BOARD(c1)) && (pHash->uCountPerFile[uColor][FILE(c1) + 1]))
1298 ASSERT(pHash->bbPawnLocations[uColor] & BBFILE[FILE(c1)]);
1299 if (!(pos->rgSquare[c1 + 8].bvAttacks[FLIP(uColor)].uWholeThing) ||
1300 (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing))
1303 // The square c1 the place a helper pawn must get to in
1304 // order to aide the candidate past a sentry.
1306 if (pos->rgSquare[c1].pPiece == pHelper)
1313 // There is no helper pawn in the support position yet.
1314 // See if one can get there.
1317 while (IS_ON_BOARD(c1) &&
1318 ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
1319 (pos->rgSquare[c1+8].bvAttacks[uColor].uWholeThing)))
1321 if (pos->rgSquare[c1].pPiece == pHelper)
1326 else if (pos->rgSquare[c1].pPiece == pSentry)
1336 c1 = cSquare - 1 - d1;
1337 if ((IS_ON_BOARD(c1)) && (pHash->uCountPerFile[uColor][FILE(c1) + 1]))
1339 ASSERT(pHash->bbPawnLocations[uColor] & BBFILE[FILE(c1)]);
1341 if (!(pos->rgSquare[c1 + 8].bvAttacks[FLIP(uColor)].uWholeThing) ||
1342 (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing))
1345 // The square c1 is the place a helper pawn must get to in
1346 // order to aide the candidate.
1348 if (pos->rgSquare[c1].pPiece == pHelper)
1355 // There is no pawn in the left support position yet. See
1356 // if one can get there.
1359 while (IS_ON_BOARD(c1) &&
1360 ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
1361 (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing)))
1363 if (pos->rgSquare[c1].pPiece == pHelper)
1368 else if (pos->rgSquare[c1].pPiece == pSentry)
1378 if ((uHelpers >= uSentries) ||
1379 ((pHash->uCountPerFile[uColor][uPawnFile + 1] +
1380 pHash->uCountPerFile[uColor][uPawnFile - 1]) &&
1381 (((WHITE == uColor) && (RANK(c) > 5)) ||
1382 ((BLACK == uColor) && (RANK(c) < 4)))))
1384 ASSERT(CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)] > 0);
1388 pHash->iScore[uColor],
1389 CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)],
1390 "candidate passer");
1393 // If the other side has no pieces then give this candidate an
1396 if (pos->uNonPawnCount[FLIP(uColor)][0] == 1)
1401 pHash->iScore[uColor],
1402 CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)],
1403 "candidate passer in endgame");
1409 _EvaluateConnectedSupportedOutsidePassers(IN POSITION *pos,
1410 IN OUT PAWN_HASH_ENTRY *pHash)
1413 Routine description:
1418 PAWN_HASH_ENTRY *pHash
1429 COOR cLeftmostPasser, cRightmostPasser;
1433 static const INT iDelta[5] =
1438 FOREACH_COLOR(uColor)
1440 ASSERT(IS_VALID_COLOR(uColor));
1442 if (pHash->bbPasserLocations[uColor])
1444 ASSERT(pos->uPawnCount[uColor] > 0);
1445 pFriend = BLACK_PAWN | uColor;
1446 cLeftmostPasser = cRightmostPasser = ILLEGAL_COOR;
1447 for (u = A; u <= H; u++)
1449 bb = pHash->bbPasserLocations[uColor] & BBFILE[u];
1452 ASSERT(pHash->uCountPerFile[uColor][u+1] != 0);
1453 while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bb)))
1456 // Keep track of leftmost/rightmost passer for
1457 // outside passer code later on.
1459 ASSERT(FILE(c) == u);
1460 ASSERT(RANK(c) > 1);
1461 ASSERT(RANK(c) < 8);
1462 if (cLeftmostPasser == ILLEGAL_COOR)
1464 cLeftmostPasser = c;
1466 cRightmostPasser = c;
1469 while(iDelta[v] != 0)
1471 cSupport = c + iDelta[v] * g_iBehind[uColor];
1472 if (IS_ON_BOARD(cSupport))
1474 if (pHash->bbPasserLocations[uColor] &
1475 COOR_TO_BB(cSupport))
1477 ASSERT(CONNECTED_PASSERS_BY_RANK[uColor]
1482 pHash->iScore[uColor],
1483 CONNECTED_PASSERS_BY_RANK[uColor]
1485 "connected passers");
1488 // TODO: connected passers vs a R is
1492 else if (pos->rgSquare[cSupport].pPiece ==
1495 ASSERT(SUPPORTED_PASSER_BY_RANK[uColor]
1500 pHash->iScore[uColor],
1501 SUPPORTED_PASSER_BY_RANK[uColor]
1503 "supported passer");
1513 ASSERT(IS_ON_BOARD(cLeftmostPasser));
1514 ASSERT(IS_ON_BOARD(cRightmostPasser));
1515 ASSERT(RANK(cLeftmostPasser) > 1);
1516 ASSERT(RANK(cRightmostPasser) > 1);
1517 ASSERT(RANK(cLeftmostPasser) < 8);
1518 ASSERT(RANK(cRightmostPasser) < 8);
1519 if (CountBits(pHash->bbPasserLocations[uColor]) == 1)
1521 ASSERT(cLeftmostPasser == cRightmostPasser);
1524 for (u = A; u <= D; u++)
1526 if (pHash->uCountPerFile[FLIP(uColor)][u + 1] != 0)
1528 ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[u]);
1529 if (!(pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[u]))
1535 if (u > FILE(cLeftmostPasser))
1540 pHash->iScore[uColor],
1541 OUTSIDE_PASSER_BY_DISTANCE[u-FILE(cLeftmostPasser)],
1542 "left outside passer");
1545 for (u = H; u >= E; u--)
1547 if (pHash->uCountPerFile[FLIP(uColor)][u + 1] != 0)
1549 ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[u]);
1550 if (!(pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[u]))
1556 if (u < FILE(cRightmostPasser))
1561 pHash->iScore[uColor],
1562 OUTSIDE_PASSER_BY_DISTANCE[FILE(cRightmostPasser)-u],
1563 "right outside passer");
1570 #define PAWN_ATTACK_BLACK_DELTA (+15)
1571 #define PAWN_ATTACK_WHITE_DELTA (-17)
1574 _PopulatePawnAttackBits(IN OUT POSITION *pos)
1577 Routine description:
1579 Populate the attack table with pawn bits.
1583 POSITION *pos : the board
1596 // IDEA: combine clearing and initial population somehow?
1598 // r - - - - - - l : only check L- and R-
1605 // r - - - - - - l : only check L+ and R+
1606 _ClearAttackTables(pos);
1608 ASSERT(pos->uPawnCount[BLACK] <= 8);
1610 u < pos->uPawnCount[BLACK];
1613 c = pos->cPawns[BLACK][u];
1614 ASSERT(IS_ON_BOARD(c));
1615 ASSERT(pos->rgSquare[c].pPiece);
1616 ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
1617 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == BLACK);
1620 // IDEA: These IS_ON_BOARD checks can be removed by a lookup table.
1622 cAttack = c + PAWN_ATTACK_BLACK_DELTA;
1623 if (IS_ON_BOARD(cAttack))
1625 ASSERT((cAttack + 8) == (cAttack|8));
1626 ASSERT(!IS_ON_BOARD(cAttack|8));
1627 pos->rgSquare[cAttack|8].bvAttacks[BLACK].small.uPawn = 1;
1630 if (IS_ON_BOARD(cAttack))
1632 ASSERT((cAttack + 8) == (cAttack|8));
1634 ASSERT(!IS_ON_BOARD(cAttack));
1635 pos->rgSquare[cAttack].bvAttacks[BLACK].small.uPawn = 1;
1639 ASSERT(pos->uPawnCount[WHITE] <= 8);
1641 u < pos->uPawnCount[WHITE];
1644 c = pos->cPawns[WHITE][u];
1645 ASSERT(IS_ON_BOARD(c));
1646 ASSERT(pos->rgSquare[c].pPiece);
1647 ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
1648 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == WHITE);
1650 cAttack = c + PAWN_ATTACK_WHITE_DELTA;
1651 if (IS_ON_BOARD(cAttack))
1653 ASSERT((cAttack + 8) == (cAttack|8));
1654 ASSERT(!IS_ON_BOARD(cAttack|8));
1655 pos->rgSquare[cAttack|8].bvAttacks[WHITE].small.uPawn = 1;
1658 if (IS_ON_BOARD(cAttack))
1660 ASSERT((cAttack + 8) == (cAttack|8));
1662 ASSERT(!IS_ON_BOARD(cAttack));
1663 pos->rgSquare[cAttack].bvAttacks[WHITE].small.uPawn = 1;
1669 static PAWN_HASH_ENTRY *
1670 _EvalPawns(IN OUT SEARCHER_THREAD_CONTEXT *ctx,
1671 OUT FLAG *pfDeferred)
1674 Routine description:
1676 Evaluate pawn structures; return a ptr to a pawn hash entry.
1680 SEARCHER_THREAD_CONTEXT *ctx : the searcher thread context
1688 static ULONG uUnmovedRank[2] = { 0x10, 0x60 };
1689 POSITION *pos = &ctx->sPosition;
1690 PAWN_HASH_ENTRY *pHash;
1698 ULONG uUnsupportable;
1706 // Now, look up the hash entry for this position.
1708 INC(ctx->sCounters.pawnhash.u64Probes);
1709 pHash = PawnHashLookup(ctx);
1710 ASSERT(NULL != pHash);
1711 if (pHash->u64Key == pos->u64PawnSig)
1714 INC(ctx->sCounters.pawnhash.u64Hits);
1719 // We need the attack table to evaluate the pawns... and we missed
1720 // the hash table so we have to populate it now. Can't defer this
1723 *pfDeferred = FALSE;
1724 _InitializePawnHashEntry(pHash, pos);
1725 _PopulatePawnAttackBits(pos);
1726 uIsolated[BLACK] = uIsolated[WHITE] = 0;
1727 uDoubled[BLACK] = uDoubled[WHITE] = 0;
1728 iDuos[BLACK] = iDuos[WHITE] = 0;
1733 FOREACH_COLOR(uColor)
1735 ASSERT(IS_VALID_COLOR(uColor));
1736 ASSERT(pos->uPawnCount[uColor] <= 8);
1738 d1 = 16 * g_iAhead[uColor];
1740 u < pos->uPawnCount[uColor];
1743 c = pos->cPawns[uColor][u];
1744 ASSERT(IS_ON_BOARD(c));
1745 ASSERT(pos->rgSquare[c].pPiece);
1746 ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
1747 uPawnFile = FILE(c) + 1;
1748 ASSERT((1 <= uPawnFile) && (uPawnFile <= 8));
1751 // Update files counter
1753 ASSERT(pHash->uCountPerFile[uColor][uPawnFile] < 6);
1754 pHash->uCountPerFile[uColor][uPawnFile]++;
1757 // Update bitboard bit
1759 ASSERT(CountBits(pHash->bbPawnLocations[uColor] &
1760 BBFILE[uPawnFile-1]) < 6);
1761 ASSERT((pHash->bbPawnLocations[uColor] & COOR_TO_BB(c)) == 0);
1762 pHash->bbPawnLocations[uColor] |= COOR_TO_BB(c);
1763 ASSERT(CountBits(pHash->bbPawnLocations[uColor] &
1764 BBFILE[uPawnFile-1]) ==
1765 pHash->uCountPerFile[uColor][uPawnFile]);
1768 // Count unmoved pawns
1770 pHash->uNumUnmovedPawns[uColor] +=
1771 ((c & 0xF0) == uUnmovedRank[uColor]);
1772 ASSERT(pHash->uNumUnmovedPawns[uColor] <= 8);
1775 // Detect rammed and other stationary pawns.
1778 ASSERT(IS_ON_BOARD(cSquare));
1779 p = pos->rgSquare[cSquare].pPiece;
1782 pHash->bbStationaryPawns[uColor] |= COOR_TO_BB(c);
1783 ASSERT(CountBits(pHash->bbStationaryPawns[uColor]) <= 8);
1784 pHash->uNumRammedPawns += OPPOSITE_COLORS(p, uColor);
1785 ASSERT(pHash->uNumRammedPawns <= 16);
1789 // Give central pawns a small bonus; penalize rook pawns:
1794 pHash->iScore[uColor],
1795 PAWN_CENTRALITY_BONUS[c],
1801 // We counted rammed pawns twice (once for the black pawn and once
1802 // for the white one). Fix this now.
1804 ASSERT(!(pHash->uNumRammedPawns & 1));
1805 pHash->uNumRammedPawns /= 2;
1810 FOREACH_COLOR(uColor)
1812 ASSERT(IS_VALID_COLOR(uColor));
1813 ASSERT(pos->uPawnCount[uColor] <= 8);
1814 ASSERT(CountBits(pHash->bbPawnLocations[uColor]) <= 8);
1816 d1 = 16 * g_iAhead[uColor];
1818 u < pos->uPawnCount[uColor];
1821 c = pos->cPawns[uColor][u];
1822 ASSERT(IS_ON_BOARD(c));
1823 ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
1824 ASSERT((1 < RANK(c)) && (RANK(c) < 8));
1827 // Find weak pawns... pawns that are isolated are weak as
1828 // are pawns that have advanced beyond their support.
1829 // Both of these can tie up one or more pieces in order to
1833 uPawnFile = FILE(c) - 1;
1834 if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
1836 bb = (pHash->bbPawnLocations[uColor] &
1838 BBADJACENT_RANKS[RANK(c)]);
1841 bb = (pHash->bbPawnLocations[FLIP(uColor)] &
1843 while(IS_ON_BOARD(cSquare =
1844 CoorFromBitBoardRank8ToRank1(&bb)))
1846 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
1847 if (uColor == WHITE)
1849 if ((cSquare & 0xF0) >= (c & 0xF0))
1851 ASSERT(RANK(cSquare) <= RANK(c));
1858 ASSERT(uColor == BLACK);
1859 if ((cSquare & 0xF0) <= (c & 0xF0))
1861 ASSERT(RANK(cSquare) >= RANK(c));
1871 uUnsupportable = 1; // no friend pawn on that file
1873 if (0 == uUnsupportable)
1877 ASSERT(1 == uUnsupportable);
1879 uPawnFile = FILE(c) + 1;
1880 if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
1882 bb = (pHash->bbPawnLocations[uColor] &
1884 BBADJACENT_RANKS[RANK(c)]);
1887 bb = (pHash->bbPawnLocations[FLIP(uColor)] &
1889 while(IS_ON_BOARD(cSquare =
1890 CoorFromBitBoardRank8ToRank1(&bb)))
1892 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
1893 if (uColor == WHITE)
1895 if ((cSquare & 0xF0) >= (c & 0xF0))
1897 ASSERT(RANK(cSquare) <= RANK(c));
1904 ASSERT(uColor == BLACK);
1905 if ((cSquare & 0xF0) <= (c & 0xF0))
1907 ASSERT(RANK(cSquare) >= RANK(c));
1921 // If this pawn is not supportable from either side then
1922 // it is either isolated or has been pushed too far ahead
1923 // of its support. Either way it's a target -- penalize
1926 if (2 == uUnsupportable)
1928 uPawnFile = FILE(c) + 1;
1932 pHash->iScore[uColor],
1933 ISOLATED_PAWN_BY_PAWNFILE[uPawnFile],
1934 "target/isolated pawn");
1937 // Isolated + exposed? Extra penalty.
1939 ASSERT(ISOLATED_EXPOSED_PAWN < 0);
1943 pHash->iScore[uColor],
1944 ((pHash->uCountPerFile[FLIP(uColor)][uPawnFile]==0)*
1945 ISOLATED_EXPOSED_PAWN),
1949 // Exponential penalty term
1951 uIsolated[uColor] += 1;
1952 ASSERT(uIsolated[uColor] > 0);
1953 ASSERT(uIsolated[uColor] <= 8);
1956 // Isolated + doubled? Extra penalty.
1958 ASSERT(ISOLATED_DOUBLED_PAWN < 0);
1962 pHash->iScore[uColor],
1963 ((pHash->uCountPerFile[uColor][uPawnFile] > 1) *
1964 ISOLATED_DOUBLED_PAWN),
1965 "doubled + target");
1969 uPawnFile = FILE(c) + 1;
1970 ASSERT((1 <= uPawnFile) && (uPawnFile <= 8));
1971 ASSERT(CountBits(pHash->bbPawnLocations[uColor] & BBFILE[FILE(c)])
1972 == pHash->uCountPerFile[uColor][uPawnFile]);
1975 // Keep count of doubled pawns
1977 uDoubled[uColor] += (pHash->uCountPerFile[uColor][uPawnFile] > 1);
1978 ASSERT((0 <= uDoubled[uColor]) && (uDoubled[uColor] <= 8));
1981 // We can detect pawn duos (triads, etc...) and backward pawns
1982 // by considering the control of the pawn's stopsquare.
1985 ASSERT(IS_ON_BOARD(cSquare));
1986 ASSERT((cSquare + 8) == (cSquare | 8));
1987 if (pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing)
1990 // Count pawn duos. See "Pawn Power in Chess" pp 10-16
1993 t = ((uColor * RANK(cSquare)) +
1994 (FLIP(uColor) * (9 - RANK(cSquare))));
1995 if (uColor == WHITE)
1997 ASSERT(t == RANK(cSquare));
2001 ASSERT(uColor == BLACK);
2002 ASSERT(t == (9 - RANK(cSquare)));
2005 iDuos[uColor] += ((uColor * RANK(cSquare)) +
2006 (FLIP(uColor) * (9 - RANK(cSquare))));
2007 ASSERT(iDuos[uColor] <= (7 * 8));
2009 else if (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing)
2012 // Detect backwards pawns. See "Pawn Power in Chess" pp 25-27
2014 if (!IS_PAWN(pos->rgSquare[cSquare].pPiece))
2016 p = (BLACK_PAWN | uColor);
2017 if (((WHITE == uColor) && (RANK(c) < 4)) ||
2018 ((BLACK == uColor) && (RANK(c) > 5)))
2020 if ((IS_ON_BOARD(cSquare - 1) &&
2021 pos->rgSquare[cSquare - 1].pPiece == p) ||
2022 (IS_ON_BOARD(cSquare + 1) &&
2023 pos->rgSquare[cSquare + 1].pPiece == p))
2026 // The pawn at c is backward. Determine
2027 // whether it is shielded or exposed.
2029 pHash->bbStationaryPawns[uColor] |= COOR_TO_BB(c);
2030 ASSERT(CountBits(pHash->bbStationaryPawns[uColor])
2032 if (pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
2034 ASSERT(BACKWARD_SHIELDED_BY_LOCATION[c] < 0);
2038 pHash->iScore[uColor],
2039 BACKWARD_SHIELDED_BY_LOCATION[c],
2040 "shielded backward pawn");
2044 ASSERT(BACKWARD_EXPOSED_BY_LOCATION[c] < 0);
2048 pHash->iScore[uColor],
2049 BACKWARD_EXPOSED_BY_LOCATION[c],
2050 "exposed backward pawn");
2056 // TODO: Think about backward doubled pawns; read Kauffman's
2057 // paper "All About Doubled Pawns".
2062 // Handle passers / candidate passers
2064 _EvaluateCandidatePasser(pos, pHash, c);
2069 // Reward pawn duos, see "Pawn Power in Chess" pp. 10-16
2071 ASSERT(iDuos[WHITE] >= 0);
2072 ASSERT(iDuos[WHITE] <= 56);
2073 ASSERT(iDuos[BLACK] >= 0);
2074 ASSERT(iDuos[BLACK] <= 56);
2078 pHash->iScore[WHITE],
2084 pHash->iScore[BLACK],
2089 // The penalty for doubled pawns is scaled based on two primary
2090 // factors: the presence of major pieces for the side with doubled
2091 // pawns and the number of doubled pawns on the board. The
2092 // presence of major pieces makes the doubled pawns less severe
2093 // while the presence of many doubled pawns makes the penalty for
2094 // each more severe.
2096 ASSERT((uDoubled[WHITE] >= 0) && (uDoubled[WHITE] <= 8));
2097 ASSERT((uDoubled[BLACK] >= 0) && (uDoubled[BLACK] <= 8));
2098 u = pos->uNonPawnCount[BLACK][ROOK] + pos->uNonPawnCount[BLACK][QUEEN] * 2;
2103 pHash->iScore[BLACK],
2104 DOUBLED_PAWN_PENALTY_BY_COUNT[u][uDoubled[BLACK]],
2105 "exponential doubled");
2106 u = pos->uNonPawnCount[WHITE][ROOK] + pos->uNonPawnCount[WHITE][QUEEN] * 2;
2111 pHash->iScore[WHITE],
2112 DOUBLED_PAWN_PENALTY_BY_COUNT[u][uDoubled[WHITE]],
2113 "exponential doubled");
2115 ASSERT(uIsolated[WHITE] >= 0);
2116 ASSERT(uIsolated[WHITE] <= 8);
2117 ASSERT(uIsolated[BLACK] >= 0);
2118 ASSERT(uIsolated[BLACK] <= 8);
2122 pHash->iScore[BLACK],
2123 ISOLATED_PAWN_PENALTY_BY_COUNT[uIsolated[BLACK]],
2124 "exponential isolated");
2128 pHash->iScore[WHITE],
2129 ISOLATED_PAWN_PENALTY_BY_COUNT[uIsolated[WHITE]],
2130 "exponential isolated");
2133 // Look for connected, supported and outside passed pawns to give
2136 _EvaluateConnectedSupportedOutsidePassers(pos, pHash);
2139 // TODO: recognize quartgrips and stonewalls
2146 CountKingSafetyDefects(IN OUT POSITION *pos,
2150 Routine description:
2152 Determine how many defects uSide's king position has _quickly_.
2153 TODO: add more knowledge as cheaply as possible...
2167 ULONG xSide = FLIP(uSide);
2175 // Don't count king safety defects if the real eval code in
2176 // _EvalKing would not...
2178 if (pos->uNonPawnMaterial[xSide] < DO_KING_SAFETY_THRESHOLD) {
2182 cKing = pos->cNonPawns[uSide][0];
2183 uCounter = KING_INITIAL_COUNTER_BY_LOCATION[uSide][cKing] >> 1;
2184 ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
2185 ASSERT(pos->rgSquare[cKing].uIndex == 0);
2186 ASSERT(IS_ON_BOARD(cKing));
2187 ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uSide);
2190 // Make sure cKing - 1, cKing and cKing + 1 are on the board
2192 cKing += (!IS_ON_BOARD(cKing - 1));
2193 cKing -= (!IS_ON_BOARD(cKing + 1));
2194 ASSERT(IS_ON_BOARD(cKing));
2195 ASSERT(IS_ON_BOARD(cKing + 1));
2196 ASSERT(IS_ON_BOARD(cKing - 1));
2199 // Consider all enemy pieces except the king (not including pawns)
2202 u < pos->uNonPawnCount[xSide][0];
2205 c = pos->cNonPawns[xSide][u];
2206 ASSERT(IS_ON_BOARD(c));
2207 i = (int)c - (int)(cKing + 1);
2208 ASSERT((i >= -128) && (i <= 125));
2209 p = pos->rgSquare[c].pPiece;
2210 ASSERT(pos->rgSquare[c].uIndex == u);
2211 ASSERT(!IS_KING(p));
2212 ASSERT(GET_COLOR(p) == xSide);
2213 p = 1 << PIECE_TYPE(p);
2215 uCounter += ((i == 0) | (i == -2) |
2216 ((CHECK_VECTOR_WITH_INDEX(i, xSide) & p) != 0) |
2217 ((CHECK_VECTOR_WITH_INDEX(i + 1, xSide) & p) != 0) |
2218 ((CHECK_VECTOR_WITH_INDEX(i + 2, xSide) & p) != 0));
2220 ASSERT(uCounter < 15);
2222 // Save the number of enemy pieces pointing at this king for later use.
2223 pos->uPiecesPointingAtKing[uSide] =
2224 (uCounter - (KING_INITIAL_COUNTER_BY_LOCATION[uSide][cKing] >> 1));
2230 _QuicklyEstimateKingSafetyTerm(IN POSITION *pos,
2231 IN OUT SCORE *piAlphaMargin,
2232 IN OUT SCORE *piBetaMargin)
2235 Routine description:
2237 Before doing an early lazy eval, look at the position and try to
2238 quickly see if there is a large king safety positional component
2252 // IDEA: make this stuff dynamic like ctx->uPositional
2254 static const SCORE iScoreByDefectCount[15] = {
2255 33, 50, 88, 146, 215, 245, 280, 430, 550, 630, 646, 646, 646, 646, 646
2257 SCORE iPenaltyEst[2];
2260 ASSERT(CountKingSafetyDefects(pos, pos->uToMove) < 15);
2261 iPenaltyEst[WHITE] =
2262 iScoreByDefectCount[CountKingSafetyDefects(pos, WHITE)];
2263 ASSERT(iPenaltyEst[WHITE] > 0);
2265 ASSERT(CountKingSafetyDefects(pos, BLACK) < 15);
2266 iPenaltyEst[BLACK] =
2267 iScoreByDefectCount[CountKingSafetyDefects(pos, BLACK)];
2268 ASSERT(iPenaltyEst[BLACK] > 0);
2271 // For the beta margin, assume our king safety penalty will stand
2272 // and our opponents will be less severe than we guess... net bonus
2273 // to them / our bonus not as high.
2275 iRet = iPenaltyEst[pos->uToMove] - iPenaltyEst[FLIP(pos->uToMove)] / 2;
2278 *piBetaMargin += iRet;
2281 // For the alpha margin, assume our king safety penalty will not
2282 // be too bad and our opponents will be as bad as we guess... net
2283 // bonus to us / their offsetting bonus not as high.
2285 iRet = iPenaltyEst[FLIP(pos->uToMove)] - iPenaltyEst[pos->uToMove] / 2;
2288 *piAlphaMargin += iRet;
2293 _QuicklyEstimatePasserBonuses(POSITION *pos,
2294 PAWN_HASH_ENTRY *pHash,
2295 SCORE *piAlphaMargin,
2296 SCORE *piBetaMargin)
2298 SCORE iBonusEst[2] = {0, 0};
2303 // Guess about the passer bonuses
2305 if (pHash->bbPasserLocations[WHITE])
2307 u = pos->uNonPawnMaterial[BLACK] - VALUE_KING;
2310 ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
2312 (CountBits(pHash->bbPasserLocations[WHITE]) *
2313 PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
2315 if (pHash->bbPasserLocations[BLACK])
2317 u = pos->uNonPawnMaterial[WHITE] - VALUE_KING;
2320 ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
2322 (CountBits(pHash->bbPasserLocations[BLACK]) *
2323 PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
2327 // For the beta margin, assume our passer bonus gets reduced and
2328 // our opponent's is enhanced... net bonus to them / our bonus
2331 iRet = iBonusEst[pos->uToMove] / 2 - iBonusEst[FLIP(pos->uToMove)];
2333 *piBetaMargin += iRet;
2336 // For the alpha bonus, assume our passer bonus gets doubled and
2337 // our opponent's is reduced. Net bonus to us / their bonus not
2340 iRet = iBonusEst[pos->uToMove] - iBonusEst[FLIP(pos->uToMove)] / 2;
2342 *piAlphaMargin += iRet;
2347 _InvalidEvaluator(UNUSED POSITION *pos,
2349 UNUSED PAWN_HASH_ENTRY *pHash)
2352 Routine description:
2354 This code should never be called
2360 PAWN_HASH_ENTRY *pHash,
2368 UtilPanic(SHOULD_NOT_GET_HERE,
2369 NULL, NULL, NULL, NULL,
2370 __FILE__, __LINE__);
2374 // ======================================================================
2377 static FLAG FASTCALL
2378 _InvalidMobilityHelper(UNUSED POSITION *pos,
2380 UNUSED ULONG *puMobility,
2381 UNUSED ULONG *puBit)
2384 Routine description:
2386 This code should never be called
2397 static FLAG FASTCALL
2401 UtilPanic(SHOULD_NOT_GET_HERE,
2402 NULL, NULL, NULL, NULL,
2403 __FILE__, __LINE__);
2407 // ----------------------------------------------------------------------
2409 static FLAG FASTCALL
2410 _BMinorToEnemyLess(IN POSITION *pos,
2412 IN OUT ULONG *puMobility,
2413 UNUSED ULONG *puBit)
2416 Routine description:
2418 Consider a black minor (knight | bishop) taking an enemy pawn
2429 static FLAG FASTCALL : always TRUE, stop scanning in this direction
2434 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2435 PIECE p = pos->rgSquare[c].pPiece;
2437 ASSERT(IS_ON_BOARD(c));
2438 ASSERT(IS_ON_BOARD(pos->cPiece));
2439 ASSERT(!IS_EMPTY(p));
2440 ASSERT(PIECE_VALUE(p) < VALUE_BISHOP);
2441 ASSERT(!IS_EMPTY(pMinor));
2443 ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
2444 ASSERT(OPPOSITE_COLORS(p, pMinor));
2445 ASSERT(GET_COLOR(pMinor) == BLACK);
2447 *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
2448 ASSERT(*puMobility <= 8);
2449 return(TRUE); // stop scanning this dir
2452 static FLAG FASTCALL
2453 _WMinorToEnemyLess(IN POSITION *pos,
2455 IN OUT ULONG *puMobility,
2456 UNUSED ULONG *puBit)
2459 Routine description:
2470 static FLAG FASTCALL
2475 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2476 PIECE p = pos->rgSquare[c].pPiece;
2478 ASSERT(IS_ON_BOARD(c));
2479 ASSERT(IS_ON_BOARD(pos->cPiece));
2480 ASSERT(!IS_EMPTY(p));
2482 ASSERT(PIECE_VALUE(p) < VALUE_BISHOP);
2483 ASSERT(!IS_EMPTY(pMinor));
2484 ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
2485 ASSERT(OPPOSITE_COLORS(p, pMinor));
2486 ASSERT(GET_COLOR(pMinor) == WHITE);
2488 *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
2489 ASSERT(*puMobility <= 8);
2490 return(TRUE); // stop scanning this dir
2493 static FLAG FASTCALL
2494 _WRookToEnemyLess(POSITION *pos,
2497 UNUSED ULONG *puBit)
2500 Routine description:
2511 static FLAG FASTCALL
2516 PIECE p = pos->rgSquare[c].pPiece;
2517 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2519 ASSERT(IS_ROOK(pRook));
2520 ASSERT(!IS_EMPTY(p));
2521 ASSERT(OPPOSITE_COLORS(p, pRook));
2522 ASSERT(PIECE_VALUE(p) < VALUE_ROOK);
2523 ASSERT(WHITE == GET_COLOR(pRook));
2525 *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
2526 ASSERT(*puMobility <= 7);
2527 return(TRUE); // stop scanning this dir
2530 static FLAG FASTCALL
2531 _BRookToEnemyLess(IN POSITION *pos,
2533 IN OUT ULONG *puMobility,
2534 UNUSED ULONG *puBit)
2537 Routine description:
2548 static FLAG FASTCALL
2553 PIECE p = pos->rgSquare[c].pPiece;
2554 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2556 ASSERT(IS_ON_BOARD(c));
2557 ASSERT(IS_ON_BOARD(pos->cPiece));
2558 ASSERT(IS_ROOK(pRook));
2559 ASSERT(OPPOSITE_COLORS(p, pRook));
2560 ASSERT(PIECE_VALUE(p) < VALUE_ROOK);
2561 ASSERT(BLACK == GET_COLOR(pRook));
2563 *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
2564 ASSERT(*puMobility <= 7);
2565 return(TRUE); // stop scanning this dir
2569 static FLAG FASTCALL
2570 _BQueenToEnemyLess(IN POSITION *pos,
2572 IN OUT ULONG *puMobility,
2573 UNUSED ULONG *puBit)
2576 Routine description:
2587 static FLAG FASTCALL
2592 PIECE p = pos->rgSquare[c].pPiece;
2593 PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2595 ASSERT(IS_ON_BOARD(c));
2596 ASSERT(IS_ON_BOARD(pos->cPiece));
2597 ASSERT(IS_QUEEN(pQueen));
2598 ASSERT(PIECE_VALUE(p) < VALUE_QUEEN);
2599 ASSERT(GET_COLOR(pQueen) == BLACK);
2600 ASSERT(OPPOSITE_COLORS(pQueen, p));
2602 *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
2603 ASSERT(*puMobility <= 27);
2604 return(TRUE); // stop scanning this dir
2608 static FLAG FASTCALL
2609 _WQueenToEnemyLess(IN POSITION *pos,
2611 IN OUT ULONG *puMobility,
2612 UNUSED ULONG *puBit)
2615 Routine description:
2626 static FLAG FASTCALL
2631 PIECE p = pos->rgSquare[c].pPiece;
2632 PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2634 ASSERT(IS_ON_BOARD(c));
2635 ASSERT(IS_ON_BOARD(pos->cPiece));
2636 ASSERT(IS_QUEEN(pQueen));
2637 ASSERT(PIECE_VALUE(p) < VALUE_QUEEN);
2638 ASSERT(GET_COLOR(pQueen) == WHITE);
2639 ASSERT(OPPOSITE_COLORS(pQueen, p));
2641 *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
2642 ASSERT(*puMobility <= 27);
2643 return(TRUE); // stop scanning this dir
2646 // ----------------------------------------------------------------------
2648 static FLAG FASTCALL
2649 _EMinorToEnemySame(IN POSITION *pos,
2651 IN OUT ULONG *puMobility,
2652 UNUSED ULONG *puBit)
2655 Routine description:
2666 static FLAG FASTCALL
2671 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2672 PIECE p = pos->rgSquare[c].pPiece;
2674 ASSERT(IS_ON_BOARD(c));
2675 ASSERT(IS_ON_BOARD(pos->cPiece));
2676 ASSERT(!IS_EMPTY(p));
2677 ASSERT(!IS_EMPTY(pMinor));
2678 ASSERT(OPPOSITE_COLORS(p, pMinor));
2680 if (IS_BISHOP(pMinor))
2682 ASSERT(PIECE_VALUE(p) == VALUE_BISHOP);
2686 ASSERT(IS_KNIGHT(pMinor));
2687 ASSERT(PIECE_VALUE(p) >= VALUE_KNIGHT);
2691 ASSERT(*puMobility <= 8);
2692 return(TRUE); // stop scanning this dir
2696 static FLAG FASTCALL
2697 _ERookToEnemySame(IN POSITION *pos,
2699 IN OUT ULONG *puMobility,
2700 UNUSED ULONG *puBit)
2703 Routine description:
2714 static FLAG FASTCALL
2719 PIECE p = pos->rgSquare[c].pPiece;
2720 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2722 ASSERT(IS_ON_BOARD(c));
2723 ASSERT(IS_ON_BOARD(pos->cPiece));
2724 ASSERT(IS_ROOK(pRook));
2725 ASSERT(!IS_EMPTY(p));
2727 ASSERT(OPPOSITE_COLORS(p, pRook));
2730 ASSERT(*puMobility <= 7);
2731 return(TRUE); // stop scanning this dir
2735 static FLAG FASTCALL
2736 _EQueenToEnemyGreaterEqual(IN POSITION *pos,
2738 IN OUT ULONG *puMobility,
2739 UNUSED ULONG *puBit)
2742 Routine description:
2753 static FLAG FASTCALL
2758 PIECE p = pos->rgSquare[c].pPiece;
2759 PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2761 ASSERT(IS_ON_BOARD(c));
2762 ASSERT(IS_ON_BOARD(pos->cPiece));
2763 ASSERT(IS_QUEEN(pQueen));
2764 ASSERT(!IS_EMPTY(p));
2765 ASSERT(PIECE_VALUE(p) >= VALUE_QUEEN);
2766 ASSERT(OPPOSITE_COLORS(pQueen, p));
2769 ASSERT(*puMobility <= 27);
2770 return(TRUE); // stop scanning this dir
2773 // ----------------------------------------------------------------------
2775 static FLAG FASTCALL
2776 _EMinorToEnemyGreater(IN POSITION *pos,
2778 IN OUT ULONG *puMobility,
2779 IN OUT ULONG *puBit)
2782 Routine description:
2793 static FLAG FASTCALL
2798 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2799 PIECE p = pos->rgSquare[c].pPiece;
2801 ASSERT(IS_ON_BOARD(c));
2802 ASSERT(IS_ON_BOARD(pos->cPiece));
2803 ASSERT(!IS_EMPTY(p));
2804 ASSERT(PIECE_VALUE(p) > VALUE_BISHOP);
2805 ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
2806 ASSERT(OPPOSITE_COLORS(p, pMinor));
2809 ASSERT(*puMobility <= 8);
2810 *puBit = MINOR_XRAY_BIT;
2811 return(FALSE); // keep scanning this dir
2814 static FLAG FASTCALL
2815 _ERookToEnemyGreater(IN POSITION *pos,
2817 IN OUT ULONG *puMobility,
2818 IN OUT ULONG *puBit)
2821 Routine description:
2832 static FLAG FASTCALL
2837 PIECE p = pos->rgSquare[c].pPiece;
2838 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2840 ASSERT(IS_ON_BOARD(c));
2841 ASSERT(IS_ON_BOARD(pos->cPiece));
2842 ASSERT(IS_ROOK(pRook));
2843 ASSERT(!IS_EMPTY(p));
2844 ASSERT(OPPOSITE_COLORS(p, pRook));
2845 ASSERT(PIECE_VALUE(p) > VALUE_ROOK);
2848 ASSERT(*puMobility <= 7);
2849 *puBit = ROOK_XRAY_BIT;
2850 return(FALSE); // keep scanning this dir
2853 // ----------------------------------------------------------------------
2855 static FLAG FASTCALL
2856 _AnythingToFriendNoXray(IN POSITION *pos,
2858 UNUSED ULONG *puMobility,
2859 UNUSED ULONG *puBit)
2862 Routine description:
2873 static FLAG FASTCALL
2878 COOR cMover = pos->cPiece;
2879 PIECE pMover = pos->rgSquare[cMover].pPiece;
2880 PIECE pFriend = pos->rgSquare[c].pPiece;
2882 ASSERT(IS_ON_BOARD(c));
2883 ASSERT(IS_ON_BOARD(cMover));
2884 ASSERT(!IS_EMPTY(pFriend));
2885 ASSERT(!IS_EMPTY(pMover));
2886 ASSERT(GET_COLOR(pMover) == GET_COLOR(pFriend));
2887 if (IS_BISHOP(pMover))
2889 ASSERT(!IS_BISHOP(pFriend));
2890 ASSERT(!IS_QUEEN(pFriend));
2892 else if (IS_ROOK(pMover))
2894 ASSERT(!IS_QUEEN(pFriend));
2895 ASSERT(!IS_ROOK(pFriend));
2897 else if (IS_QUEEN(pMover))
2899 ASSERT(!IS_BISHOP(pFriend));
2900 ASSERT(!IS_ROOK(pFriend));
2901 ASSERT(!IS_QUEEN(pFriend));
2904 return(TRUE); // stop scanning this dir
2907 // ----------------------------------------------------------------------
2909 static FLAG FASTCALL
2910 _EMinorToFriendXray(IN POSITION *pos,
2912 IN OUT ULONG *puMobility,
2913 IN OUT ULONG *puBit)
2916 Routine description:
2927 static FLAG FASTCALL
2932 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2933 PIECE p = pos->rgSquare[c].pPiece;
2935 ASSERT(!IS_EMPTY(p));
2936 ASSERT(!IS_EMPTY(pMinor));
2937 ASSERT(IS_BISHOP(pMinor));
2938 ASSERT(GET_COLOR(p) == GET_COLOR(pMinor));
2940 *puBit = MINOR_XRAY_BIT;
2944 static FLAG FASTCALL
2945 _BRookToFriendRook(IN POSITION *pos,
2947 IN OUT ULONG *puMobility,
2948 IN OUT ULONG *puBit)
2951 Routine description:
2962 static FLAG FASTCALL
2966 COOR cRook = pos->cPiece;
2967 FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
2969 PIECE p = pos->rgSquare[c].pPiece;
2970 PIECE pRook = pos->rgSquare[cRook].pPiece;
2972 ASSERT(IS_ON_BOARD(c));
2973 ASSERT(IS_ON_BOARD(cRook));
2974 ASSERT(IS_ROOK(pRook));
2975 ASSERT(!IS_EMPTY(p));
2977 ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
2978 ASSERT(GET_COLOR(p) == BLACK);
2979 ASSERT((fHoriz && (RANK(c) == RANK(pos->cPiece))) ||
2980 (!fHoriz && (FILE(c) == FILE(pos->cPiece))));
2986 (ROOK_CONNECTED_HORIZ * fHoriz +
2987 ROOK_CONNECTED_VERT * FLIP(fHoriz)),
2989 *puBit = ROOK_XRAY_BIT;
2994 static FLAG FASTCALL
2995 _WRookToFriendRook(IN POSITION *pos,
2997 IN OUT ULONG *puMobility,
2998 IN OUT ULONG *puBit)
3001 Routine description:
3012 static FLAG FASTCALL
3016 COOR cRook = pos->cPiece;
3017 FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
3019 PIECE p = pos->rgSquare[c].pPiece;
3020 PIECE pRook = pos->rgSquare[cRook].pPiece;
3022 ASSERT(IS_ON_BOARD(c));
3023 ASSERT(IS_ON_BOARD(cRook));
3024 ASSERT(IS_ROOK(pRook));
3025 ASSERT(!IS_EMPTY(p));
3027 ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
3028 ASSERT(GET_COLOR(p) == WHITE);
3029 ASSERT((fHoriz && (RANK(c) == RANK(pos->cPiece))) ||
3030 (!fHoriz && (FILE(c) == FILE(pos->cPiece))));
3036 (ROOK_CONNECTED_HORIZ * fHoriz +
3037 ROOK_CONNECTED_VERT * FLIP(fHoriz)),
3039 *puBit = ROOK_XRAY_BIT;
3044 static FLAG FASTCALL
3045 _ERookToFriendQueen(IN POSITION *pos,
3047 IN OUT ULONG *puMobility,
3048 IN OUT ULONG *puBit)
3051 Routine description:
3062 static FLAG FASTCALL
3067 PIECE p = pos->rgSquare[c].pPiece;
3068 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3070 ASSERT(IS_ON_BOARD(c));
3071 ASSERT(IS_ON_BOARD(pos->cPiece));
3072 ASSERT(IS_ROOK(pRook));
3073 ASSERT(!IS_EMPTY(p));
3074 ASSERT(IS_QUEEN(p));
3075 ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
3077 *puBit = ROOK_XRAY_BIT;
3081 static FLAG FASTCALL
3082 _EQueenToFriendBishop(IN POSITION *pos,
3084 IN OUT ULONG *puMobility,
3085 IN OUT ULONG *puBit)
3088 Routine description:
3099 static FLAG FASTCALL
3103 COOR cQueen = pos->cPiece;
3105 PIECE p = pos->rgSquare[c].pPiece;
3106 PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3108 ASSERT(IS_ON_BOARD(c));
3109 ASSERT(IS_ON_BOARD(cQueen));
3110 ASSERT(IS_QUEEN(pQueen));
3111 ASSERT(IS_BISHOP(p));
3112 ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
3114 *puBit = QUEEN_XRAY_BIT;
3115 return((((c & 0xF0) == (cQueen & 0xF0)) ||
3116 ((c & 0x0F) == (cQueen & 0x0F))));
3120 static FLAG FASTCALL
3121 _EQueenToFriendRook(IN POSITION *pos,
3123 IN OUT ULONG *puMobility,
3124 IN OUT ULONG *puBit)
3127 Routine description:
3138 static FLAG FASTCALL
3142 COOR cQueen = pos->cPiece;
3144 PIECE p = pos->rgSquare[c].pPiece;
3145 PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3147 ASSERT(IS_ON_BOARD(c));
3148 ASSERT(IS_ON_BOARD(cQueen));
3149 ASSERT(IS_QUEEN(pQueen));
3151 ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
3153 *puBit = QUEEN_XRAY_BIT;
3154 return(FLIP((((c & 0xF0) == (cQueen & 0xF0)) ||
3155 ((c & 0x0F) == (cQueen & 0x0F)))));
3159 static FLAG FASTCALL
3160 _EQueenToFriendQueen(IN POSITION *pos,
3162 IN OUT ULONG *puMobility,
3163 IN OUT ULONG *puBit)
3166 Routine description:
3177 static FLAG FASTCALL
3182 COOR cQueen = pos->cPiece;
3183 PIECE p = pos->rgSquare[c].pPiece;
3184 PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3186 ASSERT(IS_ON_BOARD(c));
3187 ASSERT(IS_ON_BOARD(cQueen));
3188 ASSERT(IS_QUEEN(pQueen));
3189 ASSERT(IS_QUEEN(p));
3190 ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
3192 *puBit = QUEEN_XRAY_BIT;
3197 // ----------------------------------------------------------------------
3199 static FLAG FASTCALL
3200 _BMinorToEmpty(IN POSITION *pos,
3202 IN OUT ULONG *puMobility,
3203 IN OUT ULONG *puBit)
3206 Routine description:
3217 static FLAG FASTCALL
3222 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
3223 PIECE p = pos->rgSquare[c].pPiece;
3225 ASSERT(IS_EMPTY(p));
3226 ASSERT(!IS_EMPTY(pMinor));
3227 ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
3228 ASSERT(GET_COLOR(pMinor) == BLACK);
3230 *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
3231 ASSERT(*puMobility <= 8);
3235 static FLAG FASTCALL
3236 _WMinorToEmpty(IN POSITION *pos,
3238 IN OUT ULONG *puMobility,
3239 IN OUT ULONG *puBit)
3242 Routine description:
3253 static FLAG FASTCALL
3258 PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
3259 PIECE p = pos->rgSquare[c].pPiece;
3261 ASSERT(IS_EMPTY(p));
3262 ASSERT(!IS_EMPTY(pMinor));
3263 ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
3264 ASSERT(GET_COLOR(pMinor) == WHITE);
3266 *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
3267 ASSERT(*puMobility <= 8);
3271 static FLAG FASTCALL
3272 _WRookToEmpty(IN POSITION *pos,
3274 IN OUT ULONG *puMobility,
3275 IN OUT ULONG *puBit)
3278 Routine description:
3289 static FLAG FASTCALL
3294 PIECE p = pos->rgSquare[c].pPiece;
3295 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3297 ASSERT(IS_ON_BOARD(c));
3298 ASSERT(IS_ON_BOARD(pos->cPiece));
3299 ASSERT(IS_ROOK(pRook));
3300 ASSERT(IS_EMPTY(p));
3301 ASSERT(GET_COLOR(pRook) == WHITE);
3303 *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
3304 ASSERT(*puMobility <= 7);
3308 static FLAG FASTCALL
3309 _BRookToEmpty(IN POSITION *pos,
3311 IN OUT ULONG *puMobility,
3312 IN OUT ULONG *puBit)
3315 Routine description:
3326 static FLAG FASTCALL
3331 PIECE p = pos->rgSquare[c].pPiece;
3332 PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3334 ASSERT(IS_ON_BOARD(c));
3335 ASSERT(IS_ON_BOARD(pos->cPiece));
3336 ASSERT(IS_ROOK(pRook));
3337 ASSERT(IS_EMPTY(p));
3338 ASSERT(GET_COLOR(pRook) == BLACK);
3340 *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
3341 ASSERT(*puMobility <= 7);
3345 static FLAG FASTCALL
3346 _BQueenToEmpty(IN POSITION *pos,
3348 IN OUT ULONG *puMobility,
3349 IN OUT ULONG *puBit)
3352 Routine description:
3363 static FLAG FASTCALL
3368 PIECE p = pos->rgSquare[c].pPiece;
3369 PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
3371 ASSERT(IS_ON_BOARD(c));
3372 ASSERT(IS_ON_BOARD(pos->cPiece));
3373 ASSERT(IS_QUEEN(pQueen));
3374 ASSERT(IS_EMPTY(p));
3375 ASSERT(GET_COLOR(pQueen) == BLACK);
3377 *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
3378 ASSERT(*puMobility <= 27);
3382 static FLAG FASTCALL
3383 _WQueenToEmpty(IN POSITION *pos,
3385 IN OUT ULONG *puMobility,
3386 IN OUT ULONG *puBit)
3389 Routine description:
3400 static FLAG FASTCALL
3405 PIECE p = pos->rgSquare[c].pPiece;
3406 PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
3408 ASSERT(IS_ON_BOARD(c));
3409 ASSERT(IS_ON_BOARD(pos->cPiece));
3410 ASSERT(IS_QUEEN(pQueen));
3411 ASSERT(IS_EMPTY(p));
3412 ASSERT(GET_COLOR(pQueen) == WHITE);
3414 *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
3415 ASSERT(*puMobility <= 27);
3421 static FLAG FASTCALL
3422 _EBishopToFriendPawn(IN POSITION *pos,
3424 IN OUT ULONG *puMobility,
3425 IN OUT ULONG *puBit)
3428 Routine description:
3439 static FLAG FASTCALL
3444 PIECE pPawn = pos->rgSquare[c].pPiece;
3445 PIECE pBishop = pos->rgSquare[pos->cPiece].pPiece;
3447 ASSERT(IS_ON_BOARD(c));
3448 ASSERT(IS_ON_BOARD(pos->cPiece));
3449 ASSERT(IS_BISHOP(pBishop));
3450 ASSERT(IS_PAWN(pPawn));
3451 ASSERT(GET_COLOR(pBishop) == GET_COLOR(pPawn));
3453 *puMobility += ((pos->bb & COOR_TO_BB(c)) != 0);
3461 // ======================================================================
3466 _EvalBishop(IN OUT POSITION *pos,
3468 IN PAWN_HASH_ENTRY *pHash)
3471 Routine description:
3477 PAWN_HASH_ENTRY *pHash,
3485 static const BITBOARD bbColorSq[2] = { 0x55aa55aa55aa55aaULL,
3486 0xaa55aa55aa55aa55ULL };
3487 static const PMOBILITY_HELPER BMobJumpTable[2][14] =
3490 _BMinorToEmpty, // EMPTY_SQUARE (0)
3491 _InvalidMobilityHelper, // INVALID_PIECE (1)
3492 _EBishopToFriendPawn, // BLACK_PAWN (2)
3493 _BMinorToEnemyLess, // WHITE_PAWN (3)
3494 _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
3495 _EMinorToEnemySame, // WHITE_KNIGHT (5)
3496 _EMinorToFriendXray, // BLACK_BISHOP (6)
3497 _EMinorToEnemySame, // WHITE_BISHOP (7)
3498 _AnythingToFriendNoXray, // BLACK_ROOK (8)
3499 _EMinorToEnemyGreater, // WHITE_ROOK (9)
3500 _EMinorToFriendXray, // BLACK_QUEEN (10)
3501 _EMinorToEnemyGreater, // WHITE_QUEEN (11)
3502 _AnythingToFriendNoXray, // BLACK_KING (12)
3503 _EMinorToEnemyGreater, // WHITE_KING (13)
3506 _WMinorToEmpty, // EMPTY_SQUARE (0)
3507 _InvalidMobilityHelper, // INVALID_PIECE (1)
3508 _WMinorToEnemyLess, // BLACK_PAWN (2)
3509 _EBishopToFriendPawn, // WHITE_PAWN (3)
3510 _EMinorToEnemySame, // BLACK_KNIGHT (4)
3511 _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
3512 _EMinorToEnemySame, // BLACK_BISHOP (6)
3513 _EMinorToFriendXray, // WHITE_BISHOP (7)
3514 _EMinorToEnemyGreater, // BLACK_ROOK (8)
3515 _AnythingToFriendNoXray, // WHITE_ROOK (9)
3516 _EMinorToEnemyGreater, // BLACK_QUEEN (10)
3517 _EMinorToFriendXray, // WHITE_QUEEN (11)
3518 _EMinorToEnemyGreater, // BLACK_KING (12)
3519 _AnythingToFriendNoXray, // WHITE_KING (13)
3522 static const COOR cBishopAtHome[2][2] =
3524 { C8, F8 }, // BLACK
3534 ULONG uTotalMobility;
3536 ULONG uCurrentMobility;
3539 PMOBILITY_HELPER pFun;
3541 ASSERT(IS_ON_BOARD(c));
3542 p = pos->rgSquare[c].pPiece;
3543 ASSERT(p && IS_BISHOP(p));
3544 uColor = GET_COLOR(p);
3553 pos->uMinorsAtHome[uColor] += (c == cBishopAtHome[uColor][0]);
3554 pos->uMinorsAtHome[uColor] += (c == cBishopAtHome[uColor][1]);
3555 ASSERT(pos->uMinorsAtHome[uColor] <= 4);
3558 // Good and bad bishops
3561 bbMask = bbColorSq[IS_SQUARE_WHITE(c)];
3562 bb = pHash->bbStationaryPawns[uColor] & bbMask;
3563 ASSERT(CountBits(bb) <= 16);
3564 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
3567 // Consider stationary (rammed or backward) pawns of the same
3568 // color as the bishop.
3570 ASSERT(pos->rgSquare[cSquare].pPiece);
3571 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
3572 ASSERT(GET_COLOR(pos->rgSquare[cSquare].pPiece) == uColor);
3573 i += STATIONARY_PAWN_ON_BISHOP_COLOR[cSquare];
3578 pos->iScore[uColor],
3580 "good/bad stationary pawns ++");
3583 bbPc = ~(pHash->bbStationaryPawns[WHITE] |
3584 pHash->bbStationaryPawns[BLACK]);
3586 bb = pHash->bbPawnLocations[uColor] & bbPc;
3587 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
3589 ASSERT(pos->rgSquare[cSquare].pPiece);
3590 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
3591 ASSERT(GET_COLOR(pos->rgSquare[cSquare].pPiece) == uColor);
3592 ASSERT(pHash->bbPawnLocations[uColor] & COOR_TO_BB(cSquare));
3593 i += TRANSIENT_PAWN_ON_BISHOP_COLOR[cSquare];
3596 bb = pHash->bbPawnLocations[FLIP(uColor)] & bbPc;
3597 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
3600 // N.B. Only count enemy pawns that are supported by another
3603 ASSERT(pos->rgSquare[cSquare].pPiece);
3604 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
3605 ASSERT(GET_COLOR(pos->rgSquare[cSquare].pPiece) == FLIP(uColor));
3606 ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & COOR_TO_BB(cSquare));
3608 (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].small.uPawn != 0) *
3609 TRANSIENT_PAWN_ON_BISHOP_COLOR[cSquare] / 2;
3614 pos->iScore[uColor],
3616 "good/bad transient pawns");
3619 // Bonus to bishops in very open positions.
3621 ASSERT(pos->uClosedScaler <= 32);
3625 pos->iScore[uColor],
3626 BISHOP_IN_CLOSED_POSITION[pos->uClosedScaler],
3627 "in closed/open position");
3630 // Bishop mobility (and update attack table bits)
3632 u = uMaxMobility = uTotalMobility = 0;
3634 ASSERT(g_iBDeltas[u] != 0);
3637 uCurrentMobility = 0;
3639 cSquare = c + g_iBDeltas[u];
3641 while(IS_ON_BOARD(cSquare))
3644 // Always toggle attack table bits.
3646 ASSERT((cSquare|8) == (cSquare + 8));
3647 pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
3652 p = pos->rgSquare[cSquare].pPiece;
3653 pFun = BMobJumpTable[uColor][p];
3655 if (TRUE == (*pFun)(pos,
3662 cSquare += g_iBDeltas[u];
3664 uTotalMobility += uCurrentMobility;
3665 ASSERT((uMaxMobility & 0x80000000) == 0);
3666 ASSERT((uCurrentMobility & 0x80000000) == 0);
3667 uMaxMobility = MAXU(uMaxMobility, uCurrentMobility);
3668 ASSERT(uMaxMobility <= 7);
3671 while(g_iBDeltas[u] != 0);
3672 ASSERT(uTotalMobility <= 13);
3676 pos->iScore[uColor],
3677 BISHOP_MOBILITY_BY_SQUARES[uTotalMobility],
3682 pos->iScore[uColor],
3683 BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS[uMaxMobility],
3684 "consecutive bishop mobility");
3687 // Look for bishops with no mobility who are under attack. These
3688 // pieces are trapped!
3690 if (uTotalMobility == 0)
3692 pos->cTrapped[uColor] = c;
3694 uTotalMobility /= 2;
3695 ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
3696 ASSERT((uTotalMobility & 0x80000000) == 0);
3697 pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
3701 // Look for "active bad bishops". See if square c is safe from
3704 bb = pHash->bbPawnLocations[FLIP(uColor)] &
3705 (~pHash->bbStationaryPawns[FLIP(uColor)]);
3706 if (TRUE == _IsSquareSafeFromEnemyPawn(pos, c, bb))
3709 // Give a bonus based on distance from enemy king
3711 if (pos->rgSquare[c|8].bvAttacks[uColor].small.uPawn)
3714 p = BLACK_PAWN | uColor;
3715 ASSERT(((IS_ON_BOARD(c + 17 * g_iBehind[uColor]) &&
3716 (pos->rgSquare[c + 17 * g_iBehind[uColor]].pPiece==p)) ||
3717 ((IS_ON_BOARD(c + 15 * g_iBehind[uColor])) &&
3718 (pos->rgSquare[c + 15 * g_iBehind[uColor]].pPiece==p))));
3720 u = DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
3721 i = BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING[u];
3725 pos->iReducedMaterialDownScaler[uColor],
3727 "[scaled] unassailable");
3733 _EvalKnight(IN OUT POSITION *pos,
3735 IN PAWN_HASH_ENTRY *pHash)
3738 Routine description:
3744 PAWN_HASH_ENTRY *pHash,
3752 static const int iPawnStart[2] = { -17, +15 };
3753 static const PMOBILITY_HELPER NMobJumpTable[2][14] =
3756 _BMinorToEmpty, // EMPTY_SQUARE (0)
3757 _InvalidMobilityHelper, // INVALID_PIECE (1)
3758 _AnythingToFriendNoXray, // BLACK_PAWN (2)
3759 _BMinorToEnemyLess, // WHITE_PAWN (3)
3760 _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
3761 _EMinorToEnemySame, // WHITE_KNIGHT (5)
3762 _AnythingToFriendNoXray, // BLACK_BISHOP (6)
3763 _EMinorToEnemySame, // WHITE_BISHOP (7)
3764 _AnythingToFriendNoXray, // BLACK_ROOK (8)
3765 _EMinorToEnemySame, // WHITE_ROOK (9)
3766 _AnythingToFriendNoXray, // BLACK_QUEEN (10)
3767 _EMinorToEnemySame, // WHITE_QUEEN (11)
3768 _AnythingToFriendNoXray, // BLACK_KING (12)
3769 _EMinorToEnemySame, // WHITE_KING (13)
3772 _WMinorToEmpty, // EMPTY_SQUARE (0)
3773 _InvalidMobilityHelper, // INVALID_PIECE (1)
3774 _WMinorToEnemyLess, // BLACK_PAWN (2)
3775 _AnythingToFriendNoXray, // WHITE_PAWN (3)
3776 _EMinorToEnemySame, // BLACK_KNIGHT (4)
3777 _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
3778 _EMinorToEnemySame, // BLACK_BISHOP (6)
3779 _AnythingToFriendNoXray, // WHITE_BISHOP (7)
3780 _EMinorToEnemySame, // BLACK_ROOK (8)
3781 _AnythingToFriendNoXray, // WHITE_ROOK (9)
3782 _EMinorToEnemySame, // BLACK_QUEEN (10)
3783 _AnythingToFriendNoXray, // WHITE_QUEEN (11)
3784 _EMinorToEnemySame, // BLACK_KING (12)
3785 _AnythingToFriendNoXray, // WHITE_KING (13)
3788 static const COOR cKnightAtHome[2][2] =
3790 { B8, G8 }, // BLACK
3797 ULONG uPawnsSupporting;
3800 ULONG uMobilitySquares;
3803 PMOBILITY_HELPER pFun;
3805 p = pos->rgSquare[c].pPiece;
3806 ASSERT(p && IS_KNIGHT(p));
3807 uColor = GET_COLOR(p);
3808 ASSERT(IS_VALID_COLOR(uColor));
3816 pos->uMinorsAtHome[uColor] += (c == cKnightAtHome[uColor][0]);
3817 pos->uMinorsAtHome[uColor] += (c == cKnightAtHome[uColor][1]);
3818 ASSERT(pos->uMinorsAtHome[uColor] <= 4);
3821 // TODO: Don't block unmoved E2/D2 pawns
3830 pos->iScore[uColor],
3831 KNIGHT_CENTRALITY_BONUS[c],
3832 "board centrality");
3835 // Give a bonus to knights on a closed / busy board
3837 ASSERT(pos->uClosedScaler <= 32);
3841 pos->iScore[uColor],
3842 KNIGHT_IN_CLOSED_POSITION[pos->uClosedScaler],
3843 "in closed/open position");
3846 // See if square c is safe from enemy pawns; if so give bonus for
3847 // outposted knight which increases the closer it is to the enemy
3848 // king and the more pawns it has supporting it.
3850 uDist = DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
3851 ASSERT((uDist > 0) && (uDist <= 8));
3852 bb = pHash->bbPawnLocations[FLIP(uColor)] &
3853 (~pHash->bbStationaryPawns[FLIP(uColor)]);
3854 if (TRUE == _IsSquareSafeFromEnemyPawn(pos, c, bb))
3857 // Count the number of supporting pawns the knight has
3859 uPawnsSupporting = 0;
3860 p = BLACK_PAWN | uColor;
3861 cSquare = c + iPawnStart[uColor];
3862 uPawnsSupporting = (IS_ON_BOARD(cSquare) &&
3863 (pos->rgSquare[cSquare].pPiece == p));
3865 uPawnsSupporting += (IS_ON_BOARD(cSquare) &&
3866 (pos->rgSquare[cSquare].pPiece == p));
3867 ASSERT(uPawnsSupporting <= 2);
3870 // Give a bonus based on distance from enemy king
3872 i = KNIGHT_UNASSAILABLE_BY_DIST_FROM_EKING[uDist] +
3873 KNIGHT_WITH_N_PAWNS_SUPPORTING[uPawnsSupporting];
3877 pos->iReducedMaterialDownScaler[uColor],
3879 "[scaled] unassailable/support");
3882 // Now, if there's zero or one supporter see if the enemy has a
3883 // bishop the color of the knight it could capture with.
3885 if (uPawnsSupporting != 2)
3887 if (IS_SQUARE_WHITE(c))
3889 if (pos->uWhiteSqBishopCount[FLIP(uColor)])
3894 pos->iScore[uColor],
3896 "not safe from enemy B");
3901 if (pos->uNonPawnCount[FLIP(uColor)][BISHOP] -
3902 pos->uWhiteSqBishopCount[FLIP(uColor)])
3907 pos->iScore[uColor],
3909 "not safe from enemy B");
3914 else // not outposted
3917 // Still good to be close to the enemy king.
3919 i = KNIGHT_KING_TROPISM_BONUS[uDist];
3923 pos->iReducedMaterialDownScaler[uColor],
3925 "[scaled] enemy king tropism");
3929 // Give a bonus for blockading an enemy backward pawn. Note:
3930 // we also reward pieces for blocking enemy passers in the
3933 cSquare = c + 16 * g_iAhead[uColor];
3934 bb = pHash->bbStationaryPawns[FLIP(uColor)];
3935 if (bb & COOR_TO_BB(cSquare))
3937 ASSERT(pos->rgSquare[cSquare].pPiece);
3938 ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
3942 pos->iScore[uColor],
3943 KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[uColor][RANK(c)],
3944 "blockades enemy pawn");
3948 // A knight with an open file behind it is good.
3950 uPawnFile = FILE(c) + 1;
3954 pos->iScore[uColor],
3955 ((pHash->uCountPerFile[uColor][uPawnFile] == 0) *
3956 KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[uColor][RANK(c)]),
3957 "open file behind");
3960 // Do mobilility and piece relevance. Also update attack tables.
3962 uMobilitySquares = 0;
3964 ASSERT(g_iNDeltas[u] != 0);
3967 cSquare = c + g_iNDeltas[u];
3968 if (IS_ON_BOARD(cSquare))
3971 // Always update the attack bits
3973 ASSERT((cSquare + 8) == (cSquare | 8));
3974 pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uMinor = 1;
3979 p = pos->rgSquare[cSquare].pPiece;
3980 pFun = NMobJumpTable[uColor][p];
3981 if (pFun != _AnythingToFriendNoXray)
3990 // IDEA: bonus for hitting friendly pawn?
3995 while(g_iNDeltas[u] != 0);
3996 ASSERT(uMobilitySquares >= 0);
3997 ASSERT(uMobilitySquares <= 8);
4001 pos->iScore[uColor],
4002 KNIGHT_MOBILITY_BY_COUNT[uMobilitySquares],
4004 if (uMobilitySquares == 0)
4006 pos->cTrapped[uColor] = c;
4008 ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4009 ASSERT((uMobilitySquares & 0x80000000) == 0);
4010 pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
4015 _EvalRook(IN OUT POSITION *pos,
4017 IN PAWN_HASH_ENTRY *pHash)
4020 Routine description:
4026 IN PAWN_HASH_ENTRY *pHash,
4034 static const PMOBILITY_HELPER RMobJumpTable[2][14] =
4037 _BRookToEmpty, // EMPTY_SQUARE (0)
4038 _InvalidMobilityHelper, // INVALID_PIECE (1)
4039 _AnythingToFriendNoXray, // BLACK_PAWN (2)
4040 _BRookToEnemyLess, // WHITE_PAWN (3)
4041 _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
4042 _BRookToEnemyLess, // WHITE_KNIGHT (5)
4043 _AnythingToFriendNoXray, // BLACK_BISHOP (6)
4044 _BRookToEnemyLess, // WHITE_BISHOP (7)
4045 _BRookToFriendRook, // BLACK_ROOK (8)
4046 _ERookToEnemySame, // WHITE_ROOK (9)
4047 _ERookToFriendQueen, // BLACK_QUEEN (10)
4048 _ERookToEnemyGreater, // WHITE_QUEEN (11)
4049 _AnythingToFriendNoXray, // BLACK_KING (12)
4050 _ERookToEnemyGreater, // WHITE_KING (13)
4053 _WRookToEmpty, // EMPTY_SQUARE (0)
4054 _InvalidMobilityHelper, // INVALID_PIECE (1)
4055 _WRookToEnemyLess, // BLACK_PAWN (2)
4056 _AnythingToFriendNoXray, // WHITE_PAWN (3)
4057 _WRookToEnemyLess, // BLACK_KNIGHT (4)
4058 _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
4059 _WRookToEnemyLess, // BLACK_BISHOP (6)
4060 _AnythingToFriendNoXray, // WHITE_BISHOP (7)
4061 _ERookToEnemySame, // BLACK_ROOK (8)
4062 _WRookToFriendRook, // WHITE_ROOK (9)
4063 _ERookToEnemyGreater, // BLACK_QUEEN (10)
4064 _ERookToFriendQueen, // WHITE_QUEEN (11)
4065 _ERookToEnemyGreater, // BLACK_KING (12)
4066 _AnythingToFriendNoXray, // WHITE_KING (13)
4072 ULONG uPawnFile = FILE(c) + 1;
4075 ULONG uCurrentMobility;
4077 ULONG uTotalMobility;
4081 PMOBILITY_HELPER pFun;
4084 ASSERT(IS_ON_BOARD(c));
4085 p = pos->rgSquare[c].pPiece;
4086 ASSERT(p && IS_ROOK(p));
4087 uColor = GET_COLOR(p);
4088 ASSERT(IS_VALID_COLOR(uColor));
4092 // Reward being on a half open or full open file.
4094 if (0 == pHash->uCountPerFile[uColor][uPawnFile])
4096 u = FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
4097 if (0 == pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
4105 pos->iScore[uColor],
4106 ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING[u],
4112 // Half open, no friendly, just enemy.
4117 pos->iScore[uColor],
4118 ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[u],
4122 // Added bonus if the enemy pawn is a passer.
4124 bb = pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[FILE(c)];
4127 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4131 pos->iScore[uColor],
4132 PASSER_BY_RANK[FLIP(uColor)][RANK(cSquare)] / 4,
4133 "hassles enemy passer");
4137 else if (0 == pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
4140 // Half open, no enemy pawn, just a friendly
4142 u = FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
4146 pos->iScore[uColor],
4147 ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING[u],
4151 // See if the friend is a passed pawn and if the rook's in
4152 // front of it or behind it.
4154 bb = pHash->bbPasserLocations[uColor] & BBFILE[FILE(c)];
4158 // IDEA: Rook behind candidates, helpers or sentries is good
4159 // because the file may open soon.
4161 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4163 if (uColor == WHITE)
4171 ROOK_BEHIND_PASSER_BY_PASSER_RANK[WHITE]
4173 "behind own passer");
4181 ROOK_LEADS_PASSER_BY_PASSER_RANK[WHITE]
4183 "in the way of passer");
4186 ASSERT(uColor == BLACK);
4193 ROOK_BEHIND_PASSER_BY_PASSER_RANK[BLACK]
4195 "behind own passer");
4203 ROOK_LEADS_PASSER_BY_PASSER_RANK[BLACK]
4205 "in the way of passer");
4213 // Look for rooks that are trapping enemy kings.
4215 if (uColor == WHITE)
4217 pFriendRook = WHITE_ROOK;
4220 // Rook on 7th/8th rank with an enemy king back there.
4222 if ((c < A6) && (pos->cNonPawns[BLACK][0] < A6))
4224 ASSERT(RANK(c) > 6);
4225 ASSERT(RANK(pos->cNonPawns[BLACK][0]) > 6);
4231 ROOK_TRAPPING_EKING,
4232 "rook trapping enemy king");
4237 pFriendRook = BLACK_ROOK;
4240 // Rook on 7th/8th rank with an enemy king back there.
4242 if ((c > H3) && (pos->cNonPawns[WHITE][0] > H3))
4244 ASSERT(RANK(c) < 3);
4245 ASSERT(RANK(pos->cNonPawns[WHITE][0]) < 3);
4250 ROOK_TRAPPING_EKING,
4251 "rook trapping enemy king");
4256 // Rooks increase in value as pawns come off:
4258 // "A further refinement would be to raise the knight's value by
4259 // 1/16 and lower the rook's value by 1/8 for each pawn above five
4260 // of the side being valued, with the opposite adjustment for each
4261 // pawn short of five."
4262 // --Larry Kaufman, IM
4263 // "Evaluation of Material Imbalance"
4268 pos->iScore[uColor],
4269 ROOK_VALUE_AS_PAWNS_COME_OFF[pos->uPawnCount[uColor] +
4270 pos->uPawnCount[FLIP(uColor)]],
4271 "increase in value/pawns");
4276 u = uMaxMobility = uTotalMobility = 0;
4277 ASSERT(g_iRDeltas[u] != 0);
4280 uCurrentMobility = 0;
4282 cSquare = c + g_iRDeltas[u];
4284 while(IS_ON_BOARD(cSquare))
4287 // Twiddle our attack table bits.
4289 pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
4290 ASSERT((cSquare | 8) == (cSquare + 8));
4295 p = pos->rgSquare[cSquare].pPiece;
4296 pFun = RMobJumpTable[uColor][p];
4297 if (TRUE == (*pFun)(pos,
4304 cSquare += g_iRDeltas[u];
4306 uTotalMobility += uCurrentMobility;
4307 ASSERT(uTotalMobility <= 14);
4308 ASSERT((uMaxMobility & 0x80000000) == 0);
4309 ASSERT((uCurrentMobility & 0x80000000) == 0);
4310 uMaxMobility = MAXU(uCurrentMobility, uMaxMobility);
4311 ASSERT(uMaxMobility <= 7);
4314 while(g_iRDeltas[u] != 0);
4315 ASSERT(uTotalMobility <= 14);
4317 ASSERT(pos->uArmyScaler[FLIP(uColor)] <= 31);
4318 ASSERT(REDUCED_MATERIAL_UP_SCALER[pos->uArmyScaler[FLIP(uColor)]] <= 8);
4319 i = ROOK_MOBILITY_BY_SQUARES[uTotalMobility];
4320 i *= (int)(REDUCED_MATERIAL_UP_SCALER[pos->uArmyScaler[FLIP(uColor)]] + 1);
4325 pos->iScore[uColor],
4331 pos->iScore[uColor],
4332 ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[uMaxMobility],
4333 "consecutive rook mobility");
4335 ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4336 ASSERT((uTotalMobility & 0x80000000) == 0);
4337 pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
4339 if (uTotalMobility < 3)
4342 // Look for rooks with no mobility who are under attack. These
4343 // pieces are trapped!
4345 if (uTotalMobility == 0)
4347 pos->cTrapped[uColor] = c;
4351 // Rook trapped in the corner by a stupid friendly king?
4353 ASSERT(IS_VALID_COLOR(uColor));
4354 if (uColor == WHITE)
4356 ASSERT(IS_ON_BOARD(c));
4359 cSquare = pos->cNonPawns[WHITE][0];
4360 ASSERT(IS_ON_BOARD(cSquare));
4363 if (((cSquare > E1) && (c > cSquare)) ||
4364 ((cSquare < D1) && (c < cSquare)))
4371 "king trapping rook");
4378 ASSERT(uColor == BLACK);
4379 ASSERT(IS_ON_BOARD(c));
4382 cSquare = pos->cNonPawns[BLACK][0];
4383 ASSERT(IS_ON_BOARD(cSquare));
4387 if (((cSquare > E8) && (c > cSquare)) ||
4388 ((cSquare < D8) && (c < cSquare)))
4395 "king trapping rook");
4400 } // if low mobility
4405 _EvalQueen(IN OUT POSITION *pos,
4407 IN PAWN_HASH_ENTRY *pHash)
4414 PAWN_HASH_ENTRY *pHash,
4422 static const PMOBILITY_HELPER QMobJumpTable[2][14] =
4425 _BQueenToEmpty, // EMPTY_SQUARE (0)
4426 _InvalidMobilityHelper, // INVALID_PIECE (1)
4427 _AnythingToFriendNoXray, // BLACK_PAWN (2)
4428 _BQueenToEnemyLess, // WHITE_PAWN (3)
4429 _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
4430 _BQueenToEnemyLess, // WHITE_KNIGHT (5)
4431 _EQueenToFriendBishop, // BLACK_BISHOP (6)
4432 _BQueenToEnemyLess, // WHITE_BISHOP (7)
4433 _EQueenToFriendRook, // BLACK_ROOK (8)
4434 _BQueenToEnemyLess, // WHITE_ROOK (9)
4435 _EQueenToFriendQueen, // BLACK_QUEEN (10)
4436 _EQueenToEnemyGreaterEqual, // WHITE_QUEEN (11)
4437 _AnythingToFriendNoXray, // BLACK_KING (12)
4438 _EQueenToEnemyGreaterEqual, // WHITE_KING (13)
4441 _WQueenToEmpty, // EMPTY_SQUARE (0)
4442 _InvalidMobilityHelper, // INVALID_PIECE (1)
4443 _WQueenToEnemyLess, // BLACK_PAWN (2)
4444 _AnythingToFriendNoXray, // WHITE_PAWN (3)
4445 _WQueenToEnemyLess, // BLACK_KNIGHT (4)
4446 _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
4447 _WQueenToEnemyLess, // BLACK_BISHOP (6)
4448 _EQueenToFriendBishop, // WHITE_BISHOP (7)
4449 _WQueenToEnemyLess, // BLACK_ROOK (8)
4450 _EQueenToFriendRook, // WHITE_ROOK (9)
4451 _EQueenToEnemyGreaterEqual, // BLACK_QUEEN (10)
4452 _EQueenToFriendQueen, // WHITE_QUEEN (11)
4453 _EQueenToEnemyGreaterEqual, // BLACK_KING (12)
4454 _AnythingToFriendNoXray, // WHITE_KING (13)
4458 PIECE p = pos->rgSquare[c].pPiece;
4461 ULONG uTotalMobility;
4464 PMOBILITY_HELPER pFun;
4465 ULONG uNearKing = 0;
4468 ASSERT(IS_ON_BOARD(c));
4469 ASSERT(p && IS_QUEEN(p));
4470 uColor = GET_COLOR(p);
4471 ASSERT(IS_VALID_COLOR(uColor));
4473 cKing = pos->cNonPawns[FLIP(uColor)][0];
4474 ASSERT(IS_ON_BOARD(cKing));
4475 ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
4477 if ((FALSE == pos->fCastled[uColor]) && (pos->uMinorsAtHome[uColor] > 1))
4480 // Discourage queen being out too early
4482 if (!RANK1(c) && !RANK8(c))
4484 ASSERT(QUEEN_OUT_EARLY[pos->uMinorsAtHome[uColor]] < 0);
4485 ASSERT(pos->uMinorsAtHome[uColor] <= 4);
4489 pos->iScore[uColor],
4490 QUEEN_OUT_EARLY[pos->uMinorsAtHome[uColor]],
4491 "queen out too early");
4497 // Encourage enemy king tropism
4499 u = DISTANCE(c, cKing);
4500 ASSERT((u <= 7) && (u > 0));
4504 pos->iScore[uColor],
4505 QUEEN_KING_TROPISM[u],
4506 "enemy king tropism");
4510 // Do queen mobility
4514 ASSERT(g_iQKDeltas[u] != 0);
4518 cSquare = c + g_iQKDeltas[u];
4519 while(IS_ON_BOARD(cSquare))
4522 // Toggle attack table bits.
4524 pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
4529 p = pos->rgSquare[cSquare].pPiece;
4530 uNearKing += (DISTANCE(cSquare, cKing) <= 1);
4531 pFun = QMobJumpTable[uColor][p];
4532 if (TRUE == (*pFun)(pos,
4539 cSquare += g_iQKDeltas[u];
4543 while(g_iQKDeltas[u] != 0);
4545 ASSERT(uTotalMobility <= 27);
4549 pos->iScore[uColor],
4550 QUEEN_MOBILITY_BY_SQUARES[uTotalMobility],
4554 // Look for queens with no mobility who are under attack. These
4555 // pieces are trapped!
4557 if (uTotalMobility == 0)
4559 pos->cTrapped[uColor] = c;
4561 ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4562 ASSERT((uTotalMobility & 0x80000000) == 0);
4563 pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
4567 // If queen points near enemy king, that's a good thing too.
4569 ASSERT(uNearKing <= 6);
4573 pos->iScore[uColor],
4574 (uNearKing * QUEEN_ATTACKS_SQ_NEXT_TO_KING),
4575 "pointing near enemy K");
4579 _EvalKing(IN OUT POSITION *pos,
4581 IN const PAWN_HASH_ENTRY *pHash)
4584 Routine description:
4590 PAWN_HASH_ENTRY *pHash,
4599 ULONG uColor, ufColor;
4607 ULONG uFlightSquares;
4610 SCORE iKingScore = 0;
4612 static ULONG KingFlightDefects[9] =
4614 +4, +2, +1, 0, 0, 0, 0, 0, 0
4617 static ULONG KingStormingPawnDefects[8] =
4619 +0, +4, +3, +1, +0, +0, +0, +0
4622 static ULONG KingFileDefects[3] =
4627 static INT KingSafetyDeltas[11] =
4631 +15, +16, +17, -2, +2, 0
4634 static ULONG EmptyAttackedSquare[2][11] =
4648 static ULONG EmptyUnattackedSquare[2][11] =
4662 static ULONG OccupiedAttackedSquare[2] =
4668 ASSERT(IS_ON_BOARD(c));
4669 p = pos->rgSquare[c].pPiece;
4670 ASSERT(p && IS_KING(p));
4671 uColor = GET_COLOR(p);
4672 ufColor = FLIP(uColor);
4673 ASSERT(IS_VALID_COLOR(uColor));
4675 u = pos->uNonPawnMaterial[ufColor];
4676 ASSERT(u >= VALUE_KING);
4677 if (u < DO_KING_SAFETY_THRESHOLD)
4680 ASSERT(g_iQKDeltas[u] != 0);
4683 cSquare = c + g_iQKDeltas[u];
4684 if (IS_ON_BOARD(cSquare))
4686 pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uKing = 1;
4690 while(g_iQKDeltas[u] != 0);
4694 // Prepare to do king safety
4695 uCounter = (u >= KEEP_KING_AT_HOME_THRESHOLD) *
4696 KING_INITIAL_COUNTER_BY_LOCATION[uColor][c];
4698 Trace("%s Initial KS Counter: %u\n", COLOR_NAME(uColor), uCounter);
4701 uCounter += pos->uPiecesPointingAtKing[uColor] / 2;
4703 Trace("%s KS Counter after pieces pointing: %u\n",
4704 COLOR_NAME(uColor), uCounter);
4708 ASSERT(KingSafetyDeltas[u] != 0);
4711 cSquare = c + KingSafetyDeltas[u];
4712 if (IS_ON_BOARD(cSquare))
4714 p = pos->rgSquare[cSquare].pPiece;
4717 bvAttack = pos->rgSquare[cSquare].bvAttacks[ufColor].uSmall;
4718 bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray;
4719 pos->rgSquare[cSquare].bvAttacks[uColor].small.uKing = 1;
4720 bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall;
4724 bvPattern |= (bvAttack | bvXray);
4725 if (bvXray || (bvAttack & (bvAttack - 1)))
4732 uCounter += EmptyAttackedSquare[uColor][u];
4737 OccupiedAttackedSquare[OPPOSITE_COLORS(p, uColor)];
4739 uCounter += (bvDefend == 0);
4743 uCounter += (bvXray != 0);
4745 uCounter += EmptyUnattackedSquare[uColor][u];
4746 ASSERT((IS_EMPTY(p) == 0) || (IS_EMPTY(p) == 1));
4747 uFlightSquares += ((IS_EMPTY(p)) && (u < 8));
4752 while(KingSafetyDeltas[u] != 0);
4754 Trace("%s KS Counter post-squares: %u\n", COLOR_NAME(uColor), uCounter);
4757 if (IS_ON_BOARD(c - 1))
4759 u = FILE(c - 1) + 1;
4760 v = (pHash->uCountPerFile[WHITE][u] > 0) +
4761 (pHash->uCountPerFile[BLACK][u] > 0);
4762 ASSERT((v >= 0) && (v <= 2));
4764 // Note: open rook files are worse than open interior files
4765 uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
4767 bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
4770 if (uColor == WHITE)
4772 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4776 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4778 ASSERT(IS_ON_BOARD(cSquare));
4779 uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4784 v = (pHash->uCountPerFile[WHITE][u] > 0) +
4785 (pHash->uCountPerFile[BLACK][u] > 0);
4786 ASSERT((v >= 0) && (v <= 2));
4788 // Note: open rook files are worse than open interior files
4789 uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
4790 bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
4793 if (uColor == WHITE)
4795 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4799 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4801 ASSERT(IS_ON_BOARD(cSquare));
4802 uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4805 if (IS_ON_BOARD(c + 1))
4807 ASSERT((FILE(c + 1) + 1) == (u + 1));
4809 v = (pHash->uCountPerFile[WHITE][u] > 0) +
4810 (pHash->uCountPerFile[BLACK][u] > 0);
4811 ASSERT((v >= 0) && (v <= 2));
4813 // Note: open rook files are worse than open interior files
4814 uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
4816 bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
4819 if (uColor == WHITE)
4821 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4825 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4827 ASSERT(IS_ON_BOARD(cSquare));
4828 uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4832 Trace("%s KS Counter post-open file/stormers: %u\n", COLOR_NAME(uColor),
4837 ASSERT(bvPattern >= 0);
4838 ASSERT(bvPattern < 32);
4839 v = KING_COUNTER_BY_ATTACK_PATTERN[bvPattern];
4842 Trace("%s KS Counter post-attack pattern: %u\n", COLOR_NAME(uColor),
4846 ASSERT(uFlightSquares <= 8);
4847 uCounter += KingFlightDefects[uFlightSquares] * (v > 1);
4849 Trace("%s KS Counter post-flight sq: %u\n", COLOR_NAME(uColor), uCounter);
4853 // Note: can't use pos->iReducedMaterialDownScaler here because we
4854 // are scaling it based on the _other_ side's material.
4856 uCounter = MINU(uCounter, 41);
4857 i = KING_SAFETY_BY_COUNTER[uCounter];
4858 i *= REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[ufColor]];
4868 // Bonus for castling / penalty for loss of castle. Also, if side has
4869 // not yet castled, be concerned with undeveloped minor pieces.
4871 if (FALSE == pos->fCastled[uColor])
4873 if (pos->uNonPawnCount[uColor][0] > 4)
4875 ASSERT(pos->uMinorsAtHome[uColor] <= 4);
4879 pos->iScore[uColor],
4880 UNDEVELOPED_MINORS_IN_OPENING[pos->uMinorsAtHome[uColor]],
4882 if (uColor == BLACK)
4888 (KING_MISSING_ONE_CASTLE_OPTION *
4889 ((CASTLE_BLACK_SHORT & pos->bvCastleInfo) == 0)),
4890 "can't castle short");
4895 (KING_MISSING_ONE_CASTLE_OPTION *
4896 ((CASTLE_BLACK_LONG & pos->bvCastleInfo) == 0)),
4897 "can't castle long");
4901 ASSERT(uColor == WHITE);
4906 (KING_MISSING_ONE_CASTLE_OPTION *
4907 ((CASTLE_WHITE_SHORT & pos->bvCastleInfo) == 0)),
4908 "can't castle short");
4913 (KING_MISSING_ONE_CASTLE_OPTION *
4914 ((CASTLE_WHITE_LONG & pos->bvCastleInfo) == 0)),
4915 "can't castle long");
4922 // Special code for kings in the endgame
4924 u = pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0];
4928 // Encourage kings to come to the center
4930 i = KING_TO_CENTER[c];
4939 // Kings in front of passers in the late endgame are strong...
4942 bb = pHash->bbPasserLocations[uColor] &
4943 (BBADJACENT_FILES[cSquare] | BBFILE[cSquare]);
4946 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4948 if (DISTANCE(cSquare, c) == 1)
4950 ASSERT(abs((INT)FILE(c) - (INT)FILE(cSquare)) <= 1);
4951 ASSERT(abs((INT)RANK(c) - (INT)RANK(cSquare)) <= 1);
4954 i += SUPPORTED_PASSER_BY_RANK[uColor][RANK(cSquare)];
4958 i += 8 * (c < (cSquare - 1));
4962 i += 8 * (c > (cSquare + 1));
4970 "supporting own passer");
4976 // Detect kings way out of the action in KP endgames:
4978 // 8/8/1p6/p6k/P3K3/8/1P6/8 w - - 0 11
4980 if ((u == 2) && (uColor == WHITE))
4983 bb = (pHash->bbPawnLocations[WHITE] |
4984 pHash->bbPawnLocations[BLACK]);
4985 while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4987 i += (DISTANCE(cSquare, pos->cNonPawns[BLACK][0]) -
4988 DISTANCE(cSquare, pos->cNonPawns[WHITE][0]));
4995 "in/out of \"action\"");
4998 pos->iScore[uColor] += iKingScore;
4999 pos->iTempScore = iKingScore;
5004 EvalPasserRaces(IN OUT POSITION *pos,
5005 IN PAWN_HASH_ENTRY *pHash)
5008 Routine description:
5010 Determine if one side has a pawn that is unstoppable.
5012 This is broken for positions like:
5017 PAWN_HASH_ENTRY *pHash,
5030 ULONG uKingDist, uPawnDist, uFriendDist;
5031 ULONG uRacerDist[2] = { 99, 99 };
5032 FLAG fDontCountMeOut[2] = { ((RANK(pos->cNonPawns[BLACK][0]) <= 3) &&
5033 (pos->uPawnCount[BLACK] != 0)),
5034 ((RANK(pos->cNonPawns[WHITE][0]) >= 6) &&
5035 (pos->uPawnCount[WHITE] != 0)) };
5036 bb[BLACK] = pHash->bbPasserLocations[BLACK];
5037 bb[WHITE] = pHash->bbPasserLocations[WHITE];
5038 if (!(bb[BLACK] | bb[WHITE]))
5042 ASSERT((pos->uNonPawnCount[WHITE][0] == 1) ||
5043 (pos->uNonPawnCount[BLACK][0] == 1))
5044 FOREACH_COLOR(uColor)
5046 if (pos->uNonPawnCount[FLIP(uColor)][0] == 1)
5048 d1 = 16 * g_iAhead[uColor];
5049 ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
5052 while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(
5055 // If the enemy king can take this passer and is
5056 // on the move, all bets are off!
5057 cKing = pos->cNonPawns[FLIP(uColor)][0];
5058 ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
5059 ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) != uColor);
5060 if (pos->uToMove == FLIP(uColor) &&
5061 (DISTANCE(cKing, c) == 1))
5063 // TODO: something clever here about protected pawns
5067 cQueen = FILE_RANK_TO_COOR(FILE(c), QUEENING_RANK[uColor]);
5068 ASSERT(FILE(cQueen) == FILE(c));
5069 uPawnDist = RANK_DISTANCE(cQueen, c);
5070 if ((RANK(c) == JUMPING_RANK[uColor]) &&
5071 (IS_EMPTY(pos->rgSquare[c + d1].pPiece) &&
5072 IS_EMPTY(pos->rgSquare[c + d1 * 2].pPiece)))
5076 ASSERT((uPawnDist >= 1) && (uPawnDist <= 6));
5078 uKingDist = DISTANCE(cKing, cQueen);
5081 uKingDist -= (pos->uToMove == FLIP(uColor));
5083 ASSERT((uKingDist >= 0) && (uPawnDist <= 7));
5085 if (uPawnDist < uKingDist)
5087 uRacerDist[uColor] = MINU(uRacerDist[uColor],
5091 cKing = pos->cNonPawns[uColor][0];
5092 ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
5093 ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uColor);
5095 uFriendDist = DISTANCE(cKing, cQueen);
5096 if ((uFriendDist <= 1) && (DISTANCE(cKing, c) <= 1))
5098 if (FILE(c) != FILE(cKing))
5100 uRacerDist[uColor] = MINU(uRacerDist[uColor],
5103 else if ((FILE(cKing) != A) &&
5106 uRacerDist[uColor] = MINU(uRacerDist[uColor],
5110 fDontCountMeOut[uColor] = TRUE;
5113 // TODO: winning connected passers
5120 if ((uRacerDist[WHITE] < uRacerDist[BLACK]) &&
5121 (FALSE == fDontCountMeOut[BLACK]))
5127 RACER_WINS_RACE - uRacerDist[WHITE] * 4,
5128 "winning racer pawn");
5131 else if ((uRacerDist[BLACK] < uRacerDist[WHITE]) &&
5132 (FALSE == fDontCountMeOut[WHITE]))
5138 RACER_WINS_RACE - uRacerDist[BLACK] * 4,
5139 "winning racer pawn");
5147 _EvalPassers(IN OUT POSITION *pos,
5148 IN PAWN_HASH_ENTRY *pHash)
5151 Routine description:
5156 PAWN_HASH_ENTRY *pHash,
5171 ULONG uNumPassers[2] = { 0, 0 };
5174 ASSERT(pHash->bbPasserLocations[WHITE] |
5175 pHash->bbPasserLocations[BLACK]);
5177 FOREACH_COLOR(uColor)
5179 bb = pHash->bbPasserLocations[uColor];
5182 uNumPassers[uColor] = CountBits(bb);
5183 ASSERT(uNumPassers[uColor] > 0);
5184 d1 = 16 * g_iAhead[uColor];
5185 ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
5187 while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bb)))
5190 // Consider the control of the square in front of the passer
5193 ASSERT(IS_ON_BOARD(cSquare));
5194 u = _WhoControlsSquareFast(pos, cSquare);
5195 if (u == FLIP(uColor))
5200 pos->iScore[uColor],
5201 -((PASSER_BY_RANK[uColor][RANK(c)] / 4) +
5202 (PASSER_BY_RANK[uColor][RANK(c)] / 16)),
5203 "enemy controls sq ahead");
5205 else if (u == (ULONG)-1)
5207 p = pos->rgSquare[cSquare].pPiece;
5208 if (!IS_EMPTY(p) && (OPPOSITE_COLORS(p, uColor)))
5210 ASSERT(GET_COLOR(p) != uColor);
5214 pos->iScore[uColor],
5215 -(PASSER_BY_RANK[uColor][RANK(c)] / 4),
5216 "enemy occupies sq ahead");
5222 ASSERT(u == uColor);
5227 // Consider distance from friend king / enemy king
5229 i = (8 - DISTANCE(c, pos->cNonPawns[uColor][0]));
5230 if (((uColor == WHITE) &&
5231 ((pos->cNonPawns[BLACK][0] >> 4) <= (c >> 4))) ||
5232 ((uColor == BLACK) &&
5233 ((pos->cNonPawns[WHITE][0] >> 4) >= (c >> 4)))) {
5235 // The enemy king is ahead of the passer
5237 i += FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
5242 // The enemy king is behind the passer
5244 i += 10 + DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
5246 i *= PASSER_MATERIAL_UP_SCALER[pos->uArmyScaler[FLIP(uColor)]];
5251 pos->iScore[uColor],
5253 "passer distance to kings");
5256 // If a side is a piece down then the other side's passers
5257 // are even more dangerous.
5259 if (pos->uNonPawnCount[uColor][0] >
5260 pos->uNonPawnCount[FLIP(uColor)][0])
5262 i = (PASSER_BY_RANK[uColor][RANK(c)] / 2);
5266 pos->iScore[uColor],
5268 "passer and piece up");
5272 // TODO: For connected passers vs KR, consult the oracle
5281 u = pos->uArmyScaler[BLACK];
5286 uNumPassers[WHITE] * PASSER_BONUS_AS_MATERIAL_COMES_OFF[u],
5287 "passer value material");
5288 ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
5289 u = pos->uArmyScaler[WHITE];
5294 uNumPassers[BLACK] * PASSER_BONUS_AS_MATERIAL_COMES_OFF[u],
5295 "passer value material");
5296 ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
5301 _EvalBadTrades(IN OUT POSITION *pos)
5304 Routine description:
5316 ULONG uAhead, uBehind;
5322 ASSERT(pos->uNonPawnMaterial[WHITE] != pos->uNonPawnMaterial[BLACK]);
5323 uAhead = (pos->uNonPawnMaterial[WHITE] > pos->uNonPawnMaterial[BLACK]);
5324 uBehind = FLIP(uAhead);
5326 if (pos->uNonPawnMaterial[WHITE] > pos->uNonPawnMaterial[BLACK])
5328 ASSERT(uAhead == WHITE);
5329 ASSERT(uBehind == BLACK);
5333 ASSERT(pos->uNonPawnMaterial[BLACK] > pos->uNonPawnMaterial[WHITE]);
5334 ASSERT(uAhead == BLACK);
5335 ASSERT(uBehind == WHITE);
5338 uMagnitude = ((pos->uNonPawnMaterial[uAhead] +
5339 pos->uNonPawnCount[uAhead][0] * 128) -
5340 (pos->uNonPawnMaterial[uBehind] +
5341 pos->uNonPawnCount[uBehind][0] * 128));
5343 uMagnitude -= (uMagnitude != 0);
5344 ASSERT(!(uMagnitude & 0x80000000));
5345 uMagnitude = MINU(2, uMagnitude);
5346 ASSERT(uMagnitude <= 2);
5349 // Encourage the side that is ahead in piece material to continue
5350 // trading pieces and not to trade pawns. This also has the
5351 // effect of making the side that is behind in material want to
5352 // trade pawns and not pieces. This also gives the side that is
5353 // ahead a bit of a "bad trade" bonus. Note that the bonus is not
5354 // given if the side "ahead" has no pawns; this is so that the
5355 // engine will not like positions like KNB vs KRP - the side with
5356 // the pawn has the winning chances.
5361 pos->iScore[uAhead],
5362 ((pos->uPawnCount[uAhead] != 0) *
5363 TRADE_PIECES[uMagnitude][pos->uNonPawnCount[uBehind][0]]),
5365 ASSERT(TRADE_PIECES[uMagnitude][pos->uNonPawnCount[uBehind][0]] > 0);
5369 pos->iScore[uAhead],
5370 DONT_TRADE_PAWNS[uMagnitude][pos->uPawnCount[uAhead]],
5371 "don't trade pawns");
5375 _EvalLookForDanger(IN OUT SEARCHER_THREAD_CONTEXT *ctx)
5378 Routine description:
5380 This routine looks for squares on the board where the side to move
5381 has a piece that is en prise. So far in eval we will have tagged
5382 pieces in situations where they are attacked by lesser-valued
5383 enemy pieces as "in danger". However, because of the order in
5384 which the attack table was generated, we will have missed
5385 situations where a piece is undefended (or underdefended) and
5386 attacked by an enemy piece that is the same (or greater) value.
5388 Note: This routine only considers side to move.
5390 Also Note: this routine does not find pawns that are en prise, only
5395 SEARCHER_THREAD_CONTEXT *ctx
5405 POSITION *pos = &ctx->sPosition;
5406 ULONG uSide = pos->uToMove;
5412 u < pos->uNonPawnCount[uSide][0];
5415 c = pos->cNonPawns[uSide][u];
5417 ASSERT(IS_ON_BOARD(c));
5418 p = pos->rgSquare[c].pPiece;
5420 ASSERT(GET_COLOR(p) == uSide);
5421 ASSERT(!IS_PAWN(p));
5423 if (_WhoControlsSquareFast(pos, c) == FLIP(uSide))
5425 StoreEnprisePiece(pos, c);
5432 _EvalTrappedPieces(IN OUT SEARCHER_THREAD_CONTEXT *ctx)
5435 Routine description:
5439 SEARCHER_THREAD_CONTEXT *ctx
5449 POSITION *pos = &ctx->sPosition;
5454 FOREACH_COLOR(uColor)
5456 c = pos->cTrapped[uColor];
5459 if (_WhoControlsSquareFast(pos, c) == FLIP(uColor))
5462 p = pos->rgSquare[c].pPiece;
5464 ASSERT(!IS_PAWN(p));
5465 ASSERT(GET_COLOR(p) == uColor);
5467 if (OPPOSITE_COLORS(uColor, pos->uToMove))
5469 StoreEnprisePiece(pos, c);
5473 StoreTrappedPiece(pos, c);
5482 _EvalBishopPairs(IN POSITION *pos)
5485 Routine description:
5487 Give a bonus to sides that have a viable bishop pair based; scale
5488 the bonus by the number of pawns remaining on the board.
5492 IN POSITION *pos - position
5500 ULONG uPawnSum = pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK];
5502 ULONG uBishopCount = pos->uNonPawnCount[BLACK][BISHOP];
5503 ULONG uWhiteSqBishopCount = pos->uWhiteSqBishopCount[BLACK];
5504 ASSERT(uPawnSum <= 16);
5505 ASSERT(uBishopCount <= 10);
5506 ASSERT(uWhiteSqBishopCount <= 10);
5507 fPair = ((uBishopCount > 1) &
5508 (uWhiteSqBishopCount != 0) &
5509 (uWhiteSqBishopCount != uBishopCount));
5514 BISHOP_PAIR[fPair][uPawnSum],
5516 uBishopCount = pos->uNonPawnCount[WHITE][BISHOP];
5517 uWhiteSqBishopCount = pos->uWhiteSqBishopCount[WHITE];
5518 ASSERT(uBishopCount <= 10);
5519 ASSERT(uWhiteSqBishopCount <= 10);
5520 fPair = ((uBishopCount > 1) &
5521 (uWhiteSqBishopCount != 0) &
5522 (uWhiteSqBishopCount != uBishopCount));
5527 BISHOP_PAIR[fPair][uPawnSum],
5534 Eval(IN SEARCHER_THREAD_CONTEXT *ctx,
5539 Routine description:
5543 SEARCHER_THREAD_CONTEXT *ctx,
5553 static const PEVAL_HELPER JumpTable[] =
5555 _InvalidEvaluator, // EMPTY_SQUARE (0)
5556 _InvalidEvaluator, // INVALID_PIECE (1)
5557 _InvalidEvaluator, // BLACK_PAWN (2)
5558 _InvalidEvaluator, // WHITE_PAWN (3)
5559 _EvalKnight, // BLACK_KNIGHT (4)
5560 _EvalKnight, // WHITE_KNIGHT (5)
5561 _EvalBishop, // BLACK_BISHOP (6)
5562 _EvalBishop, // WHITE_BISHOP (7)
5563 _InvalidEvaluator, // BLACK_ROOK (8)
5564 _InvalidEvaluator, // WHITE_ROOK (9)
5565 _InvalidEvaluator, // BLACK_QUEEN (10)
5566 _InvalidEvaluator, // WHITE_QUEEN (11)
5567 _InvalidEvaluator, // BLACK_KING (12)
5568 _InvalidEvaluator // WHITE_KING (13)
5571 COOR cDefer[2][2][10];
5572 POSITION *pos = &(ctx->sPosition);
5573 SCORE iScoreForSideToMove;
5574 SCORE iAlphaMargin, iBetaMargin;
5575 PAWN_HASH_ENTRY *pHash;
5583 UINT64 uTimer = SystemReadTimeStampCounter();
5585 ASSERT(IS_VALID_SCORE(iAlpha));
5586 ASSERT(IS_VALID_SCORE(iBeta));
5587 ASSERT(iAlpha < iBeta);
5588 ASSERT((pos->iMaterialBalance[WHITE] * -1) ==
5589 pos->iMaterialBalance[BLACK]);
5590 // ASSERT(!InCheck(pos, pos->uToMove));
5592 pos->uMinMobility[BLACK] = pos->uMinMobility[WHITE] = 100;
5593 pos->cTrapped[BLACK] = pos->cTrapped[WHITE] = ILLEGAL_COOR;
5597 // Check the eval hash
5599 iScoreForSideToMove = ProbeEvalHash(ctx);
5600 if (iScoreForSideToMove != INVALID_SCORE)
5602 INC(ctx->sCounters.tree.u64EvalHashHits);
5607 pos->iScore[BLACK] =
5608 (pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]);
5609 pos->iScore[WHITE] =
5610 (pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]);
5613 Trace("Material:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5617 // Pawn eval. Note: if fDeferred comes back as TRUE then we have
5618 // neither cleared nor initialized the attack tables. This is
5619 // because we hope that we can get a lazy eval cutoff here and
5620 // save some time. BEFORE ANY CODE BELOW TOUCHES THE ATTACK
5621 // TABLES IT NEEDS TO CLEAR/POPULATE THEM THOUGH!!!
5623 pHash = _EvalPawns(ctx, &fDeferred);
5624 ASSERT(NULL != pHash);
5625 ASSERT(IS_VALID_FLAG(fDeferred));
5626 pos->iScore[WHITE] += pHash->iScore[WHITE];
5627 pos->iScore[BLACK] += pHash->iScore[BLACK];
5628 ASSERT(IS_VALID_SCORE(pos->iScore[WHITE] - pos->iScore[BLACK]));
5630 Trace("After pawns:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5634 // Look for won passers races. Note: This code cannot trust the
5635 // state of the attack tables yet!
5637 if ((pos->uNonPawnCount[WHITE][0] == 1) ||
5638 (pos->uNonPawnCount[BLACK][0] == 1))
5640 (void)EvalPasserRaces(pos, pHash);
5642 Trace("After passer races:\n%d\t\t%d\n", pos->iScore[WHITE],
5643 pos->iScore[BLACK]);
5648 // Bad trade code. Right. Note: this code cannot trust the state
5649 // of the attack tables...
5651 if (pos->uNonPawnMaterial[WHITE] != pos->uNonPawnMaterial[BLACK])
5653 _EvalBadTrades(pos);
5655 Trace("After bad trades:\n%d\t\t%d\n", pos->iScore[WHITE],
5656 pos->iScore[BLACK]);
5661 // Bishop pairs. Again... Note: this code cannot trust the state
5662 // of the attack tables.
5664 _EvalBishopPairs(pos);
5666 Trace("After bishop pair bonus:\n%d\t\t%d\n", pos->iScore[WHITE],
5667 pos->iScore[BLACK]);
5672 // Compute an estimate of the score for the side to move based on the
5673 // eval terms we have already considered:
5675 // 1. Material balance
5676 // 2. Pawn structure bonuses/penalties (incl passers/candidates)
5677 // 3. Passer races are detected already
5678 // 4. "Bad trade" code has already run
5679 // 5. We've already detected unwinnable endgames
5682 iScoreForSideToMove = (pos->iScore[pos->uToMove] -
5683 pos->iScore[FLIP(pos->uToMove)]);
5684 ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
5687 // Eval has not considered several potentially large terms:
5689 // 1. Piece positional components (such as mobility, trapped)
5690 // 2. King safety penalties
5691 // 3. Other miscellaneous bonuses/penalties
5693 // We build two "margins" to account for these components of the
5696 iAlphaMargin = iBetaMargin = (50 + (SCORE)ctx->uPositional);
5699 // If (score + alpha_margin) is already > alpha -OR-
5700 // (score - beta_margin) is already < beta
5702 // ...then we can stop thinking about lazy eval; the rest of the
5703 // computation only increases the margin so we know LE will fail
5704 // and can save some work here.
5706 if ((iScoreForSideToMove + iAlphaMargin < iAlpha) ||
5707 (iScoreForSideToMove - iBetaMargin > iBeta))
5710 // Ok, we can't say for sure that we won't take a lazy exit
5711 // yet. So do the expensive part of lazy eval estimation and
5712 // widen the margin further for king safety issues and passed
5715 _QuicklyEstimateKingSafetyTerm(pos, &iAlphaMargin, &iBetaMargin);
5716 _QuicklyEstimatePasserBonuses(pos, pHash, &iAlphaMargin, &iBetaMargin);
5718 if ((iScoreForSideToMove + iAlphaMargin <= iAlpha) ||
5719 (iScoreForSideToMove - iBetaMargin >= iBeta))
5721 ctx->uPositional = MINU(200, ctx->uPositional);
5722 INC(ctx->sCounters.tree.u64LazyEvals);
5729 // If we have to clear/populate the attack table, do it now that
5730 // we know we aren't taking a lazy exit.
5732 if (TRUE == fDeferred)
5734 _PopulatePawnAttackBits(pos);
5738 // Pre-compute some common terms used in per-piece evals:
5740 // This is a scaler based on the size of the army for each side.
5742 pos->uArmyScaler[BLACK] = pos->uNonPawnMaterial[BLACK] - VALUE_KING;
5743 pos->uArmyScaler[WHITE] = pos->uNonPawnMaterial[WHITE] - VALUE_KING;
5744 pos->uArmyScaler[BLACK] /= VALUE_PAWN;
5745 pos->uArmyScaler[WHITE] /= VALUE_PAWN;
5746 ASSERT(!(pos->uArmyScaler[BLACK] & 0x80000000));
5747 ASSERT(!(pos->uArmyScaler[WHITE] & 0x80000000));
5748 pos->uArmyScaler[BLACK] = MINU(31, pos->uArmyScaler[BLACK]);
5749 pos->uArmyScaler[WHITE] = MINU(31, pos->uArmyScaler[WHITE]);
5750 ASSERT(pos->uArmyScaler[BLACK] >= 0);
5751 ASSERT(pos->uArmyScaler[BLACK] <= 31);
5752 ASSERT(pos->uArmyScaler[WHITE] >= 0);
5753 ASSERT(pos->uArmyScaler[WHITE] <= 31);
5754 pos->iReducedMaterialDownScaler[BLACK] =
5755 pos->iReducedMaterialDownScaler[WHITE] = 0;
5758 // This is a "position is closed|open" number.
5760 pos->uClosedScaler = (pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK]) -
5761 (pHash->uNumUnmovedPawns[WHITE] + pHash->uNumUnmovedPawns[BLACK]) +
5762 (pHash->uNumRammedPawns);
5763 ASSERT(pos->uClosedScaler >= 0);
5764 ASSERT(pos->uClosedScaler <= 32);
5767 // Evaluate individual pieces.
5769 pos->uMinorsAtHome[BLACK] = pos->uMinorsAtHome[WHITE] = 0;
5770 uDefer[BLACK][0] = uDefer[BLACK][1] =
5771 uDefer[WHITE][0] = uDefer[WHITE][1] = 0;
5772 uColor = pos->uToMove;
5773 for (u = 1; // skips the king
5774 u < pos->uNonPawnCount[uColor][0];
5777 c = pos->cNonPawns[uColor][u];
5778 ASSERT(IS_ON_BOARD(c));
5779 p = pos->rgSquare[c].pPiece;
5780 ASSERT(IS_VALID_PIECE(p));
5781 ASSERT(GET_COLOR(p) == uColor);
5782 ASSERT(!IS_PAWN(p) && !IS_KING(p));
5786 ASSERT(IS_BISHOP(p) || IS_KNIGHT(p));
5789 // Note: The side on move's pieces of value X are
5790 // evaluated and have their mobility counted and added to
5791 // the attack table before the other side's pieces. Also,
5792 // we do not care if JumpTable tells us this piece is in
5793 // danger b/c we will find out later on in
5794 // EvalLookForDanger anyway.
5796 ASSERT(JumpTable[p]);
5797 (void)(JumpTable[p])(pos, c, pHash);
5799 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5800 pos->iScore[WHITE], pos->iScore[BLACK]);
5805 ASSERT(IS_ROOK(p) || IS_QUEEN(p));
5806 cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
5810 uColor = FLIP(uColor);
5811 ASSERT(uColor != pos->uToMove);
5813 u < pos->uNonPawnCount[uColor][0];
5816 c = pos->cNonPawns[uColor][u];
5817 ASSERT(IS_ON_BOARD(c));
5818 p = pos->rgSquare[c].pPiece;
5819 ASSERT(IS_VALID_PIECE(p));
5820 ASSERT(GET_COLOR(p) == uColor);
5821 ASSERT(!IS_PAWN(p) && !IS_KING(p));
5825 // This time we are evaluating a piece from the side not
5826 // on move. We will not go back later and look at this
5827 // piece again so if JumpTable tells us it's in danger
5828 // then record it. The drawback, of course, is that the
5829 // JumpTable routines only detect danger if a piece is
5830 // attacked by an enemy of lesser value!
5832 ASSERT(JumpTable[p]);
5833 (void)(JumpTable[p])(pos, c, pHash);
5835 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5836 pos->iScore[WHITE], pos->iScore[BLACK]);
5841 ASSERT(IS_ROOK(p) || IS_QUEEN(p));
5842 cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
5847 // Evaluate any rook(s) for side on move then for side not on move.
5849 uColor = FLIP(uColor);
5851 u < uDefer[uColor][0];
5854 c = cDefer[uColor][0][u];
5855 ASSERT(IS_ON_BOARD(c));
5856 ASSERT(IS_ROOK(pos->rgSquare[c].pPiece));
5857 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == uColor);
5858 _EvalRook(pos, c, pHash);
5860 p = BLACK_ROOK | uColor;
5861 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5862 pos->iScore[WHITE], pos->iScore[BLACK]);
5866 uColor = FLIP(uColor);
5868 u < uDefer[uColor][0];
5871 c = cDefer[uColor][0][u];
5872 ASSERT(IS_ON_BOARD(c));
5873 ASSERT(IS_ROOK(pos->rgSquare[c].pPiece));
5874 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == uColor);
5875 _EvalRook(pos, c, pHash);
5877 p = BLACK_ROOK | uColor;
5878 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5879 pos->iScore[WHITE], pos->iScore[BLACK]);
5884 // Evaluate any queen(s) for side on move then for side not on move.
5886 uColor = FLIP(uColor);
5888 u < uDefer[uColor][1];
5891 c = cDefer[uColor][1][u];
5892 ASSERT(IS_ON_BOARD(c));
5893 ASSERT(IS_QUEEN(pos->rgSquare[c].pPiece));
5894 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == uColor);
5895 _EvalQueen(pos, c, pHash);
5897 p = BLACK_ROOK | uColor;
5898 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5899 pos->iScore[WHITE], pos->iScore[BLACK]);
5903 uColor = FLIP(uColor);
5905 u < uDefer[uColor][1];
5908 c = cDefer[uColor][1][u];
5909 ASSERT(IS_ON_BOARD(c));
5910 ASSERT(IS_QUEEN(pos->rgSquare[c].pPiece));
5911 ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == uColor);
5912 _EvalQueen(pos, c, pHash);
5914 p = BLACK_ROOK | uColor;
5915 Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5916 pos->iScore[WHITE], pos->iScore[BLACK]);
5921 // Evaluate the two kings last.
5923 c = pos->cNonPawns[BLACK][0];
5925 ASSERT(IS_ON_BOARD(c));
5926 p = pos->rgSquare[c].pPiece;
5927 ASSERT(IS_VALID_PIECE(p));
5928 ASSERT(GET_COLOR(p) == BLACK);
5930 ASSERT(JumpTable[p]);
5932 _EvalKing(pos, c, pHash);
5933 ctx->sPlyInfo[ctx->uPly].iKingScore[BLACK] = pos->iTempScore;
5935 Trace("After *k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5938 c = pos->cNonPawns[WHITE][0];
5940 ASSERT(IS_ON_BOARD(c));
5941 p = pos->rgSquare[c].pPiece;
5942 ASSERT(IS_VALID_PIECE(p));
5943 ASSERT(GET_COLOR(p) == WHITE);
5945 ASSERT(JumpTable[p]);
5947 _EvalKing(pos, c, pHash);
5948 ctx->sPlyInfo[ctx->uPly].iKingScore[WHITE] = pos->iTempScore;
5950 Trace("After .k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5954 // Now that we have the whole attack table generated, think about
5955 // passed pawns identified by the pawn eval routine again. Also
5956 // see if the side not on move has a trapped piece.
5958 bb = (pHash->bbPasserLocations[WHITE] | pHash->bbPasserLocations[BLACK]);
5961 _EvalPassers(pos, pHash);
5963 Trace("After passers:\n%d\t\t%d\n", pos->iScore[WHITE],
5964 pos->iScore[BLACK]);
5969 // Make one more pass over the piece list for the side on move now
5970 // that the full attack table is computed to detect
5971 // under/unprotected pieces en prise to more valuable enemy pieces
5972 // which we missed when building the attack table incrementally.
5974 ctx->sPlyInfo[ctx->uPly].uMinMobility[BLACK] = pos->uMinMobility[BLACK];
5975 ctx->sPlyInfo[ctx->uPly].uMinMobility[WHITE] = pos->uMinMobility[WHITE];
5976 _EvalLookForDanger(ctx);
5977 _EvalTrappedPieces(ctx);
5980 // B over N in the endgame with 2 pawn wings.
5982 if ((pos->uNonPawnCount[WHITE][0] <= 2) &&
5983 (pos->uNonPawnCount[BLACK][0] <= 2))
5985 if ((pos->uNonPawnCount[WHITE][BISHOP] > 0) &&
5986 (pos->uNonPawnCount[BLACK][BISHOP] > 0))
5988 if ((pos->uNonPawnCount[BLACK][0] == 2) &&
5989 (pos->uNonPawnCount[WHITE][0] == 2))
5991 ASSERT(pos->uNonPawnCount[BLACK][BISHOP] == 1);
5992 ASSERT(pos->uNonPawnCount[WHITE][BISHOP] == 1);
5993 if (pos->uWhiteSqBishopCount[BLACK] +
5994 pos->uWhiteSqBishopCount[WHITE] == 1)
5996 pos->iScore[WHITE] /= 2;
5997 pos->iScore[BLACK] /= 2;
6004 // At least one side has no bishop. Look for positions
6005 // with two pawn wings where having a bishop is an
6008 bb = (pHash->bbPawnLocations[WHITE] |
6009 pHash->bbPawnLocations[BLACK]);
6010 ASSERT((BBFILE[A] | BBFILE[B] | BBFILE[C]) ==
6011 0x0707070707070707ULL);
6012 ASSERT((BBFILE[F] | BBFILE[G] | BBFILE[H]) ==
6013 0xe0e0e0e0e0e0e0e0ULL);
6014 if ((bb & 0x0707070707070707ULL) &&
6015 (bb & 0xe0e0e0e0e0e0e0e0ULL))
6017 if ((pos->uNonPawnCount[BLACK][BISHOP] == 0) &&
6018 (pos->uNonPawnCount[WHITE][BISHOP] > 0))
6024 BISHOP_OVER_KNIGHT_IN_ENDGAME *
6025 pos->uNonPawnCount[WHITE][BISHOP],
6026 "endgame w/ 2 pawn flanks");
6028 else if ((pos->uNonPawnCount[BLACK][BISHOP] > 0) &&
6029 (pos->uNonPawnCount[WHITE][BISHOP] == 0))
6035 BISHOP_OVER_KNIGHT_IN_ENDGAME *
6036 pos->uNonPawnCount[BLACK][BISHOP],
6037 "endgame w/ 2 pawn flanks");
6042 Trace("After BOOC / BvsN:\n%d\t\t%d\n",
6043 pos->iScore[WHITE], pos->iScore[BLACK]);
6048 // Roll in the reduced material down scaler terms.
6050 ASSERT(pos->iReducedMaterialDownScaler[BLACK] > -200);
6051 ASSERT(pos->iReducedMaterialDownScaler[BLACK] < +200);
6052 iAlphaMargin = (pos->iReducedMaterialDownScaler[BLACK] *
6053 (SCORE)REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[BLACK]]) / 8;
6054 pos->iScore[BLACK] += iAlphaMargin;
6055 ASSERT(pos->iReducedMaterialDownScaler[WHITE] > -200);
6056 ASSERT(pos->iReducedMaterialDownScaler[WHITE] < +200);
6057 iAlphaMargin = (pos->iReducedMaterialDownScaler[WHITE] *
6058 (SCORE)REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[WHITE]]) / 8;
6059 pos->iScore[WHITE] += iAlphaMargin;
6064 iScoreForSideToMove = (pos->iScore[pos->uToMove] -
6065 pos->iScore[FLIP(pos->uToMove)]);
6067 Trace("At the end:\n%d\t\t%d\n", pos->iScore[WHITE],
6068 pos->iScore[BLACK]);
6072 // TODO: detect and discourage blocked positions?
6076 // TODO: drive the score towards zero as we approach a 50 move w/o
6081 // Adjust dynamic positional component.
6083 iAlphaMargin = abs(pos->iMaterialBalance[pos->uToMove] - iScoreForSideToMove);
6084 if ((ULONG)iAlphaMargin > ctx->uPositional)
6086 ctx->uPositional = (ULONG)iAlphaMargin;
6090 ctx->uPositional -= (ctx->uPositional - (ULONG)iAlphaMargin) / 4;
6091 ctx->uPositional = MAXU(ctx->uPositional, VALUE_PAWN);
6093 g_Options.iLastEvalScore = iScoreForSideToMove;
6096 ctx->sCounters.tree.u64CyclesInEval += (SystemReadTimeStampCounter() -
6099 INC(ctx->sCounters.tree.u64FullEvals);
6103 // Store in eval hash.
6105 StoreEvalHash(ctx, iScoreForSideToMove);
6109 ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
6110 ASSERT((iScoreForSideToMove > -NMATE) &&
6111 (iScoreForSideToMove < +NMATE));
6112 ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[BLACK]) < 700);
6113 ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[WHITE]) < 700);
6114 ASSERT(ctx->sPlyInfo[ctx->uPly].uMinMobility[BLACK] <= 100);
6115 ASSERT(ctx->sPlyInfo[ctx->uPly].uMinMobility[WHITE] <= 100);
6116 ASSERT((ctx->uPositional < 2500) && (ctx->uPositional >= VALUE_PAWN));
6117 return(iScoreForSideToMove);