Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / eval.c
1 /**
2 Copyright (c) Scott Gasch
3
4 Module Name:
5
6     eval.c
7
8 Abstract:
9
10     Position evaluation routines.
11
12 Author:
13
14     Scott Gasch ([email protected]) 14 Jun 2004
15
16 Revision History:
17
18     $Id: eval.c 357 2008-07-03 16:18:11Z scott $
19
20 **/              
21
22 #include "chess.h"
23
24 typedef void (*PEVAL_HELPER)(POSITION *, COOR, PAWN_HASH_ENTRY *);
25 typedef FLAG (FASTCALL *PMOBILITY_HELPER)(POSITION *, COOR, ULONG *, ULONG *);
26
27 //
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.
31 //
32 const int g_iAhead[2] = { +1, -1 };
33 const int g_iBehind[2] = { -1, +1 };
34
35 //
36 // General eval terms
37 // ---------------------------------------------------------------------------
38 //
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},
44 };
45
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
51 };
52
53 static ULONG REDUCED_MATERIAL_DOWN_SCALER[32] = 
54
55 //  none    na      na      m       na      R       2m      na
56     0,      0,      0,      0,      0,      0,      0,      0,
57
58 //  Rm      3m/Q    2R      R2m     4m/Qm   2Rm     R3m/QR  Q2m
59     0,      1,      1,      1,      1,      1,      2,      3,
60
61 //  2R2m    R4m/QRm Q3m     2R3m/   QR2m    Q4m     2R4m/   QR3m
62 //                          Q2R                     Q2Rm    
63     4,      5,      6,      6,      7,      7,      7,      7,
64
65 //  na      Q2R2m   QR4m    na      Q2R3m   na      na      full
66     8,      8,      8,      8,      8,      8,      8,      8,
67 };
68
69 static ULONG REDUCED_MATERIAL_UP_SCALER[32] = 
70
71 //  none    na      na      m       na      R       2m      na
72     8,      8,      8,      8,      8,      8,      8,      8,
73
74 //  Rm      3m/Q    2R      R2m     4m/Qm   2Rm     R3m/QR  Q2m
75     8,      7,      7,      7,      7,      6,      6,      5,
76
77 //  2R2m    R4m/QRm Q3m     2R3m/   QR2m    Q4m     2R4m/   QR3m
78 //                          Q2R                     Q2Rm    
79     4,      3,      3,      3,      2,      2,      2,      1,
80
81 //  na      Q2R2m   QR4m    na      Q2R3m   na      na      full
82     1,      1,      0,      0,      0,      0,      0,      0,
83 };
84
85 static ULONG PASSER_MATERIAL_UP_SCALER[32] = 
86
87 //  none    na      na      m       na      R       2m      na
88     8,      8,      8,      8,      8,      8,      7,      7,
89
90 //  Rm      3m/Q    2R      R2m     4m/Qm   2Rm     R3m/QR  Q2m
91     7,      6,      7,      5,      4,      5,      4,      3,
92
93 //  2R2m    R4m/QRm Q3m     2R3m/   QR2m    Q4m     2R4m/   QR3m
94 //                          Q2R                     Q2Rm    
95     2,      2,      1,      1,      0,      0,      0,      0,
96
97 //  na      Q2R2m   QR4m    na      Q2R3m   na      na      full
98     0,      0,      0,      0,      0,      0,      0,      0,
99 };
100
101 COOR QUEENING_RANK[2] = { 1, 8 };
102 COOR JUMPING_RANK[2] = { 7, 2 };
103
104 //
105 // Pawn eval terms
106 // ---------------------------------------------------------------------------
107 //
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
118 // file."
119 //                                                --Larry Kaufman, IM
120 //                                  "Evaluation of Material Imbalance"
121 //
122 static SCORE PAWN_CENTRALITY_BONUS[128] = 
123 {
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
133 };
134
135 static SCORE BACKWARD_SHIELDED_BY_LOCATION[128] = 
136 {
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
146 };
147
148 static SCORE BACKWARD_EXPOSED_BY_LOCATION[128] = 
149 {
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
159 };
160
161 //
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"
179 // 
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
185     },
186     {//                                                   : 1 rook
187       +0,  -23,  -47,  -76,  -108, -144, -184, -200, -216
188     },
189     {//                                                   : 2 rooks or 1 queen
190       +0,  -13,  -23,  -34,  -46,   -64,  -86, -111, -138
191     },
192     {//                                                   : all majors alive
193       +0,   -7,  -13,  -25,  -39,   -55,  -73,  -95, -121
194     },
195 };
196
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
200 };
201
202 static SCORE ISOLATED_PAWN_BY_PAWNFILE[9] =
203 {
204     0, -7, -8, -9, -10, -10, -9, -8, -7
205 };
206
207 static SCORE ISOLATED_EXPOSED_PAWN = -5;
208
209 static SCORE ISOLATED_DOUBLED_PAWN = -11;
210
211 //
212 // Note: -25% to -33% if the enemy occupies or controls the next sq.
213 //
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
218 };
219
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
224 };
225
226 // Note: x2
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
231 };
232
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
237 };
238
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 
242 };
243
244 static SCORE PASSER_BONUS_AS_MATERIAL_COMES_OFF[32] = 
245
246 //  none    na      na      m       na      R       2m      na
247     +60,    -1,     -1,    +37,    -1,     +43,    +19,    -1,
248
249 //  Rm      3m/Q    2R      R2m     4m/Qm   2Rm     R3m/QR  Q2m
250     +14,    +9,    +20,    +4,     +3,     +3,      0,      0,
251
252 //  2R2m    R4m/QRm Q3m     2R3m/   QR2m    Q4m     2R4m/   QR3m
253 //                          Q2R                     Q2Rm    
254     0,      0,      0,      0,      0,      0,      0,      0,
255
256 //  na      Q2R2m   QR4m    na      Q2R3m   na      na      full
257     0,      0,      0,      0,      0,      0,      0,      0,
258 };
259
260 SCORE RACER_WINS_RACE = +800;
261
262 static SCORE UNDEVELOPED_MINORS_IN_OPENING[5] = 
263 {//  0    1    2    3    4
264      0,  -6, -10, -16, -22
265 };
266
267 //
268 // Bishop eval terms
269 // ---------------------------------------------------------------------------
270 //
271 static SCORE BISHOP_OVER_KNIGHT_IN_ENDGAME = +33;
272
273 //
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...
280 // 
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...
285 // 
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] =
293 {
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 }
296 };
297
298 static SCORE STATIONARY_PAWN_ON_BISHOP_COLOR[128] = 
299 {
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
309 };
310
311 static SCORE TRANSIENT_PAWN_ON_BISHOP_COLOR[128] = 
312 {
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
322 };
323
324 // 
325 // A bishop can move to between 0..13 squares.
326 // 
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
330 };//                    ^   |  
331
332 static SCORE BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
333 {//  0   1   2   3   4    5    6    7
334    -10, -4, +1, +3, +4,  +5,  +5,  +5
335 };
336
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
340 };
341
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
347 };
348
349 //
350 // Knight eval terms
351 // ---------------------------------------------------------------------------
352 //
353 static SCORE KNIGHT_CENTRALITY_BONUS[128] = 
354 {
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
364 };
365
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 
369 };
370
371
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
375 };
376
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
381 };
382
383 //
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
390 // 
391 // Total: 16 mobility max
392 // 
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
396 };//               ^   |
397
398 static SCORE KNIGHT_WITH_N_PAWNS_SUPPORTING[3] = 
399 {
400     +0, +4, +8
401 };
402
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
408 };
409
410 //
411 // Rook eval terms
412 // ---------------------------------------------------------------------------
413 //
414 static SCORE ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING[8] =
415 {//  0    1    2    3    4    5    6    7
416    +24, +22, +17, +14, +13, +13, +12, +12
417 };
418
419 static SCORE ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[8] = 
420 {//  0    1    2    3    4    5    6    7
421    +12, +11,  +9,  +9,  +8,  +8,  +8,  +7
422 };
423
424 static SCORE ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING[8] =
425 {//  0    1    2    3    4    5    6    7
426    +13, +12, +11, +11,  +9,  +9,  +9,  +8
427 };
428
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
433 };
434
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
439 };
440
441 static SCORE KING_TRAPPING_ROOK = -40;
442
443 static SCORE ROOK_TRAPPING_EKING = +22;
444
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
450 };
451
452 //
453 // Note: these are multiplied by two (one per rook). 
454 //
455 static SCORE ROOK_CONNECTED_VERT = +7;        // x2
456 static SCORE ROOK_CONNECTED_HORIZ = +4;       // x2
457
458 //
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
464 // 
465 // Total: 28 mobility max
466 // 
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
470 };//                          ^   |
471
472 static SCORE ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[8] =
473 {//  0    1   2   3   4    5    6    7
474    -15,  -6, +0, +4, +8,  +8,  +8,  +8
475 };
476
477 //
478 // Queen eval terms
479 // ---------------------------------------------------------------------------
480 //
481
482
483 //
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
489 // 
490 // Total: 54 mobility max
491 // 
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,
495 //                                            |
496
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
499 };
500
501 static SCORE QUEEN_OUT_EARLY[5] = 
502 {// 0    1    2    3    4 : num unmoved minors
503     0, -14, -22, -26, -33
504 };
505
506 //
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.
510 //
511 static SCORE QUEEN_KING_TROPISM[8] = 
512 {// 0    1    2    3    4    5    6    7
513     0, +34, +28, +22, +19, +17, +16, +15
514 };
515
516 static SCORE QUEEN_ATTACKS_SQ_NEXT_TO_KING = 8; // x #sq_attacked
517
518 //
519 // King eval terms
520 // ---------------------------------------------------------------------------
521 //
522 static ULONG KING_INITIAL_COUNTER_BY_LOCATION[2][128] = 
523 {
524     {
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
534     },
535     {
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
545     }
546 };
547
548 static SCORE KING_TO_CENTER[128] = 
549 {
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
559 };
560
561 //
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
564 // material.
565 //
566 #define DO_KING_SAFETY_THRESHOLD \
567     (VALUE_ROOK + VALUE_BISHOP + VALUE_KING + 1)
568
569 //
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.
572 //
573 #define KEEP_KING_AT_HOME_THRESHOLD \
574     (VALUE_ROOK + VALUE_ROOK + VALUE_BISHOP + VALUE_KING + 1)
575
576 static ULONG KING_COUNTER_BY_ATTACK_PATTERN[32] = 
577 {
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
584 };
585
586 static SCORE KING_SAFETY_BY_COUNTER[42] =
587 {
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,
591     -500,-500,-500
592 };
593
594 static SCORE KING_MISSING_ONE_CASTLE_OPTION = -23;
595 typedef struct _DNA_BASE_SIZE {
596     SCORE *pBase;
597     ULONG uCount;
598 } DNA_BASE_SIZE;
599
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)
660 };
661
662 ULONG 
663 DNABufferSizeBytes() 
664 {
665     ULONG u;
666     ULONG uSize = 0;
667     for (u = 0; u < ARRAY_LENGTH(g_EvalDNA); u++) {
668         uSize += 10 * g_EvalDNA[u].uCount;
669     }
670     return uSize + 1;
671 }
672
673
674 char *
675 ExportEvalDNA() 
676 {
677     ULONG uSize = DNABufferSizeBytes();
678     char *p = malloc(uSize);
679     ULONG u, v;
680     SCORE *q;
681     FLAG fFirst = TRUE;
682     
683     memset(p, 0, 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++) {
687             if (!fFirst) {
688                 sprintf(p, "%s,%d", p, *q);
689             } else {
690                 sprintf(p, "%s%d", p, *q);
691                 fFirst = FALSE;
692             }
693             q++;
694         }
695         strcat(p, "\n");
696         fFirst = TRUE;
697     }
698     return p; // caller must free
699 }
700
701 FLAG
702 WriteEvalDNA(char *szFilename)
703 {
704     FILE *p = NULL;
705     char *q = NULL;
706     FLAG fRet = FALSE;
707
708     if (SystemDoesFileExist(szFilename)) goto end;
709     p = fopen(szFilename, "a+b");
710     if (!p) goto end;
711     q = ExportEvalDNA();
712     if (!q) goto end;
713     fprintf(p, "%s", q);
714     fRet = TRUE;
715  end:
716     if (p) fclose(p);
717     if (q) free(q);
718     return fRet;
719 }
720
721 FLAG
722 ImportEvalDNA(char *p)
723 {
724     ULONG u, v;
725
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++;
732         }
733     }
734     return TRUE;
735 }
736
737 FLAG
738 ReadEvalDNA(char *szFilename) 
739 {
740     FILE *p = NULL;
741     ULONG uSize = DNABufferSizeBytes();
742     char *q = malloc(uSize);
743     FLAG fRet = FALSE;
744     static char line[1024];
745     char *c;
746
747     if (!q) goto end;
748     memset(q, 0, uSize);
749     p = fopen(szFilename, "rb");
750     if (!p) {
751         Trace("Failed to open file \"%s\"\n", szFilename);
752         goto end;
753     }
754     while(fgets(line, 1024, p) != NULL) {
755         c = strchr(line, '#');
756         if (c) *c = '\0';
757         c = line;
758         strcat(q, c);
759     }
760     fRet = ImportEvalDNA(q);
761  end:
762     if (q) free(q);
763     if (p) fclose(p);
764     return fRet;
765 }
766
767
768
769 //
770 // Misc stuff
771 // ---------------------------------------------------------------------------
772 //
773
774 //
775 // The three ranks "around" a rank (indexed by rank, used in eval.c)
776 //
777 BITBOARD BBADJACENT_RANKS[9] =
778 {
779     0,
780     BBRANK11 | BBRANK22,
781     BBRANK11 | BBRANK22 | BBRANK33,
782     BBRANK22 | BBRANK33 | BBRANK44,
783     BBRANK33 | BBRANK44 | BBRANK55,
784     BBRANK44 | BBRANK55 | BBRANK66,
785     BBRANK55 | BBRANK66 | BBRANK77,
786     BBRANK66 | BBRANK77 | BBRANK88,
787     BBRANK77 | BBRANK88
788 };
789
790
791 //
792 // The files "around" one, indexed by file (used in eval.c)
793 //
794 BITBOARD BBADJACENT_FILES[8] =
795 {
796     // A = 0
797     BBFILEB,
798     
799     // B = 1
800     BBFILEA | BBFILEC,
801     
802     // C = 2
803     BBFILEB | BBFILED,
804     
805     // D = 3
806     BBFILEC | BBFILEE,
807     
808     // E = 4
809     BBFILED | BBFILEF,
810     
811     // F = 5
812     BBFILEE | BBFILEG,
813     
814     // G = 6
815     BBFILEF | BBFILEH,
816     
817     // H = 7
818     BBFILEG
819 };
820
821 //
822 // The ranks preceeding one, indexed by rank/color of pawn (used in 
823 // eval.c)
824 //
825 BITBOARD BBPRECEEDING_RANKS[8][2] =
826 {
827     //     BLACK                          WHITE
828     //     -----                          -----
829     { // 0 == RANK8
830         BBRANK72,                         0
831     },
832     { // 1 == RANK7
833         BBRANK62,                         0
834     },
835     { // 2 == RANK6
836         BBRANK52,                         BBRANK77
837     },
838     { // 3 == RANK5
839         BBRANK42,                         BBRANK67
840     },
841     { // 4 == RANK4
842         BBRANK32,                         BBRANK57
843     },
844     { // 5 == RANK3
845         BBRANK22,                         BBRANK47
846     },
847     { // 6 == RANK2
848         0,                                BBRANK37
849     },
850     { // 7 == RANK1
851         0,                                BBRANK27
852     }
853 };
854
855
856 static FLAG 
857 _IsSquareSafeFromEnemyPawn(IN POSITION *pos, 
858                            IN COOR c, 
859                            IN BITBOARD bb)
860 /**
861
862 Routine description:
863
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
866     it away.
867
868 Parameters:
869
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
873
874 Return value:
875
876     FLAG : TRUE if the piece is safe/outposted, FALSE otherwise
877
878 **/
879 {
880     ULONG uColor = GET_COLOR(pos->rgSquare[c].pPiece);
881     ULONG uFile, uRank;
882 #ifdef DEBUG
883     COOR cSquare;
884     PIECE p = pos->rgSquare[c].pPiece;
885     BITBOARD dbb = bb;
886
887     ASSERT(IS_ON_BOARD(c));
888     ASSERT(p && (IS_BISHOP(p) || IS_KNIGHT(p) || IS_PAWN(p)));
889     ASSERT(IS_VALID_COLOR(uColor));
890 #endif
891     
892     uFile = FILE(c);
893     ASSERT(uFile < 8);
894     bb &= BBADJACENT_FILES[uFile];
895     
896     ASSERT(((c & 0x70) >> 4) == (c >> 4));
897     uRank = c >> 4;
898     ASSERT(uRank < 8);
899     bb &= BBPRECEEDING_RANKS[uRank][uColor];
900     
901 #ifdef DEBUG
902     if (bb != 0)
903     {
904         while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&dbb)))
905         {
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)))
910             {
911                 switch(uColor)
912                 {
913                     case WHITE:
914                         if (RANK(cSquare) > RANK(c))
915                         {
916                             return(FALSE);
917                         }
918                         break;
919                     case BLACK:
920                         if (RANK(cSquare) < RANK(c))
921                         {
922                             return(FALSE);
923                         }
924                         break;
925                 }
926             }
927         }
928         ASSERT(FALSE);
929     }
930     else
931     {
932         ASSERT(bb == 0);
933         while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&dbb)))
934         {
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)))
939             {
940                 switch(uColor)
941                 {
942                     case WHITE:
943                         if (RANK(cSquare) > RANK(c))
944                         {
945                             ASSERT(FALSE);
946                         }
947                         break;
948                     case BLACK:
949                         if (RANK(cSquare) < RANK(c))
950                         {
951                             ASSERT(FALSE);
952                         }
953                         break;
954                 }
955             }
956         }
957     }
958 #endif
959     return(bb == 0);
960 }
961
962
963 static ULONG 
964 _WhoControlsSquareFast(IN POSITION *pos, 
965                        IN COOR c)
966 /**
967
968 Routine description:
969
970     Determine which side controls a board square.
971
972 Parameters:
973
974     POSITION *pos : the board
975     COOR c : the square in question
976
977 Return value:
978
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.
982     
983     TODO: fix this to use counts / xrays
984
985 **/
986 {
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;
991     ULONG u;
992     PIECE p;
993     CHAR ch;
994     
995     ASSERT((c + 8) == (c | 8));
996     ASSERT((uWhite & 0xFFFFFF00) == 0);
997     ASSERT((uBlack & 0xFFFFFF00) == 0);
998
999     // TODO: keep these and update the table to use them
1000     uWhite >>= 3;
1001     uBlack >>= 3;
1002     
1003     p = pos->rgSquare[c].pPiece;
1004     // p -= 2;
1005     ch = g_SwapTable[p][uWhite][uBlack];
1006     if (ch != 0)
1007     {
1008         u = ch;
1009         u >>= 7;
1010         u = u & 1;
1011         ASSERT(((u == 1) && (ch < 0)) ||
1012                ((u == 0) && (ch > 0)));
1013         return(FLIP(u));
1014     }
1015     return((ULONG)-1);
1016 }
1017
1018 /**
1019
1020 Routine description:
1021
1022     Zero out the attack table before building it.
1023
1024 Parameters:
1025
1026     POSITION *pos
1027
1028 Return value:
1029
1030     void
1031
1032 **/
1033 #define CLEAR_A_SQ \
1034         pos->rgSquare[c].bvAttacks[0].uWholeThing = 0; \
1035         pos->rgSquare[c].bvAttacks[1].uWholeThing = 0;
1036
1037 #define CLEAR_A_RANK \
1038         CLEAR_A_SQ; c++; \
1039         CLEAR_A_SQ; c++; \
1040         CLEAR_A_SQ; c++; \
1041         CLEAR_A_SQ; c++; \
1042         CLEAR_A_SQ; c++; \
1043         CLEAR_A_SQ; c++; \
1044         CLEAR_A_SQ; c++; \
1045         CLEAR_A_SQ; c += 9;
1046
1047 #define CLEAR_SHORT_RANK \
1048         CLEAR_A_SQ; c++; \
1049         CLEAR_A_SQ; c++; \
1050         CLEAR_A_SQ; c++; \
1051         CLEAR_A_SQ; c++; \
1052         CLEAR_A_SQ; c++; \
1053         CLEAR_A_SQ; c++; \
1054         CLEAR_A_SQ; c += 10;
1055
1056 static void 
1057 _ClearAttackTables(IN OUT POSITION *pos)
1058 {
1059     register COOR c = 8;
1060 #if 1
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;
1068     CLEAR_A_SQ; c = 9;
1069     CLEAR_SHORT_RANK;
1070     CLEAR_SHORT_RANK;
1071     CLEAR_SHORT_RANK;
1072     CLEAR_SHORT_RANK;
1073     CLEAR_SHORT_RANK;
1074     CLEAR_SHORT_RANK;
1075     CLEAR_SHORT_RANK;
1076     CLEAR_SHORT_RANK;
1077 #else
1078     CLEAR_A_RANK;
1079     CLEAR_A_RANK;
1080     CLEAR_A_RANK;
1081     CLEAR_A_RANK;
1082     CLEAR_A_RANK;
1083     CLEAR_A_RANK;
1084     CLEAR_A_RANK;
1085     CLEAR_A_RANK;
1086 #endif
1087 }
1088
1089
1090 static INLINE void 
1091 _InitializePawnHashEntry(IN OUT PAWN_HASH_ENTRY *pHash, 
1092                          IN POSITION *pos)
1093 /**
1094
1095 Routine description:
1096
1097 Parameters:
1098
1099     PAWN_HASH_ENTRY *pHash,
1100     POSITION *pos
1101
1102 Return value:
1103
1104     static INLINE void
1105
1106 **/
1107 {
1108     memset(pHash, 0, sizeof(PAWN_HASH_ENTRY));
1109     pHash->u64Key = pos->u64PawnSig;
1110 }
1111
1112
1113 static INLINE void
1114 _EvaluateCandidatePasser(IN POSITION *pos,
1115                          IN OUT PAWN_HASH_ENTRY *pHash,
1116                          IN COOR c)
1117 /**
1118
1119 Routine description:
1120
1121 Parameters:
1122
1123     POSITION *pos,
1124     PAWN_HASH_ENTRY *pHash,
1125     COOR c
1126
1127 Return value:
1128
1129     static INLINE
1130
1131 **/
1132 {
1133     COOR c1, cSquare;
1134     PIECE pSentry, pHelper;
1135     ULONG uPawnFile = FILE(c) + 1;
1136     BITBOARD bb;
1137     ULONG uSentries, uHelpers;
1138     ULONG uColor;
1139     int d1;
1140 #ifdef DEBUG
1141     COOR cVerifySquare;
1142     ULONG uVerifySentries;
1143 #endif
1144
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));
1152     
1153     if (pHash->uCountPerFile[FLIP(uColor)][uPawnFile] != 0)
1154     {
1155         ASSERT((pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[FILE(c)]) != 0);
1156         
1157         //
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.
1162         //
1163         switch(uColor)
1164         {
1165             case WHITE:
1166                 bb = pHash->bbPawnLocations[BLACK] & BBFILE[FILE(c)];
1167                 ASSERT(bb);
1168                 while(IS_ON_BOARD(c1 = CoorFromBitBoardRank8ToRank1(&bb)))
1169                 {
1170                     ASSERT(FILE(c1) == FILE(c));
1171                     if (c1 < c) return;
1172                 }
1173                 break;
1174             case BLACK:
1175                 bb = pHash->bbPawnLocations[WHITE] & BBFILE[FILE(c)];
1176                 ASSERT(bb);
1177                 while(IS_ON_BOARD(c1 = CoorFromBitBoardRank1ToRank8(&bb)))
1178                 {
1179                     ASSERT(FILE(c1) == FILE(c));
1180                     if (c1 > c) return;
1181                 }
1182                 break;
1183         }
1184     }
1185         
1186     //
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.
1190     // 
1191     bb = pHash->bbPawnLocations[FLIP(uColor)] & BBADJACENT_FILES[FILE(c)];
1192     bb &= BBPRECEEDING_RANKS[(c & 0x70) >> 4][uColor];
1193     if (!bb)
1194     {
1195         ASSERT(CountBits(bb) == 0);
1196
1197         //
1198         // There are no sentries so this pawn is a passer.
1199         //
1200         pHash->bbPasserLocations[uColor] |= COOR_TO_BB(c);
1201         ASSERT(CountBits(pHash->bbPasserLocations[uColor]) > 0);
1202         ASSERT(CountBits(pHash->bbPasserLocations[uColor]) <= 8);
1203         EVAL_TERM(uColor,
1204                   PAWN,
1205                   c,
1206                   pHash->iScore[uColor],
1207                   PASSER_BY_RANK[uColor][RANK(c)],
1208                   "passed pawn");
1209         
1210         //
1211         // However, don't give doubled passers such a big bonus.
1212         //
1213         if (IS_PAWN(pos->rgSquare[c - 16 * g_iAhead[uColor]].pPiece)) 
1214         {
1215             EVAL_TERM(uColor,
1216                       PAWN,
1217                       c,
1218                       pHash->iScore[uColor],
1219                       -(PASSER_BY_RANK[uColor][RANK(c)] / 2),
1220                       "doubled passer");
1221         }
1222         return;
1223     }
1224     uSentries = CountBits(bb);
1225
1226     //
1227     // There's one or more sentry pawns so we'll look for helpers to
1228     // decide if this pawn is a candidate passer.
1229     //
1230     if (uColor == WHITE)
1231     {
1232         pSentry = BLACK_PAWN;
1233         cSquare = CoorFromBitBoardRank1ToRank8(&bb);
1234         cSquare += 0x10;
1235     }
1236     else
1237     {
1238         pSentry = WHITE_PAWN;
1239         cSquare = CoorFromBitBoardRank8ToRank1(&bb);
1240         cSquare -= 0x10;
1241     }
1242     cSquare &= 0xF0;
1243     cSquare |= FILE(c);
1244     ASSERT(IS_ON_BOARD(cSquare));
1245     ASSERT(FILE(cSquare) == FILE(c));
1246
1247 #ifdef DEBUG
1248     uVerifySentries = 0;
1249     cVerifySquare = 0;
1250     d1 = 16 * g_iAhead[uColor];
1251     c1 = c + d1;
1252     do
1253     {
1254         if (IS_ON_BOARD(c1 - 1))
1255         {
1256             if (pos->rgSquare[c1 - 1].pPiece == pSentry)
1257             {
1258                 uVerifySentries++;
1259                 if (0 == cVerifySquare) 
1260                 {
1261                     cVerifySquare = c1 - d1;
1262                     ASSERT(cVerifySquare == cSquare);
1263                 }
1264             }
1265         }
1266         if (IS_ON_BOARD(c1 + 1))
1267         {
1268             if (pos->rgSquare[c1 + 1].pPiece == pSentry)
1269             {
1270                 uVerifySentries++;
1271                 if (0 == cVerifySquare)
1272                 {
1273                     cVerifySquare = c1 - d1;
1274                     ASSERT(cVerifySquare == cSquare);
1275                 }
1276             }
1277         }
1278         c1 = c1 + d1;
1279     }
1280     while(!RANK8(c1) && !RANK1(c1));
1281     ASSERT(uVerifySentries == uSentries);
1282 #endif
1283
1284     //
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.
1288     //
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.
1291     //
1292     uHelpers = 0;
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]))
1297     {
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))
1301         {
1302             //
1303             // The square c1 the place a helper pawn must get to in
1304             // order to aide the candidate past a sentry.
1305             //
1306             if (pos->rgSquare[c1].pPiece == pHelper)
1307             {
1308                 uHelpers = 1;
1309                 goto do_left;
1310             }
1311             
1312             //
1313             // There is no helper pawn in the support position yet.
1314             // See if one can get there.
1315             //
1316             c1 = c1 - d1;
1317             while (IS_ON_BOARD(c1) &&
1318                ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
1319                 (pos->rgSquare[c1+8].bvAttacks[uColor].uWholeThing)))
1320             {
1321                 if (pos->rgSquare[c1].pPiece == pHelper)
1322                 {
1323                     uHelpers = 1;
1324                     break;
1325                 }
1326                 else if (pos->rgSquare[c1].pPiece == pSentry)
1327                 {
1328                     break;
1329                 }
1330                 c1 = c1 - d1;
1331             }
1332         }
1333     }
1334     
1335  do_left:
1336     c1 = cSquare - 1 - d1;
1337     if ((IS_ON_BOARD(c1)) && (pHash->uCountPerFile[uColor][FILE(c1) + 1]))
1338     {
1339         ASSERT(pHash->bbPawnLocations[uColor] & BBFILE[FILE(c1)]);
1340
1341         if (!(pos->rgSquare[c1 + 8].bvAttacks[FLIP(uColor)].uWholeThing) ||
1342             (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing))
1343         {
1344             //
1345             // The square c1 is the place a helper pawn must get to in
1346             // order to aide the candidate.
1347             //
1348             if (pos->rgSquare[c1].pPiece == pHelper)
1349             {
1350                 uHelpers++;
1351                 goto done_helpers;
1352             }
1353             
1354             //
1355             // There is no pawn in the left support position yet.  See
1356             // if one can get there.
1357             //
1358             c1 -= d1;
1359             while (IS_ON_BOARD(c1) &&
1360                ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
1361                 (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing)))
1362             {
1363                 if (pos->rgSquare[c1].pPiece == pHelper)
1364                 {
1365                     uHelpers++;
1366                     break;
1367                 }
1368                 else if (pos->rgSquare[c1].pPiece == pSentry)
1369                 {
1370                     break;
1371                 }
1372                 c1 -= d1;
1373             }
1374         }
1375     }
1376     
1377  done_helpers:
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)))))
1383     {
1384         ASSERT(CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)] > 0);
1385         EVAL_TERM(uColor,
1386                   PAWN,
1387                   c,
1388                   pHash->iScore[uColor],
1389                   CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)],
1390                   "candidate passer");
1391
1392         //
1393         // If the other side has no pieces then give this candidate an
1394         // extra bonus.
1395         //
1396         if (pos->uNonPawnCount[FLIP(uColor)][0] == 1)
1397         {
1398             EVAL_TERM(uColor,
1399                       PAWN,
1400                       c,
1401                       pHash->iScore[uColor],
1402                       CANDIDATE_PASSER_BY_RANK[uColor][RANK(c)],
1403                       "candidate passer in endgame");
1404         }
1405     }
1406 }
1407
1408 static void 
1409 _EvaluateConnectedSupportedOutsidePassers(IN POSITION *pos,
1410                                           IN OUT PAWN_HASH_ENTRY *pHash)
1411 /**
1412
1413 Routine description:
1414
1415 Parameters:
1416
1417     POSITION *pos,
1418     PAWN_HASH_ENTRY *pHash
1419
1420 Return value:
1421
1422     void
1423
1424 **/
1425 {
1426     ULONG uColor;
1427     ULONG u, v;
1428     COOR c;
1429     COOR cLeftmostPasser, cRightmostPasser;
1430     PIECE pFriend;
1431     COOR cSupport;
1432     BITBOARD bb;
1433     static const INT iDelta[5] = 
1434     {
1435         -1, +1, +17, +15, 0
1436     };
1437     
1438     FOREACH_COLOR(uColor)
1439     {
1440         ASSERT(IS_VALID_COLOR(uColor));
1441         
1442         if (pHash->bbPasserLocations[uColor])
1443         {
1444             ASSERT(pos->uPawnCount[uColor] > 0);
1445             pFriend = BLACK_PAWN | uColor;
1446             cLeftmostPasser = cRightmostPasser = ILLEGAL_COOR;
1447             for (u = A; u <= H; u++)
1448             {
1449                 bb = pHash->bbPasserLocations[uColor] & BBFILE[u];
1450                 if (bb != 0)
1451                 {
1452                     ASSERT(pHash->uCountPerFile[uColor][u+1] != 0);
1453                     while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bb)))
1454                     {
1455                         //
1456                         // Keep track of leftmost/rightmost passer for
1457                         // outside passer code later on.
1458                         //
1459                         ASSERT(FILE(c) == u);
1460                         ASSERT(RANK(c) > 1);
1461                         ASSERT(RANK(c) < 8);
1462                         if (cLeftmostPasser == ILLEGAL_COOR)
1463                         {
1464                             cLeftmostPasser = c;
1465                         }
1466                         cRightmostPasser = c;
1467                         
1468                         v = 0;
1469                         while(iDelta[v] != 0)
1470                         {
1471                             cSupport = c + iDelta[v] * g_iBehind[uColor];
1472                             if (IS_ON_BOARD(cSupport))
1473                             {
1474                                 if (pHash->bbPasserLocations[uColor] & 
1475                                     COOR_TO_BB(cSupport))
1476                                 {
1477                                     ASSERT(CONNECTED_PASSERS_BY_RANK[uColor]
1478                                            [RANK(c)] > 0);
1479                                     EVAL_TERM(uColor,
1480                                               PAWN,
1481                                               c,
1482                                               pHash->iScore[uColor],
1483                                               CONNECTED_PASSERS_BY_RANK[uColor]
1484                                               [RANK(c)],
1485                                               "connected passers");
1486
1487                                     //
1488                                     // TODO: connected passers vs a R is
1489                                     // strong.
1490                                     //
1491                                 }
1492                                 else if (pos->rgSquare[cSupport].pPiece == 
1493                                          pFriend)
1494                                 {
1495                                     ASSERT(SUPPORTED_PASSER_BY_RANK[uColor]
1496                                            [RANK(c)] > 0);
1497                                     EVAL_TERM(uColor,
1498                                               PAWN,
1499                                               c,
1500                                               pHash->iScore[uColor],
1501                                               SUPPORTED_PASSER_BY_RANK[uColor]
1502                                               [RANK(c)],
1503                                               "supported passer");
1504                                 }
1505                             }
1506                             v++;
1507                         }
1508                     }
1509                 }
1510             }
1511             
1512 #ifdef DEBUG
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)
1520             {
1521                 ASSERT(cLeftmostPasser == cRightmostPasser);
1522             }
1523 #endif
1524             for (u = A; u <= D; u++)
1525             {
1526                 if (pHash->uCountPerFile[FLIP(uColor)][u + 1] != 0)
1527                 {
1528                     ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[u]);
1529                     if (!(pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[u]))
1530                     {
1531                         break;
1532                     }
1533                 }
1534             }
1535             if (u > FILE(cLeftmostPasser))
1536             {
1537                 EVAL_TERM(uColor,
1538                           PAWN,
1539                           ILLEGAL_COOR,
1540                           pHash->iScore[uColor],
1541                           OUTSIDE_PASSER_BY_DISTANCE[u-FILE(cLeftmostPasser)],
1542                           "left outside passer");
1543             }
1544
1545             for (u = H; u >= E; u--)
1546             {
1547                 if (pHash->uCountPerFile[FLIP(uColor)][u + 1] != 0)
1548                 {
1549                     ASSERT(pHash->bbPawnLocations[FLIP(uColor)] & BBFILE[u]);
1550                     if (!(pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[u]))
1551                     {
1552                         break;
1553                     }
1554                 }
1555             }
1556             if (u < FILE(cRightmostPasser))
1557             {
1558                 EVAL_TERM(uColor,
1559                           PAWN,
1560                           ILLEGAL_COOR,
1561                           pHash->iScore[uColor],
1562                           OUTSIDE_PASSER_BY_DISTANCE[FILE(cRightmostPasser)-u],
1563                           "right outside passer");
1564             }
1565         }
1566     }
1567 }
1568                     
1569
1570 #define PAWN_ATTACK_BLACK_DELTA (+15)
1571 #define PAWN_ATTACK_WHITE_DELTA (-17)
1572
1573 static void 
1574 _PopulatePawnAttackBits(IN OUT POSITION *pos)
1575 /**
1576
1577 Routine description:
1578
1579     Populate the attack table with pawn bits.
1580
1581 Parameters:
1582
1583     POSITION *pos : the board
1584
1585 Return value:
1586
1587     void
1588
1589 **/
1590 {
1591     ULONG u;
1592     COOR c;
1593     COOR cAttack;
1594
1595     //
1596     // IDEA: combine clearing and initial population somehow?
1597     //
1598     // r - - - - - - l : only check L- and R-
1599     // r - - - - - - l
1600     // R A A A A A A L
1601     // R A A A A A A L
1602     // R A A A A A A L
1603     // R A A A A A A L
1604     // r - - - - - - l
1605     // r - - - - - - l : only check L+ and R+
1606     _ClearAttackTables(pos);
1607
1608     ASSERT(pos->uPawnCount[BLACK] <= 8);
1609     for (u = 0;
1610          u < pos->uPawnCount[BLACK]; 
1611          u++)
1612     {
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);
1618             
1619         //
1620         // IDEA: These IS_ON_BOARD checks can be removed by a lookup table.
1621         // 
1622         cAttack = c + PAWN_ATTACK_BLACK_DELTA;
1623         if (IS_ON_BOARD(cAttack))
1624         {
1625             ASSERT((cAttack + 8) == (cAttack|8));
1626             ASSERT(!IS_ON_BOARD(cAttack|8));
1627             pos->rgSquare[cAttack|8].bvAttacks[BLACK].small.uPawn = 1;
1628         }
1629         cAttack += 2;
1630         if (IS_ON_BOARD(cAttack))
1631         {
1632             ASSERT((cAttack + 8) == (cAttack|8));
1633             cAttack |= 8;
1634             ASSERT(!IS_ON_BOARD(cAttack));
1635             pos->rgSquare[cAttack].bvAttacks[BLACK].small.uPawn = 1;
1636         }
1637     }
1638
1639     ASSERT(pos->uPawnCount[WHITE] <= 8);
1640     for (u = 0;
1641          u < pos->uPawnCount[WHITE]; 
1642          u++)
1643     {
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);
1649             
1650         cAttack = c + PAWN_ATTACK_WHITE_DELTA;
1651         if (IS_ON_BOARD(cAttack))
1652         {
1653             ASSERT((cAttack + 8) == (cAttack|8));
1654             ASSERT(!IS_ON_BOARD(cAttack|8));
1655             pos->rgSquare[cAttack|8].bvAttacks[WHITE].small.uPawn = 1;
1656         }
1657         cAttack += 2;
1658         if (IS_ON_BOARD(cAttack))
1659         {
1660             ASSERT((cAttack + 8) == (cAttack|8));
1661             cAttack |= 8;
1662             ASSERT(!IS_ON_BOARD(cAttack));
1663             pos->rgSquare[cAttack].bvAttacks[WHITE].small.uPawn = 1;
1664         }
1665     }
1666 }
1667     
1668
1669 static PAWN_HASH_ENTRY *
1670 _EvalPawns(IN OUT SEARCHER_THREAD_CONTEXT *ctx, 
1671            OUT FLAG *pfDeferred)
1672 /**
1673
1674 Routine description:
1675
1676     Evaluate pawn structures; return a ptr to a pawn hash entry.
1677
1678 Parameters:
1679
1680     SEARCHER_THREAD_CONTEXT *ctx : the searcher thread context
1681
1682 Return value:
1683
1684     PAWN_HASH_ENTRY *
1685
1686 **/
1687 {
1688     static ULONG uUnmovedRank[2] = { 0x10, 0x60 };
1689     POSITION *pos = &ctx->sPosition;
1690     PAWN_HASH_ENTRY *pHash;
1691     COOR c, cSquare;
1692     PIECE p;
1693     ULONG uIsolated[2];
1694     ULONG uDoubled[2];
1695     SCORE iDuos[2];
1696     ULONG u, uPawnFile;
1697     ULONG uColor;
1698     ULONG uUnsupportable;
1699     BITBOARD bb;
1700     int d1;
1701 #ifdef DEBUG 
1702     SCORE t;
1703 #endif
1704
1705     //
1706     // Now, look up the hash entry for this position.
1707     //
1708     INC(ctx->sCounters.pawnhash.u64Probes);
1709     pHash = PawnHashLookup(ctx);
1710     ASSERT(NULL != pHash);
1711     if (pHash->u64Key == pos->u64PawnSig)
1712     {
1713         *pfDeferred = TRUE;
1714         INC(ctx->sCounters.pawnhash.u64Hits);
1715         return(pHash);
1716     }
1717
1718     //
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
1721     // one. :(
1722     //
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;
1729
1730     //
1731     // First pass
1732     //
1733     FOREACH_COLOR(uColor)
1734     {
1735         ASSERT(IS_VALID_COLOR(uColor));
1736         ASSERT(pos->uPawnCount[uColor] <= 8);
1737         
1738         d1 = 16 * g_iAhead[uColor];
1739         for (u = 0; 
1740              u < pos->uPawnCount[uColor]; 
1741              u++)
1742         {
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));
1749             
1750             //
1751             // Update files counter
1752             //
1753             ASSERT(pHash->uCountPerFile[uColor][uPawnFile] < 6);
1754             pHash->uCountPerFile[uColor][uPawnFile]++;
1755             
1756             //
1757             // Update bitboard bit
1758             //
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]);
1766
1767             //
1768             // Count unmoved pawns
1769             //
1770             pHash->uNumUnmovedPawns[uColor] += 
1771                 ((c & 0xF0) == uUnmovedRank[uColor]);
1772             ASSERT(pHash->uNumUnmovedPawns[uColor] <= 8);
1773             
1774             //
1775             // Detect rammed and other stationary pawns.
1776             //
1777             cSquare = c + d1;
1778             ASSERT(IS_ON_BOARD(cSquare));
1779             p = pos->rgSquare[cSquare].pPiece; 
1780             if (IS_PAWN(p))
1781             {
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);
1786             }
1787
1788             //
1789             // Give central pawns a small bonus; penalize rook pawns:
1790             //
1791             EVAL_TERM(uColor,
1792                       PAWN,
1793                       c,
1794                       pHash->iScore[uColor],
1795                       PAWN_CENTRALITY_BONUS[c],
1796                       "centrality");
1797         }
1798     }
1799
1800     //
1801     // We counted rammed pawns twice (once for the black pawn and once
1802     // for the white one).  Fix this now.
1803     //
1804     ASSERT(!(pHash->uNumRammedPawns & 1));
1805     pHash->uNumRammedPawns /= 2;
1806
1807     //
1808     // Second pass
1809     // 
1810     FOREACH_COLOR(uColor)
1811     {
1812         ASSERT(IS_VALID_COLOR(uColor));
1813         ASSERT(pos->uPawnCount[uColor] <= 8);
1814         ASSERT(CountBits(pHash->bbPawnLocations[uColor]) <= 8);
1815         
1816         d1 = 16 * g_iAhead[uColor];
1817         for (u = 0; 
1818              u < pos->uPawnCount[uColor];
1819              u++)
1820         {
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));
1825             
1826             //
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
1830             // defend them.
1831             //
1832             uUnsupportable = 0;
1833             uPawnFile = FILE(c) - 1;
1834             if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
1835             {
1836                 bb = (pHash->bbPawnLocations[uColor] & 
1837                       BBFILE[uPawnFile] &
1838                       BBADJACENT_RANKS[RANK(c)]);
1839                 if (!bb)
1840                 {
1841                     bb = (pHash->bbPawnLocations[FLIP(uColor)] &
1842                           BBFILE[uPawnFile]);
1843                     while(IS_ON_BOARD(cSquare = 
1844                                       CoorFromBitBoardRank8ToRank1(&bb)))
1845                     {
1846                         ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
1847                         if (uColor == WHITE)
1848                         {
1849                             if ((cSquare & 0xF0) >= (c & 0xF0))
1850                             {
1851                                 ASSERT(RANK(cSquare) <= RANK(c));
1852                                 uUnsupportable = 1;
1853                                 break;
1854                             }
1855                         }
1856                         else
1857                         {
1858                             ASSERT(uColor == BLACK);
1859                             if ((cSquare & 0xF0) <= (c & 0xF0))
1860                             {
1861                                 ASSERT(RANK(cSquare) >= RANK(c));
1862                                 uUnsupportable = 1;
1863                                 break;
1864                             }
1865                         }
1866                     }
1867                 }
1868             }
1869             else
1870             {
1871                 uUnsupportable = 1;           // no friend pawn on that file
1872             }
1873             if (0 == uUnsupportable)
1874             {
1875                 goto fast_skip;
1876             }
1877             ASSERT(1 == uUnsupportable);
1878
1879             uPawnFile = FILE(c) + 1;
1880             if (pHash->uCountPerFile[uColor][uPawnFile + 1] > 0)
1881             {
1882                 bb = (pHash->bbPawnLocations[uColor] & 
1883                       BBFILE[uPawnFile] &
1884                       BBADJACENT_RANKS[RANK(c)]);
1885                 if (!bb)
1886                 {
1887                     bb = (pHash->bbPawnLocations[FLIP(uColor)] &
1888                           BBFILE[uPawnFile]);
1889                     while(IS_ON_BOARD(cSquare = 
1890                                       CoorFromBitBoardRank8ToRank1(&bb)))
1891                     {
1892                         ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
1893                         if (uColor == WHITE)
1894                         {
1895                             if ((cSquare & 0xF0) >= (c & 0xF0))
1896                             {
1897                                 ASSERT(RANK(cSquare) <= RANK(c));
1898                                 uUnsupportable = 2;
1899                                 break;
1900                             }
1901                         }
1902                         else
1903                         {
1904                             ASSERT(uColor == BLACK);
1905                             if ((cSquare & 0xF0) <= (c & 0xF0))
1906                             {
1907                                 ASSERT(RANK(cSquare) >= RANK(c));
1908                                 uUnsupportable = 2;
1909                                 break;
1910                             }
1911                         }
1912                     }
1913                 }
1914             }
1915             else
1916             {
1917                 uUnsupportable = 2;
1918             }
1919             
1920             //
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
1924             // it.
1925             //
1926             if (2 == uUnsupportable)
1927             {
1928                 uPawnFile = FILE(c) + 1;
1929                 EVAL_TERM(uColor,
1930                           PAWN,
1931                           c,
1932                           pHash->iScore[uColor],
1933                           ISOLATED_PAWN_BY_PAWNFILE[uPawnFile],
1934                           "target/isolated pawn");
1935
1936                 //
1937                 // Isolated + exposed?  Extra penalty.
1938                 //
1939                 ASSERT(ISOLATED_EXPOSED_PAWN < 0);
1940                 EVAL_TERM(uColor,
1941                           PAWN,
1942                           c,
1943                           pHash->iScore[uColor],
1944                           ((pHash->uCountPerFile[FLIP(uColor)][uPawnFile]==0)* 
1945                            ISOLATED_EXPOSED_PAWN),
1946                           "exposed target");
1947                         
1948                 //
1949                 // Exponential penalty term
1950                 //
1951                 uIsolated[uColor] += 1;
1952                 ASSERT(uIsolated[uColor] > 0);
1953                 ASSERT(uIsolated[uColor] <= 8);
1954                         
1955                 //
1956                 // Isolated + doubled?  Extra penalty.
1957                 //
1958                 ASSERT(ISOLATED_DOUBLED_PAWN < 0);
1959                 EVAL_TERM(uColor,
1960                           PAWN,
1961                           c,
1962                           pHash->iScore[uColor],
1963                           ((pHash->uCountPerFile[uColor][uPawnFile] > 1) *
1964                            ISOLATED_DOUBLED_PAWN),
1965                           "doubled + target");
1966             }
1967
1968  fast_skip:
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]);
1973
1974             //
1975             // Keep count of doubled pawns
1976             //
1977             uDoubled[uColor] += (pHash->uCountPerFile[uColor][uPawnFile] > 1);
1978             ASSERT((0 <= uDoubled[uColor]) && (uDoubled[uColor] <= 8));
1979
1980             //
1981             // We can detect pawn duos (triads, etc...) and backward pawns
1982             // by considering the control of the pawn's stopsquare.
1983             //
1984             cSquare = c + d1;
1985             ASSERT(IS_ON_BOARD(cSquare));
1986             ASSERT((cSquare + 8) == (cSquare | 8));
1987             if (pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing)
1988             {
1989                 //
1990                 // Count pawn duos.  See "Pawn Power in Chess" pp 10-16
1991                 //
1992 #ifdef DEBUG
1993                 t = ((uColor * RANK(cSquare)) +
1994                      (FLIP(uColor) * (9 - RANK(cSquare))));
1995                 if (uColor == WHITE)
1996                 {
1997                     ASSERT(t == RANK(cSquare));
1998                 }
1999                 else
2000                 {
2001                     ASSERT(uColor == BLACK);
2002                     ASSERT(t == (9 - RANK(cSquare)));
2003                 }
2004 #endif
2005                 iDuos[uColor] += ((uColor * RANK(cSquare)) +
2006                                   (FLIP(uColor) * (9 - RANK(cSquare))));
2007                 ASSERT(iDuos[uColor] <= (7 * 8));
2008             }
2009             else if (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing)
2010             {
2011                 //
2012                 // Detect backwards pawns.  See "Pawn Power in Chess" pp 25-27
2013                 // 
2014                 if (!IS_PAWN(pos->rgSquare[cSquare].pPiece))
2015                 {
2016                     p = (BLACK_PAWN | uColor);
2017                     if (((WHITE == uColor) && (RANK(c) < 4)) ||
2018                         ((BLACK == uColor) && (RANK(c) > 5)))
2019                     {
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))
2024                         {
2025                             //
2026                             // The pawn at c is backward.  Determine
2027                             // whether it is shielded or exposed.
2028                             //
2029                             pHash->bbStationaryPawns[uColor] |= COOR_TO_BB(c);
2030                             ASSERT(CountBits(pHash->bbStationaryPawns[uColor])
2031                                    <= 8);
2032                             if (pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
2033                             {
2034                                 ASSERT(BACKWARD_SHIELDED_BY_LOCATION[c] < 0);
2035                                 EVAL_TERM(uColor,
2036                                           PAWN,
2037                                           c,
2038                                           pHash->iScore[uColor],
2039                                           BACKWARD_SHIELDED_BY_LOCATION[c],
2040                                           "shielded backward pawn");
2041                             }
2042                             else
2043                             {
2044                                 ASSERT(BACKWARD_EXPOSED_BY_LOCATION[c] < 0);
2045                                 EVAL_TERM(uColor,
2046                                           PAWN,
2047                                           c,
2048                                           pHash->iScore[uColor],
2049                                           BACKWARD_EXPOSED_BY_LOCATION[c],
2050                                           "exposed backward pawn");
2051                             }
2052                         }
2053                     }
2054                 }
2055                 //
2056                 // TODO: Think about backward doubled pawns; read Kauffman's
2057                 // paper "All About Doubled Pawns".
2058                 // 
2059             }
2060
2061             //
2062             // Handle passers / candidate passers
2063             // 
2064             _EvaluateCandidatePasser(pos, pHash, c);
2065         }
2066     }
2067     
2068     //
2069     // Reward pawn duos, see "Pawn Power in Chess" pp. 10-16
2070     // 
2071     ASSERT(iDuos[WHITE] >= 0);
2072     ASSERT(iDuos[WHITE] <= 56);
2073     ASSERT(iDuos[BLACK] >= 0);
2074     ASSERT(iDuos[BLACK] <= 56);
2075     EVAL_TERM(WHITE,
2076               PAWN,
2077               ILLEGAL_COOR,
2078               pHash->iScore[WHITE],
2079               iDuos[WHITE] / 2,
2080               "pawn duos");
2081     EVAL_TERM(BLACK,
2082               PAWN,
2083               ILLEGAL_COOR,
2084               pHash->iScore[BLACK],
2085               iDuos[BLACK] / 2,
2086               "pawn duos");
2087
2088     //
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.
2095     //
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;
2099     u = MINU(u, 3);
2100     EVAL_TERM(BLACK,
2101               PAWN,
2102               ILLEGAL_COOR,
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;
2107     u = MINU(u, 3);
2108     EVAL_TERM(WHITE,
2109               PAWN,
2110               ILLEGAL_COOR,
2111               pHash->iScore[WHITE],
2112               DOUBLED_PAWN_PENALTY_BY_COUNT[u][uDoubled[WHITE]],
2113               "exponential doubled");
2114
2115     ASSERT(uIsolated[WHITE] >= 0);
2116     ASSERT(uIsolated[WHITE] <= 8);
2117     ASSERT(uIsolated[BLACK] >= 0);
2118     ASSERT(uIsolated[BLACK] <= 8);
2119     EVAL_TERM(BLACK,
2120               PAWN,
2121               ILLEGAL_COOR,
2122               pHash->iScore[BLACK],
2123               ISOLATED_PAWN_PENALTY_BY_COUNT[uIsolated[BLACK]],
2124               "exponential isolated");
2125     EVAL_TERM(WHITE,
2126               PAWN,
2127               ILLEGAL_COOR,
2128               pHash->iScore[WHITE],
2129               ISOLATED_PAWN_PENALTY_BY_COUNT[uIsolated[WHITE]],
2130               "exponential isolated");
2131     
2132     //
2133     // Look for connected, supported and outside passed pawns to give 
2134     // extra bonuses.
2135     //
2136     _EvaluateConnectedSupportedOutsidePassers(pos, pHash);
2137
2138     //
2139     // TODO: recognize quartgrips and stonewalls
2140     //
2141     return(pHash);
2142 }
2143
2144
2145 ULONG 
2146 CountKingSafetyDefects(IN OUT POSITION *pos,
2147                        IN ULONG uSide)
2148 /**
2149
2150 Routine description:
2151
2152     Determine how many defects uSide's king position has _quickly_.
2153     TODO: add more knowledge as cheaply as possible...
2154
2155 Parameters:
2156
2157     POSITION *pos,
2158     ULONG uSide
2159
2160 Return value:
2161
2162     ULONG
2163
2164 **/
2165 {
2166     ULONG uCounter = 0;
2167     ULONG xSide = FLIP(uSide);
2168     COOR cKing;
2169     COOR c;
2170     int i;
2171     PIECE p;
2172     ULONG u;
2173     
2174     //
2175     // Don't count king safety defects if the real eval code in
2176     // _EvalKing would not...
2177     // 
2178     if (pos->uNonPawnMaterial[xSide] < DO_KING_SAFETY_THRESHOLD) {
2179         return 0;
2180     }
2181
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);
2188     
2189     //
2190     // Make sure cKing - 1, cKing and cKing + 1 are on the board
2191     //
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));
2197
2198     //
2199     // Consider all enemy pieces except the king (not including pawns)
2200     //
2201     for (u = 1;
2202          u < pos->uNonPawnCount[xSide][0];
2203          u++)
2204     {
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);
2214
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));
2219     }
2220     ASSERT(uCounter < 15);
2221     
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));
2225     return uCounter;
2226 }
2227
2228
2229 static void
2230 _QuicklyEstimateKingSafetyTerm(IN POSITION *pos, 
2231                                IN OUT SCORE *piAlphaMargin,
2232                                IN OUT SCORE *piBetaMargin)
2233 /**
2234
2235 Routine description:
2236
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
2239     to the score.
2240
2241 Parameters:
2242
2243     POSITION *pos
2244
2245 Return value:
2246
2247     void
2248
2249 **/
2250 {
2251     //
2252     // IDEA: make this stuff dynamic like ctx->uPositional
2253     //
2254     static const SCORE iScoreByDefectCount[15] = {
2255         33, 50, 88, 146, 215, 245, 280, 430, 550, 630, 646, 646, 646, 646, 646
2256     };
2257     SCORE iPenaltyEst[2];
2258     SCORE iRet;
2259
2260     ASSERT(CountKingSafetyDefects(pos, pos->uToMove) < 15);
2261     iPenaltyEst[WHITE] = 
2262         iScoreByDefectCount[CountKingSafetyDefects(pos, WHITE)];
2263     ASSERT(iPenaltyEst[WHITE] > 0);
2264
2265     ASSERT(CountKingSafetyDefects(pos, BLACK) < 15);
2266     iPenaltyEst[BLACK] = 
2267         iScoreByDefectCount[CountKingSafetyDefects(pos, BLACK)];
2268     ASSERT(iPenaltyEst[BLACK] > 0);
2269
2270     //
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.
2274     //
2275     iRet = iPenaltyEst[pos->uToMove] - iPenaltyEst[FLIP(pos->uToMove)] / 2;
2276     iRet = MAX0(iRet);
2277     ASSERT(iRet >= 0);
2278     *piBetaMargin += iRet;
2279
2280     //
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.
2284     //
2285     iRet = iPenaltyEst[FLIP(pos->uToMove)] - iPenaltyEst[pos->uToMove] / 2;
2286     iRet = MAX0(iRet);
2287     ASSERT(iRet >= 0);
2288     *piAlphaMargin += iRet;
2289 }
2290
2291
2292 static void
2293 _QuicklyEstimatePasserBonuses(POSITION *pos,
2294                               PAWN_HASH_ENTRY *pHash,
2295                               SCORE *piAlphaMargin,
2296                               SCORE *piBetaMargin) 
2297 {
2298     SCORE iBonusEst[2] = {0, 0};
2299     SCORE iRet;
2300     ULONG u;
2301
2302     //
2303     // Guess about the passer bonuses
2304     //
2305     if (pHash->bbPasserLocations[WHITE])
2306     {
2307         u = pos->uNonPawnMaterial[BLACK] - VALUE_KING;
2308         u /= VALUE_PAWN;
2309         u = MINU(31, u);
2310         ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
2311         iBonusEst[WHITE] = 
2312             (CountBits(pHash->bbPasserLocations[WHITE]) *
2313              PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
2314     }
2315     if (pHash->bbPasserLocations[BLACK])
2316     {
2317         u = pos->uNonPawnMaterial[WHITE] - VALUE_KING;
2318         u /= VALUE_PAWN;
2319         u = MINU(31, u);
2320         ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
2321         iBonusEst[BLACK] = 
2322             (CountBits(pHash->bbPasserLocations[BLACK]) *
2323              PASSER_BONUS_AS_MATERIAL_COMES_OFF[u]);
2324     }
2325
2326     //
2327     // For the beta margin, assume our passer bonus gets reduced and
2328     // our opponent's is enhanced... net bonus to them / our bonus
2329     // not as high.
2330     //
2331     iRet = iBonusEst[pos->uToMove] / 2 - iBonusEst[FLIP(pos->uToMove)];
2332     iRet = MAX0(iRet);
2333     *piBetaMargin += iRet;
2334
2335     //
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 
2338     // as high.
2339     //
2340     iRet = iBonusEst[pos->uToMove] - iBonusEst[FLIP(pos->uToMove)] / 2;
2341     iRet = MAX0(iRet);
2342     *piAlphaMargin += iRet;
2343 }
2344
2345
2346 static void 
2347 _InvalidEvaluator(UNUSED POSITION *pos, 
2348                   UNUSED COOR c, 
2349                   UNUSED PAWN_HASH_ENTRY *pHash)
2350 /**
2351
2352 Routine description:
2353
2354     This code should never be called
2355
2356 Parameters:
2357
2358     POSITION *pos,
2359     COOR c,
2360     PAWN_HASH_ENTRY *pHash,
2361
2362 Return value:
2363
2364     void
2365
2366 **/
2367 {
2368     UtilPanic(SHOULD_NOT_GET_HERE,
2369               NULL, NULL, NULL, NULL,
2370               __FILE__, __LINE__);
2371 }
2372
2373 //
2374 // ======================================================================
2375 //
2376
2377 static FLAG FASTCALL  
2378 _InvalidMobilityHelper(UNUSED POSITION *pos,
2379                        UNUSED COOR c,
2380                        UNUSED ULONG *puMobility,
2381                        UNUSED ULONG *puBit)
2382 /**
2383
2384 Routine description:
2385
2386     This code should never be called
2387
2388 Parameters:
2389
2390     POSITION *pos,
2391     COOR c,
2392     ULONG *puMobility,
2393     ULONG *puBit
2394
2395 Return value:
2396
2397     static FLAG FASTCALL
2398
2399 **/
2400 {
2401     UtilPanic(SHOULD_NOT_GET_HERE,
2402               NULL, NULL, NULL, NULL,
2403               __FILE__, __LINE__);
2404     return(TRUE);
2405 }
2406
2407 // ----------------------------------------------------------------------
2408
2409 static FLAG FASTCALL 
2410 _BMinorToEnemyLess(IN POSITION *pos,
2411                    IN COOR c,
2412                    IN OUT ULONG *puMobility,
2413                    UNUSED ULONG *puBit)
2414 /**
2415
2416 Routine description:
2417
2418     Consider a black minor (knight | bishop) taking an enemy pawn
2419
2420 Parameters:
2421
2422     POSITION *pos,
2423     COOR c,
2424     ULONG *puMobility,
2425     ULONG *puBit
2426
2427 Return value:
2428
2429     static FLAG FASTCALL : always TRUE, stop scanning in this direction
2430
2431 **/
2432 {
2433 #ifdef DEBUG
2434     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2435     PIECE p = pos->rgSquare[c].pPiece;
2436     
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));
2442     ASSERT(IS_PAWN(p));
2443     ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
2444     ASSERT(OPPOSITE_COLORS(p, pMinor));
2445     ASSERT(GET_COLOR(pMinor) == BLACK);
2446 #endif
2447     *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
2448     ASSERT(*puMobility <= 8);
2449     return(TRUE);                             // stop scanning this dir
2450 }
2451
2452 static FLAG FASTCALL 
2453 _WMinorToEnemyLess(IN POSITION *pos,
2454                    IN COOR c,
2455                    IN OUT ULONG *puMobility,
2456                    UNUSED ULONG *puBit)
2457 /**
2458
2459 Routine description:
2460
2461 Parameters:
2462
2463     POSITION *pos,
2464     COOR c,
2465     ULONG *puMobility,
2466     ULONG *puBit
2467
2468 Return value:
2469
2470     static FLAG FASTCALL
2471
2472 **/
2473 {
2474 #ifdef DEBUG
2475     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2476     PIECE p = pos->rgSquare[c].pPiece;
2477     
2478     ASSERT(IS_ON_BOARD(c));
2479     ASSERT(IS_ON_BOARD(pos->cPiece));
2480     ASSERT(!IS_EMPTY(p));
2481     ASSERT(IS_PAWN(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);
2487 #endif
2488     *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
2489     ASSERT(*puMobility <= 8);
2490     return(TRUE);                             // stop scanning this dir
2491 }
2492
2493 static FLAG FASTCALL 
2494 _WRookToEnemyLess(POSITION *pos,
2495                   COOR c,
2496                   ULONG *puMobility,
2497                   UNUSED ULONG *puBit)
2498 /**
2499
2500 Routine description:
2501
2502 Parameters:
2503
2504     POSITION *pos,
2505     COOR c,
2506     ULONG *puMobility,
2507     ULONG *puBit
2508
2509 Return value:
2510
2511     static FLAG FASTCALL
2512
2513 **/
2514 {
2515 #ifdef DEBUG
2516     PIECE p = pos->rgSquare[c].pPiece;
2517     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2518     
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));
2524 #endif
2525     *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
2526     ASSERT(*puMobility <= 7);
2527     return(TRUE);                             // stop scanning this dir
2528 }
2529
2530 static FLAG FASTCALL 
2531 _BRookToEnemyLess(IN POSITION *pos,
2532                   IN COOR c,
2533                   IN OUT ULONG *puMobility,
2534                   UNUSED ULONG *puBit)
2535 /**
2536
2537 Routine description:
2538
2539 Parameters:
2540
2541     POSITION *pos,
2542     COOR c,
2543     ULONG *puMobility,
2544     ULONG *puBit
2545
2546 Return value:
2547
2548     static FLAG FASTCALL
2549
2550 **/
2551 {
2552 #ifdef DEBUG
2553     PIECE p = pos->rgSquare[c].pPiece;
2554     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2555     
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));
2562 #endif
2563     *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
2564     ASSERT(*puMobility <= 7);
2565     return(TRUE);                             // stop scanning this dir
2566 }
2567
2568
2569 static FLAG FASTCALL 
2570 _BQueenToEnemyLess(IN POSITION *pos,
2571                    IN COOR c,
2572                    IN OUT ULONG *puMobility,
2573                    UNUSED ULONG *puBit)
2574 /**
2575
2576 Routine description:
2577
2578 Parameters:
2579
2580     POSITION *pos,
2581     COOR c,
2582     ULONG *puMobility,
2583     ULONG *puBit
2584
2585 Return value:
2586
2587     static FLAG FASTCALL
2588
2589 **/
2590 {
2591 #ifdef DEBUG
2592     PIECE p = pos->rgSquare[c].pPiece;
2593     PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2594     
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));
2601 #endif
2602     *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
2603     ASSERT(*puMobility <= 27);
2604     return(TRUE);                             // stop scanning this dir
2605 }
2606
2607
2608 static FLAG FASTCALL 
2609 _WQueenToEnemyLess(IN POSITION *pos,
2610                    IN COOR c,
2611                    IN OUT ULONG *puMobility,
2612                    UNUSED ULONG *puBit)
2613 /**
2614
2615 Routine description:
2616
2617 Parameters:
2618
2619     POSITION *pos,
2620     COOR c,
2621     ULONG *puMobility,
2622     ULONG *puBit
2623
2624 Return value:
2625
2626     static FLAG FASTCALL
2627
2628 **/
2629 {
2630 #ifdef DEBUG
2631     PIECE p = pos->rgSquare[c].pPiece;
2632     PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2633     
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));
2640 #endif
2641     *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
2642     ASSERT(*puMobility <= 27);
2643     return(TRUE);                             // stop scanning this dir
2644 }
2645
2646 // ----------------------------------------------------------------------
2647
2648 static FLAG FASTCALL 
2649 _EMinorToEnemySame(IN POSITION *pos,
2650                    IN COOR c,
2651                    IN OUT ULONG *puMobility,
2652                    UNUSED ULONG *puBit)
2653 /**
2654
2655 Routine description:
2656
2657 Parameters:
2658
2659     POSITION *pos,
2660     COOR c,
2661     ULONG *puMobility,
2662     ULONG *puBit
2663
2664 Return value:
2665
2666     static FLAG FASTCALL
2667
2668 **/
2669 {
2670 #ifdef DEBUG
2671     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2672     PIECE p = pos->rgSquare[c].pPiece;
2673     
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));
2679     
2680     if (IS_BISHOP(pMinor))
2681     {
2682         ASSERT(PIECE_VALUE(p) == VALUE_BISHOP);
2683     }
2684     else
2685     {
2686         ASSERT(IS_KNIGHT(pMinor));
2687         ASSERT(PIECE_VALUE(p) >= VALUE_KNIGHT);
2688     }
2689 #endif
2690     *puMobility += 1;
2691     ASSERT(*puMobility <= 8);
2692     return(TRUE);                             // stop scanning this dir
2693 }
2694
2695
2696 static FLAG FASTCALL 
2697 _ERookToEnemySame(IN POSITION *pos,
2698                   IN COOR c,
2699                   IN OUT ULONG *puMobility,
2700                   UNUSED ULONG *puBit)
2701 /**
2702
2703 Routine description:
2704
2705 Parameters:
2706
2707     POSITION *pos,
2708     COOR c,
2709     ULONG *puMobility,
2710     ULONG *puBit
2711
2712 Return value:
2713
2714     static FLAG FASTCALL
2715
2716 **/
2717 {
2718 #ifdef DEBUG
2719     PIECE p = pos->rgSquare[c].pPiece;
2720     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2721     
2722     ASSERT(IS_ON_BOARD(c));
2723     ASSERT(IS_ON_BOARD(pos->cPiece));
2724     ASSERT(IS_ROOK(pRook));
2725     ASSERT(!IS_EMPTY(p));
2726     ASSERT(IS_ROOK(p));
2727     ASSERT(OPPOSITE_COLORS(p, pRook));
2728 #endif
2729     *puMobility += 1;
2730     ASSERT(*puMobility <= 7);
2731     return(TRUE);                             // stop scanning this dir
2732 }
2733
2734
2735 static FLAG FASTCALL 
2736 _EQueenToEnemyGreaterEqual(IN POSITION *pos,
2737                            IN COOR c,
2738                            IN OUT ULONG *puMobility,
2739                            UNUSED ULONG *puBit)
2740 /**
2741
2742 Routine description:
2743
2744 Parameters:
2745
2746     POSITION *pos,
2747     COOR c,
2748     ULONG *puMobility,
2749     ULONG *puBit
2750
2751 Return value:
2752
2753     static FLAG FASTCALL
2754
2755 **/
2756 {
2757 #ifdef DEBUG
2758     PIECE p = pos->rgSquare[c].pPiece;
2759     PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
2760     
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));
2767 #endif
2768     *puMobility += 1;
2769     ASSERT(*puMobility <= 27);
2770     return(TRUE);                             // stop scanning this dir
2771 }
2772
2773 // ----------------------------------------------------------------------
2774
2775 static FLAG FASTCALL 
2776 _EMinorToEnemyGreater(IN POSITION *pos,
2777                       IN COOR c,
2778                       IN OUT ULONG *puMobility,
2779                       IN OUT ULONG *puBit)
2780 /**
2781
2782 Routine description:
2783
2784 Parameters:
2785
2786     POSITION *pos,
2787     COOR c,
2788     ULONG *puMobility,
2789     ULONG *puBit
2790
2791 Return value:
2792
2793     static FLAG FASTCALL
2794
2795 **/
2796 {
2797 #ifdef DEBUG
2798     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2799     PIECE p = pos->rgSquare[c].pPiece;
2800     
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));
2807 #endif
2808     *puMobility += 1;
2809     ASSERT(*puMobility <= 8);
2810     *puBit = MINOR_XRAY_BIT;
2811     return(FALSE);                            // keep scanning this dir
2812 }
2813
2814 static FLAG FASTCALL 
2815 _ERookToEnemyGreater(IN POSITION *pos,
2816                      IN COOR c,
2817                      IN OUT ULONG *puMobility,
2818                      IN OUT ULONG *puBit)
2819 /**
2820
2821 Routine description:
2822
2823 Parameters:
2824
2825     POSITION *pos,
2826     COOR c,
2827     ULONG *puMobility,
2828     ULONG *puBit
2829
2830 Return value:
2831
2832     static FLAG FASTCALL
2833
2834 **/
2835 {
2836 #ifdef DEBUG
2837     PIECE p = pos->rgSquare[c].pPiece;
2838     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
2839
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);
2846 #endif
2847     *puMobility += 1;
2848     ASSERT(*puMobility <= 7);
2849     *puBit = ROOK_XRAY_BIT;
2850     return(FALSE);                            // keep scanning this dir
2851 }
2852
2853 // ----------------------------------------------------------------------
2854
2855 static FLAG FASTCALL 
2856 _AnythingToFriendNoXray(IN POSITION *pos,
2857                         IN COOR c,
2858                         UNUSED ULONG *puMobility,
2859                         UNUSED ULONG *puBit)
2860 /**
2861
2862 Routine description:
2863
2864 Parameters:
2865
2866     POSITION *pos,
2867     COOR c,
2868     ULONG *puMobility,
2869     ULONG *puBit
2870
2871 Return value:
2872
2873     static FLAG FASTCALL
2874
2875 **/
2876 {
2877 #ifdef DEBUG
2878     COOR cMover = pos->cPiece;
2879     PIECE pMover = pos->rgSquare[cMover].pPiece;
2880     PIECE pFriend = pos->rgSquare[c].pPiece;
2881     
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))
2888     {
2889         ASSERT(!IS_BISHOP(pFriend));
2890         ASSERT(!IS_QUEEN(pFriend));
2891     }
2892     else if (IS_ROOK(pMover))
2893     {
2894         ASSERT(!IS_QUEEN(pFriend));
2895         ASSERT(!IS_ROOK(pFriend));
2896     }
2897     else if (IS_QUEEN(pMover))
2898     {
2899         ASSERT(!IS_BISHOP(pFriend));
2900         ASSERT(!IS_ROOK(pFriend));
2901         ASSERT(!IS_QUEEN(pFriend));
2902     }
2903 #endif
2904     return(TRUE);                             // stop scanning this dir
2905 }
2906
2907 // ----------------------------------------------------------------------
2908
2909 static FLAG FASTCALL 
2910 _EMinorToFriendXray(IN POSITION *pos,
2911                     IN COOR c,
2912                     IN OUT ULONG *puMobility,
2913                     IN OUT ULONG *puBit)
2914 /**
2915
2916 Routine description:
2917
2918 Parameters:
2919
2920     POSITION *pos,
2921     COOR c,
2922     ULONG *puMobility,
2923     ULONG *puBit
2924
2925 Return value:
2926
2927     static FLAG FASTCALL
2928
2929 **/
2930 {
2931 #ifdef DEBUG
2932     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
2933     PIECE p = pos->rgSquare[c].pPiece;
2934     
2935     ASSERT(!IS_EMPTY(p));
2936     ASSERT(!IS_EMPTY(pMinor));
2937     ASSERT(IS_BISHOP(pMinor));
2938     ASSERT(GET_COLOR(p) == GET_COLOR(pMinor));
2939 #endif
2940     *puBit = MINOR_XRAY_BIT;
2941     return(FALSE);
2942 }
2943
2944 static FLAG FASTCALL 
2945 _BRookToFriendRook(IN POSITION *pos,
2946                    IN COOR c,
2947                    IN OUT ULONG *puMobility,
2948                    IN OUT ULONG *puBit)
2949 /**
2950
2951 Routine description:
2952
2953 Parameters:
2954
2955     POSITION *pos,
2956     COOR c,
2957     ULONG *puMobility,
2958     ULONG *puBit
2959
2960 Return value:
2961
2962     static FLAG FASTCALL
2963
2964 **/
2965 {
2966     COOR cRook = pos->cPiece;
2967     FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
2968 #ifdef DEBUG
2969     PIECE p = pos->rgSquare[c].pPiece;
2970     PIECE pRook = pos->rgSquare[cRook].pPiece;
2971     
2972     ASSERT(IS_ON_BOARD(c));
2973     ASSERT(IS_ON_BOARD(cRook));
2974     ASSERT(IS_ROOK(pRook));
2975     ASSERT(!IS_EMPTY(p));
2976     ASSERT(IS_ROOK(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))));
2981 #endif
2982     EVAL_TERM(BLACK,
2983               ROOK,
2984               c,
2985               pos->iScore[BLACK],
2986               (ROOK_CONNECTED_HORIZ * fHoriz + 
2987                ROOK_CONNECTED_VERT * FLIP(fHoriz)),
2988               "rook connected");
2989     *puBit = ROOK_XRAY_BIT;
2990     return(FALSE);
2991 }
2992
2993
2994 static FLAG FASTCALL 
2995 _WRookToFriendRook(IN POSITION *pos,
2996                    IN COOR c,
2997                    IN OUT ULONG *puMobility,
2998                    IN OUT ULONG *puBit)
2999 /**
3000
3001 Routine description:
3002
3003 Parameters:
3004
3005     POSITION *pos,
3006     COOR c,
3007     ULONG *puMobility,
3008     ULONG *puBit
3009
3010 Return value:
3011
3012     static FLAG FASTCALL
3013
3014 **/
3015 {
3016     COOR cRook = pos->cPiece;
3017     FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
3018 #ifdef DEBUG
3019     PIECE p = pos->rgSquare[c].pPiece;
3020     PIECE pRook = pos->rgSquare[cRook].pPiece;
3021     
3022     ASSERT(IS_ON_BOARD(c));
3023     ASSERT(IS_ON_BOARD(cRook));
3024     ASSERT(IS_ROOK(pRook));
3025     ASSERT(!IS_EMPTY(p));
3026     ASSERT(IS_ROOK(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))));
3031 #endif
3032     EVAL_TERM(WHITE,
3033               ROOK,
3034               c,
3035               pos->iScore[WHITE],
3036               (ROOK_CONNECTED_HORIZ * fHoriz + 
3037                ROOK_CONNECTED_VERT * FLIP(fHoriz)),
3038               "rook connected");
3039     *puBit = ROOK_XRAY_BIT;
3040     return(FALSE);
3041 }
3042
3043
3044 static FLAG FASTCALL 
3045 _ERookToFriendQueen(IN POSITION *pos,
3046                     IN COOR c,
3047                     IN OUT ULONG *puMobility,
3048                     IN OUT ULONG *puBit)
3049 /**
3050
3051 Routine description:
3052
3053 Parameters:
3054
3055     POSITION *pos,
3056     COOR c,
3057     ULONG *puMobility,
3058     ULONG *puBit
3059
3060 Return value:
3061
3062     static FLAG FASTCALL
3063
3064 **/
3065 {
3066 #ifdef DEBUG
3067     PIECE p = pos->rgSquare[c].pPiece;
3068     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3069     
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));
3076 #endif
3077     *puBit = ROOK_XRAY_BIT;
3078     return(FALSE);
3079 }
3080
3081 static FLAG FASTCALL 
3082 _EQueenToFriendBishop(IN POSITION *pos,
3083                       IN COOR c,
3084                       IN OUT ULONG *puMobility,
3085                       IN OUT ULONG *puBit)
3086 /**
3087
3088 Routine description:
3089
3090 Parameters:
3091
3092     POSITION *pos,
3093     COOR c,
3094     ULONG *puMobility,
3095     ULONG *puBit
3096
3097 Return value:
3098
3099     static FLAG FASTCALL
3100
3101 **/
3102 {
3103     COOR cQueen = pos->cPiece;
3104 #ifdef DEBUG
3105     PIECE p = pos->rgSquare[c].pPiece;
3106     PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3107     
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));
3113 #endif
3114     *puBit = QUEEN_XRAY_BIT;
3115     return((((c & 0xF0) == (cQueen & 0xF0)) ||
3116             ((c & 0x0F) == (cQueen & 0x0F))));
3117 }
3118
3119
3120 static FLAG FASTCALL 
3121 _EQueenToFriendRook(IN POSITION *pos,
3122                     IN COOR c,
3123                     IN OUT ULONG *puMobility,
3124                     IN OUT ULONG *puBit)
3125 /**
3126
3127 Routine description:
3128
3129 Parameters:
3130
3131     POSITION *pos,
3132     COOR c,
3133     ULONG *puMobility,
3134     ULONG *puBit
3135
3136 Return value:
3137
3138     static FLAG FASTCALL
3139
3140 **/
3141 {
3142     COOR cQueen = pos->cPiece;
3143 #ifdef DEBUG
3144     PIECE p = pos->rgSquare[c].pPiece;
3145     PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3146     
3147     ASSERT(IS_ON_BOARD(c));
3148     ASSERT(IS_ON_BOARD(cQueen));
3149     ASSERT(IS_QUEEN(pQueen));
3150     ASSERT(IS_ROOK(p));
3151     ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
3152 #endif
3153     *puBit = QUEEN_XRAY_BIT;
3154     return(FLIP((((c & 0xF0) == (cQueen & 0xF0)) ||
3155                  ((c & 0x0F) == (cQueen & 0x0F)))));
3156 }
3157
3158
3159 static FLAG FASTCALL 
3160 _EQueenToFriendQueen(IN POSITION *pos,
3161                      IN COOR c,
3162                      IN OUT ULONG *puMobility,
3163                      IN OUT ULONG *puBit)
3164 /**
3165
3166 Routine description:
3167
3168 Parameters:
3169
3170     POSITION *pos,
3171     COOR c,
3172     ULONG *puMobility,
3173     ULONG *puBit
3174
3175 Return value:
3176
3177     static FLAG FASTCALL
3178
3179 **/
3180 {
3181 #ifdef DEBUG
3182     COOR cQueen = pos->cPiece;
3183     PIECE p = pos->rgSquare[c].pPiece;
3184     PIECE pQueen = pos->rgSquare[cQueen].pPiece;
3185     
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));
3191 #endif
3192     *puBit = QUEEN_XRAY_BIT;
3193     return(FALSE);
3194 }
3195
3196
3197 // ----------------------------------------------------------------------
3198
3199 static FLAG FASTCALL 
3200 _BMinorToEmpty(IN POSITION *pos,
3201                IN COOR c,
3202                IN OUT ULONG *puMobility,
3203                IN OUT ULONG *puBit)
3204 /**
3205
3206 Routine description:
3207
3208 Parameters:
3209
3210     POSITION *pos,
3211     COOR c,
3212     ULONG *puMobility,
3213     ULONG *puBit
3214
3215 Return value:
3216
3217     static FLAG FASTCALL
3218
3219 **/
3220 {
3221 #ifdef DEBUG
3222     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
3223     PIECE p = pos->rgSquare[c].pPiece;
3224     
3225     ASSERT(IS_EMPTY(p));
3226     ASSERT(!IS_EMPTY(pMinor));
3227     ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
3228     ASSERT(GET_COLOR(pMinor) == BLACK);
3229 #endif
3230     *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
3231     ASSERT(*puMobility <= 8);
3232     return(FALSE);
3233 }
3234
3235 static FLAG FASTCALL 
3236 _WMinorToEmpty(IN POSITION *pos,
3237                IN COOR c,
3238                IN OUT ULONG *puMobility,
3239                IN OUT ULONG *puBit)
3240 /**
3241
3242 Routine description:
3243
3244 Parameters:
3245
3246     POSITION *pos,
3247     COOR c,
3248     ULONG *puMobility,
3249     ULONG *puBit
3250
3251 Return value:
3252
3253     static FLAG FASTCALL
3254
3255 **/
3256 {
3257 #ifdef DEBUG
3258     PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
3259     PIECE p = pos->rgSquare[c].pPiece;
3260     
3261     ASSERT(IS_EMPTY(p));
3262     ASSERT(!IS_EMPTY(pMinor));
3263     ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
3264     ASSERT(GET_COLOR(pMinor) == WHITE);
3265 #endif
3266     *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
3267     ASSERT(*puMobility <= 8);
3268     return(FALSE);
3269 }
3270
3271 static FLAG FASTCALL 
3272 _WRookToEmpty(IN POSITION *pos,
3273               IN COOR c,
3274               IN OUT ULONG *puMobility,
3275               IN OUT ULONG *puBit)
3276 /**
3277
3278 Routine description:
3279
3280 Parameters:
3281
3282     POSITION *pos,
3283     COOR c,
3284     ULONG *puMobility,
3285     ULONG *puBit
3286
3287 Return value:
3288
3289     static FLAG FASTCALL
3290
3291 **/
3292 {
3293 #ifdef DEBUG
3294     PIECE p = pos->rgSquare[c].pPiece;
3295     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3296     
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);
3302 #endif
3303     *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
3304     ASSERT(*puMobility <= 7);
3305     return(FALSE);
3306 }
3307
3308 static FLAG FASTCALL 
3309 _BRookToEmpty(IN POSITION *pos,
3310               IN COOR c,
3311               IN OUT ULONG *puMobility,
3312               IN OUT ULONG *puBit)
3313 /**
3314
3315 Routine description:
3316
3317 Parameters:
3318
3319     POSITION *pos,
3320     COOR c,
3321     ULONG *puMobility,
3322     ULONG *puBit
3323
3324 Return value:
3325
3326     static FLAG FASTCALL
3327
3328 **/
3329 {
3330 #ifdef DEBUG
3331     PIECE p = pos->rgSquare[c].pPiece;
3332     PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
3333     
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);
3339 #endif
3340     *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
3341     ASSERT(*puMobility <= 7);
3342     return(FALSE);
3343 }
3344
3345 static FLAG FASTCALL 
3346 _BQueenToEmpty(IN POSITION *pos,
3347                IN COOR c,
3348                IN OUT ULONG *puMobility,
3349                IN OUT ULONG *puBit)
3350 /**
3351
3352 Routine description:
3353
3354 Parameters:
3355
3356     POSITION *pos,
3357     COOR c,
3358     ULONG *puMobility,
3359     ULONG *puBit
3360
3361 Return value:
3362
3363     static FLAG FASTCALL
3364
3365 **/
3366 {
3367 #ifdef DEBUG
3368     PIECE p = pos->rgSquare[c].pPiece;
3369     PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
3370     
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);
3376 #endif
3377     *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
3378     ASSERT(*puMobility <= 27);
3379     return(FALSE);
3380 }
3381
3382 static FLAG FASTCALL 
3383 _WQueenToEmpty(IN POSITION *pos,
3384                IN COOR c,
3385                IN OUT ULONG *puMobility,
3386                IN OUT ULONG *puBit)
3387 /**
3388
3389 Routine description:
3390
3391 Parameters:
3392
3393     POSITION *pos,
3394     COOR c,
3395     ULONG *puMobility,
3396     ULONG *puBit
3397
3398 Return value:
3399
3400     static FLAG FASTCALL
3401
3402 **/
3403 {
3404 #ifdef DEBUG
3405     PIECE p = pos->rgSquare[c].pPiece;
3406     PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
3407     
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);
3413 #endif
3414     *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
3415     ASSERT(*puMobility <= 27);
3416     return(FALSE);
3417 }
3418
3419
3420
3421 static FLAG FASTCALL 
3422 _EBishopToFriendPawn(IN POSITION *pos,
3423                      IN COOR c,
3424                      IN OUT ULONG *puMobility,
3425                      IN OUT ULONG *puBit)
3426 /**
3427
3428 Routine description:
3429
3430 Parameters:
3431
3432     POSITION *pos,
3433     COOR c,
3434     ULONG *puMobility,
3435     ULONG *puBit
3436
3437 Return value:
3438
3439     static FLAG FASTCALL
3440
3441 **/
3442 {
3443 #ifdef DEBUG
3444     PIECE pPawn = pos->rgSquare[c].pPiece;
3445     PIECE pBishop = pos->rgSquare[pos->cPiece].pPiece;
3446     
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));
3452 #endif
3453     *puMobility += ((pos->bb & COOR_TO_BB(c)) != 0);
3454     return(TRUE);
3455 }
3456
3457
3458
3459
3460 //
3461 // ======================================================================
3462 //
3463
3464
3465 static void
3466 _EvalBishop(IN OUT POSITION *pos,
3467             IN COOR c, 
3468             IN PAWN_HASH_ENTRY *pHash)
3469 /**
3470
3471 Routine description:
3472
3473 Parameters:
3474
3475     POSITION *pos,
3476     COOR c,
3477     PAWN_HASH_ENTRY *pHash,
3478
3479 Return value:
3480
3481     FLAG
3482
3483 **/
3484 {
3485     static const BITBOARD bbColorSq[2] = { 0x55aa55aa55aa55aaULL,
3486                                            0xaa55aa55aa55aa55ULL };
3487     static const PMOBILITY_HELPER BMobJumpTable[2][14] = 
3488     {
3489         {// (black)
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)
3504         },
3505         {// (white)
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)
3520         }
3521     };
3522     static const COOR cBishopAtHome[2][2] = 
3523     {
3524         { C8, F8 }, // BLACK
3525         { C1, F1 }  // WHITE
3526     };
3527     ULONG uColor;
3528     BITBOARD bb;
3529     BITBOARD bbMask;
3530     BITBOARD bbPc;
3531     COOR cSquare;
3532     SCORE i;
3533     ULONG u;
3534     ULONG uTotalMobility;
3535     ULONG uMaxMobility;
3536     ULONG uCurrentMobility;
3537     ULONG uBit;
3538     PIECE p;
3539     PMOBILITY_HELPER pFun;
3540     
3541     ASSERT(IS_ON_BOARD(c));
3542     p = pos->rgSquare[c].pPiece;
3543     ASSERT(p && IS_BISHOP(p));
3544     uColor = GET_COLOR(p);
3545
3546 #ifdef DEBUG
3547     pos->cPiece = c;
3548 #endif
3549
3550     //
3551     // Unmoved piece
3552     //
3553     pos->uMinorsAtHome[uColor] += (c == cBishopAtHome[uColor][0]);
3554     pos->uMinorsAtHome[uColor] += (c == cBishopAtHome[uColor][1]);
3555     ASSERT(pos->uMinorsAtHome[uColor] <= 4);
3556
3557     //
3558     // Good and bad bishops
3559     //
3560     i = 16;
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)))
3565     {
3566         //
3567         // Consider stationary (rammed or backward) pawns of the same
3568         // color as the bishop.
3569         //
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];
3574     }
3575     EVAL_TERM(uColor,
3576               BISHOP,
3577               c,
3578               pos->iScore[uColor],
3579               i,
3580               "good/bad stationary pawns ++");
3581
3582     i = 0;
3583     bbPc = ~(pHash->bbStationaryPawns[WHITE] | 
3584              pHash->bbStationaryPawns[BLACK]);
3585     bbPc &= bbMask;
3586     bb = pHash->bbPawnLocations[uColor] & bbPc;
3587     while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
3588     {
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];
3594     }
3595
3596     bb = pHash->bbPawnLocations[FLIP(uColor)] & bbPc;
3597     while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
3598     {
3599         //
3600         // N.B. Only count enemy pawns that are supported by another
3601         // pawn.
3602         //
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));
3607         i += 
3608          (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].small.uPawn != 0) *
3609             TRANSIENT_PAWN_ON_BISHOP_COLOR[cSquare] / 2;
3610     }
3611     EVAL_TERM(uColor,
3612               BISHOP,
3613               c,
3614               pos->iScore[uColor],
3615               i,
3616               "good/bad transient pawns");
3617
3618     //
3619     // Bonus to bishops in very open positions.
3620     //
3621     ASSERT(pos->uClosedScaler <= 32);
3622     EVAL_TERM(uColor,
3623               BISHOP,
3624               c,
3625               pos->iScore[uColor],
3626               BISHOP_IN_CLOSED_POSITION[pos->uClosedScaler],
3627               "in closed/open position");
3628     
3629     //
3630     // Bishop mobility (and update attack table bits)
3631     //
3632     u = uMaxMobility = uTotalMobility = 0;
3633     pos->bb = bbPc;
3634     ASSERT(g_iBDeltas[u] != 0);
3635     do
3636     {
3637         uCurrentMobility = 0;
3638         uBit = MINOR_BIT;
3639         cSquare = c + g_iBDeltas[u];
3640         
3641         while(IS_ON_BOARD(cSquare))
3642         {
3643             //
3644             // Always toggle attack table bits.
3645             //
3646             ASSERT((cSquare|8) == (cSquare + 8));
3647             pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
3648
3649             //
3650             // What did we hit?
3651             //
3652             p = pos->rgSquare[cSquare].pPiece;
3653             pFun = BMobJumpTable[uColor][p];
3654             ASSERT(pFun);
3655             if (TRUE == (*pFun)(pos,
3656                                 cSquare,
3657                                 &uCurrentMobility,
3658                                 &uBit))
3659             {
3660                 break;
3661             }
3662             cSquare += g_iBDeltas[u];
3663         }
3664         uTotalMobility += uCurrentMobility;
3665         ASSERT((uMaxMobility & 0x80000000) == 0);
3666         ASSERT((uCurrentMobility & 0x80000000) == 0);
3667         uMaxMobility = MAXU(uMaxMobility, uCurrentMobility);
3668         ASSERT(uMaxMobility <= 7);
3669         u++;
3670     }
3671     while(g_iBDeltas[u] != 0);
3672     ASSERT(uTotalMobility <= 13);
3673     EVAL_TERM(uColor,
3674               BISHOP,
3675               c,
3676               pos->iScore[uColor],
3677               BISHOP_MOBILITY_BY_SQUARES[uTotalMobility],
3678               "bishop mobility");
3679     EVAL_TERM(uColor,
3680               BISHOP,
3681               c,
3682               pos->iScore[uColor],
3683               BISHOP_MAX_MOBILITY_IN_A_ROW_BONUS[uMaxMobility],
3684               "consecutive bishop mobility");
3685
3686     //
3687     // Look for bishops with no mobility who are under attack.  These
3688     // pieces are trapped!
3689     //
3690     if (uTotalMobility == 0)
3691     {
3692         pos->cTrapped[uColor] = c;
3693     }
3694     uTotalMobility /= 2;
3695     ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
3696     ASSERT((uTotalMobility & 0x80000000) == 0);
3697     pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor], 
3698                                      uTotalMobility);
3699     
3700     //
3701     // Look for "active bad bishops".  See if square c is safe from
3702     // enemy pawns.
3703     //
3704     bb = pHash->bbPawnLocations[FLIP(uColor)] &
3705         (~pHash->bbStationaryPawns[FLIP(uColor)]);
3706     if (TRUE == _IsSquareSafeFromEnemyPawn(pos, c, bb))
3707     {
3708         //
3709         // Give a bonus based on distance from enemy king
3710         //
3711         if (pos->rgSquare[c|8].bvAttacks[uColor].small.uPawn)
3712         {
3713 #ifdef DEBUG
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))));
3719 #endif
3720             u = DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
3721             i = BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING[u];
3722             EVAL_TERM(uColor,
3723                       BISHOP,
3724                       c,
3725                       pos->iReducedMaterialDownScaler[uColor],
3726                       i,
3727                       "[scaled] unassailable");
3728         }
3729     }
3730 }
3731
3732 static void
3733 _EvalKnight(IN OUT POSITION *pos, 
3734             IN COOR c, 
3735             IN PAWN_HASH_ENTRY *pHash)
3736 /**
3737
3738 Routine description:
3739
3740 Parameters:
3741
3742     POSITION *pos,
3743     COOR c,
3744     PAWN_HASH_ENTRY *pHash,
3745
3746 Return value:
3747
3748     FLAG
3749
3750 **/
3751 {
3752     static const int iPawnStart[2] = { -17, +15 };
3753     static const PMOBILITY_HELPER NMobJumpTable[2][14] = 
3754     {
3755         {// (black)
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)
3770         },
3771         {// (white)
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)
3786         }
3787     };
3788     static const COOR cKnightAtHome[2][2] = 
3789     {
3790         { B8, G8 }, // BLACK
3791         { B1, G1 }  // WHITE
3792     };
3793     PIECE p;
3794     COOR cSquare;
3795     BITBOARD bb;
3796     ULONG uColor;
3797     ULONG uPawnsSupporting;
3798     ULONG u;
3799     ULONG uPawnFile;
3800     ULONG uMobilitySquares;
3801     SCORE i;
3802     ULONG uDist;
3803     PMOBILITY_HELPER pFun;
3804
3805     p = pos->rgSquare[c].pPiece;
3806     ASSERT(p && IS_KNIGHT(p));
3807     uColor = GET_COLOR(p);
3808     ASSERT(IS_VALID_COLOR(uColor));
3809 #ifdef DEBUG
3810     pos->cPiece = c;
3811 #endif
3812
3813     //
3814     // Unmoved piece
3815     //
3816     pos->uMinorsAtHome[uColor] += (c == cKnightAtHome[uColor][0]);
3817     pos->uMinorsAtHome[uColor] += (c == cKnightAtHome[uColor][1]);
3818     ASSERT(pos->uMinorsAtHome[uColor] <= 4);
3819
3820     //
3821     // TODO: Don't block unmoved E2/D2 pawns
3822     // 
3823     
3824     //
3825     // Centrality bonus
3826     //
3827     EVAL_TERM(uColor,
3828               KNIGHT,
3829               c,
3830               pos->iScore[uColor],
3831               KNIGHT_CENTRALITY_BONUS[c],
3832               "board centrality");
3833
3834     //
3835     // Give a bonus to knights on a closed / busy board
3836     //
3837     ASSERT(pos->uClosedScaler <= 32);
3838     EVAL_TERM(uColor,
3839               KNIGHT,
3840               c,
3841               pos->iScore[uColor],
3842               KNIGHT_IN_CLOSED_POSITION[pos->uClosedScaler],
3843               "in closed/open position");
3844
3845     //
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.
3849     //
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))
3855     {
3856         //
3857         // Count the number of supporting pawns the knight has
3858         //
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));
3864         cSquare += 2;
3865         uPawnsSupporting += (IS_ON_BOARD(cSquare) &&
3866                              (pos->rgSquare[cSquare].pPiece == p));
3867         ASSERT(uPawnsSupporting <= 2);
3868         
3869         //
3870         // Give a bonus based on distance from enemy king
3871         //
3872         i = KNIGHT_UNASSAILABLE_BY_DIST_FROM_EKING[uDist] +
3873             KNIGHT_WITH_N_PAWNS_SUPPORTING[uPawnsSupporting];
3874         EVAL_TERM(uColor,
3875                   KNIGHT,
3876                   c,
3877                   pos->iReducedMaterialDownScaler[uColor],
3878                   i,
3879                   "[scaled] unassailable/support");
3880         
3881         //
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.
3884         //
3885         if (uPawnsSupporting != 2)
3886         {
3887             if (IS_SQUARE_WHITE(c))
3888             {
3889                 if (pos->uWhiteSqBishopCount[FLIP(uColor)])
3890                 {
3891                     EVAL_TERM(uColor,
3892                               KNIGHT,
3893                               c,
3894                               pos->iScore[uColor],
3895                               -(i / 2),
3896                               "not safe from enemy B");
3897                 }
3898             }
3899             else
3900             {
3901                 if (pos->uNonPawnCount[FLIP(uColor)][BISHOP] - 
3902                     pos->uWhiteSqBishopCount[FLIP(uColor)])
3903                 {
3904                     EVAL_TERM(uColor,
3905                               KNIGHT,
3906                               c,
3907                               pos->iScore[uColor],
3908                               -(i / 2),
3909                               "not safe from enemy B");
3910                 }
3911             }
3912         }
3913     } 
3914     else // not outposted
3915     {
3916         //
3917         // Still good to be close to the enemy king.
3918         //
3919         i = KNIGHT_KING_TROPISM_BONUS[uDist];
3920         EVAL_TERM(uColor,
3921                   KNIGHT,
3922                   c,
3923                   pos->iReducedMaterialDownScaler[uColor],
3924                   i,
3925                   "[scaled] enemy king tropism");
3926     }
3927     
3928     //
3929     // Give a bonus for blockading an enemy backward pawn.  Note:
3930     // we also reward pieces for blocking enemy passers in the
3931     // passer code.
3932     //
3933     cSquare = c + 16 * g_iAhead[uColor];
3934     bb = pHash->bbStationaryPawns[FLIP(uColor)];
3935     if (bb & COOR_TO_BB(cSquare))
3936     {
3937         ASSERT(pos->rgSquare[cSquare].pPiece);
3938         ASSERT(IS_PAWN(pos->rgSquare[cSquare].pPiece));
3939         EVAL_TERM(uColor,
3940                   KNIGHT,
3941                   c,
3942                   pos->iScore[uColor],
3943                   KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[uColor][RANK(c)],
3944                   "blockades enemy pawn");
3945     }
3946
3947     //
3948     // A knight with an open file behind it is good.
3949     // 
3950     uPawnFile = FILE(c) + 1;
3951     EVAL_TERM(uColor,
3952               KNIGHT,
3953               c,
3954               pos->iScore[uColor],
3955               ((pHash->uCountPerFile[uColor][uPawnFile] == 0) *
3956                KNIGHT_ON_INTERESTING_SQUARE_BY_RANK[uColor][RANK(c)]),
3957               "open file behind");
3958     
3959     //
3960     // Do mobilility and piece relevance.  Also update attack tables.
3961     //
3962     uMobilitySquares = 0;
3963     u = 0;
3964     ASSERT(g_iNDeltas[u] != 0);
3965     do
3966     {
3967         cSquare = c + g_iNDeltas[u];
3968         if (IS_ON_BOARD(cSquare))
3969         {
3970             //
3971             // Always update the attack bits
3972             //
3973             ASSERT((cSquare + 8) == (cSquare | 8));
3974             pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uMinor = 1;
3975
3976             //
3977             // See what we hit
3978             //
3979             p = pos->rgSquare[cSquare].pPiece;
3980             pFun = NMobJumpTable[uColor][p];
3981             if (pFun != _AnythingToFriendNoXray)
3982             {
3983                 (void)(*pFun)(pos,
3984                               cSquare,
3985                               &uMobilitySquares,
3986                               NULL);
3987             }
3988
3989             //
3990             // IDEA: bonus for hitting friendly pawn?
3991             //
3992         }
3993         u++;
3994     }
3995     while(g_iNDeltas[u] != 0);
3996     ASSERT(uMobilitySquares >= 0);
3997     ASSERT(uMobilitySquares <= 8);
3998     EVAL_TERM(uColor,
3999               KNIGHT,
4000               c,
4001               pos->iScore[uColor],
4002               KNIGHT_MOBILITY_BY_COUNT[uMobilitySquares],
4003               "knight mobility");
4004     if (uMobilitySquares == 0)
4005     {
4006         pos->cTrapped[uColor] = c;
4007     }
4008     ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4009     ASSERT((uMobilitySquares & 0x80000000) == 0);
4010     pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor], 
4011                                      uMobilitySquares);
4012 }
4013
4014 static void
4015 _EvalRook(IN OUT POSITION *pos, 
4016           IN COOR c, 
4017           IN PAWN_HASH_ENTRY *pHash)
4018 /**
4019
4020 Routine description:
4021
4022 Parameters:
4023
4024     IN POSITION *pos,
4025     IN COOR c,
4026     IN PAWN_HASH_ENTRY *pHash,
4027
4028 Return value:
4029
4030     FLAG
4031
4032 **/
4033 {
4034     static const PMOBILITY_HELPER RMobJumpTable[2][14] = 
4035     {
4036         {// (black)
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)
4051         },
4052         {// (white)
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)
4067         },
4068     };
4069
4070     PIECE p;
4071     PIECE pFriendRook;
4072     ULONG uPawnFile = FILE(c) + 1;
4073     ULONG uColor;
4074     ULONG u;
4075     ULONG uCurrentMobility;
4076     ULONG uMaxMobility;
4077     ULONG uTotalMobility;
4078     COOR cSquare;
4079     BITBOARD bb;
4080     ULONG uBit;
4081     PMOBILITY_HELPER pFun;
4082     SCORE i;
4083     
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));
4089     pos->cPiece = c;
4090     
4091     //
4092     // Reward being on a half open or full open file.
4093     //
4094     if (0 == pHash->uCountPerFile[uColor][uPawnFile])
4095     {
4096         u = FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
4097         if (0 == pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
4098         {
4099             //
4100             // Full open
4101             //
4102             EVAL_TERM(uColor,
4103                       ROOK,
4104                       c,
4105                       pos->iScore[uColor],
4106                       ROOK_ON_FULL_OPEN_BY_DIST_FROM_EKING[u],
4107                       "on full open");
4108         }
4109         else
4110         {
4111             //
4112             // Half open, no friendly, just enemy.
4113             //
4114             EVAL_TERM(uColor,
4115                       ROOK,
4116                       c,
4117                       pos->iScore[uColor],
4118                       ROOK_ON_HALF_OPEN_WITH_ENEMY_BY_DIST_FROM_EKING[u],
4119                       "on half open");
4120             
4121             //
4122             // Added bonus if the enemy pawn is a passer.
4123             //
4124             bb = pHash->bbPasserLocations[FLIP(uColor)] & BBFILE[FILE(c)];
4125             if (bb)
4126             {
4127                 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4128                 EVAL_TERM(uColor,
4129                           ROOK, 
4130                           c,
4131                           pos->iScore[uColor],
4132                           PASSER_BY_RANK[FLIP(uColor)][RANK(cSquare)] / 4,
4133                           "hassles enemy passer");
4134             }
4135         }
4136     }
4137     else if (0 == pHash->uCountPerFile[FLIP(uColor)][uPawnFile])
4138     {
4139         //
4140         // Half open, no enemy pawn, just a friendly
4141         //
4142         u = FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]);
4143         EVAL_TERM(uColor,
4144                   ROOK,
4145                   c,
4146                   pos->iScore[uColor],
4147                   ROOK_ON_HALF_OPEN_WITH_FRIEND_BY_DIST_FROM_EKING[u],
4148                   "on half open");
4149
4150         //
4151         // See if the friend is a passed pawn and if the rook's in
4152         // front of it or behind it.
4153         //
4154         bb = pHash->bbPasserLocations[uColor] & BBFILE[FILE(c)];
4155         if (bb)
4156         {
4157             //
4158             // IDEA: Rook behind candidates, helpers or sentries is good
4159             // because the file may open soon.
4160             //
4161             while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4162             {
4163                 if (uColor == WHITE) 
4164                 {
4165                     if (cSquare < c)
4166                     {
4167                         EVAL_TERM(WHITE,
4168                                   ROOK,
4169                                   c,
4170                                   pos->iScore[WHITE],
4171                                   ROOK_BEHIND_PASSER_BY_PASSER_RANK[WHITE]
4172                                   [RANK(cSquare)],
4173                                   "behind own passer");
4174                     }
4175                     else
4176                     {
4177                         EVAL_TERM(WHITE,
4178                                   ROOK,
4179                                   c,
4180                                   pos->iScore[WHITE],
4181                                   ROOK_LEADS_PASSER_BY_PASSER_RANK[WHITE]
4182                                   [RANK(cSquare)],
4183                                   "in the way of passer");
4184                     }
4185                 } else {
4186                     ASSERT(uColor == BLACK);
4187                     if (cSquare > c)
4188                     {
4189                         EVAL_TERM(BLACK,
4190                                   ROOK,
4191                                   c,
4192                                   pos->iScore[BLACK],
4193                                   ROOK_BEHIND_PASSER_BY_PASSER_RANK[BLACK]
4194                                   [RANK(cSquare)],
4195                                   "behind own passer");
4196                     }
4197                     else
4198                     {
4199                         EVAL_TERM(BLACK,
4200                                   ROOK,
4201                                   c,
4202                                   pos->iScore[BLACK],
4203                                   ROOK_LEADS_PASSER_BY_PASSER_RANK[BLACK]
4204                                   [RANK(cSquare)],
4205                                   "in the way of passer");
4206                     }
4207                 }
4208             }
4209         }
4210     }
4211     
4212     //
4213     // Look for rooks that are trapping enemy kings.
4214     // 
4215     if (uColor == WHITE) 
4216     {
4217         pFriendRook = WHITE_ROOK;
4218
4219         //
4220         // Rook on 7th/8th rank with an enemy king back there.
4221         // 
4222         if ((c < A6) && (pos->cNonPawns[BLACK][0] < A6))
4223         {
4224             ASSERT(RANK(c) > 6);
4225             ASSERT(RANK(pos->cNonPawns[BLACK][0]) > 6);
4226             
4227             EVAL_TERM(WHITE,
4228                       ROOK,
4229                       c,
4230                       pos->iScore[WHITE],
4231                       ROOK_TRAPPING_EKING,
4232                       "rook trapping enemy king");
4233         }
4234     }
4235     else 
4236     {
4237         pFriendRook = BLACK_ROOK;
4238
4239         //
4240         // Rook on 7th/8th rank with an enemy king back there.
4241         // 
4242         if ((c > H3) && (pos->cNonPawns[WHITE][0] > H3))
4243         {
4244             ASSERT(RANK(c) < 3);
4245             ASSERT(RANK(pos->cNonPawns[WHITE][0]) < 3);
4246             EVAL_TERM(BLACK,
4247                       ROOK,
4248                       c,
4249                       pos->iScore[BLACK],
4250                       ROOK_TRAPPING_EKING,
4251                       "rook trapping enemy king");
4252         }
4253     }
4254     
4255     //
4256     // Rooks increase in value as pawns come off:
4257     // 
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"
4264     // 
4265     EVAL_TERM(uColor,
4266               ROOK,
4267               c,
4268               pos->iScore[uColor],
4269               ROOK_VALUE_AS_PAWNS_COME_OFF[pos->uPawnCount[uColor] +
4270                                            pos->uPawnCount[FLIP(uColor)]],
4271               "increase in value/pawns");
4272     
4273     //
4274     // Rook mobility
4275     //
4276     u = uMaxMobility = uTotalMobility = 0;
4277     ASSERT(g_iRDeltas[u] != 0);
4278     do
4279     {
4280         uCurrentMobility = 0;
4281         uBit = ROOK_BIT;
4282         cSquare = c + g_iRDeltas[u];
4283         
4284         while(IS_ON_BOARD(cSquare))
4285         {
4286             //
4287             // Twiddle our attack table bits.
4288             //
4289             pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
4290             ASSERT((cSquare | 8) == (cSquare + 8));
4291
4292             //
4293             // What did we hit?
4294             //
4295             p = pos->rgSquare[cSquare].pPiece;
4296             pFun = RMobJumpTable[uColor][p];
4297             if (TRUE == (*pFun)(pos,
4298                                 cSquare,
4299                                 &uCurrentMobility,
4300                                 &uBit))
4301             {
4302                 break;
4303             }
4304             cSquare += g_iRDeltas[u];
4305         }
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);
4312         u++;
4313     }
4314     while(g_iRDeltas[u] != 0);
4315     ASSERT(uTotalMobility <= 14);
4316
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);
4321     i /= 8;
4322     EVAL_TERM(uColor,
4323               ROOK,
4324               c,
4325               pos->iScore[uColor],
4326               i,
4327               "rook mobility");
4328     EVAL_TERM(uColor,
4329               ROOK,
4330               c,
4331               pos->iScore[uColor],
4332               ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[uMaxMobility],
4333               "consecutive rook mobility");
4334
4335     ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4336     ASSERT((uTotalMobility & 0x80000000) == 0);
4337     pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor], 
4338                                      uTotalMobility);
4339     if (uTotalMobility < 3)
4340     {
4341         //
4342         // Look for rooks with no mobility who are under attack.  These
4343         // pieces are trapped!
4344         //
4345         if (uTotalMobility == 0)
4346         {
4347             pos->cTrapped[uColor] = c;
4348         }
4349
4350         //
4351         // Rook trapped in the corner by a stupid friendly king?
4352         // 
4353         ASSERT(IS_VALID_COLOR(uColor));
4354         if (uColor == WHITE)
4355         {
4356             ASSERT(IS_ON_BOARD(c));
4357             if (RANK1(c))
4358             {
4359                 cSquare = pos->cNonPawns[WHITE][0];
4360                 ASSERT(IS_ON_BOARD(cSquare));
4361                 if (RANK1(cSquare))
4362                 {
4363                     if (((cSquare > E1) && (c > cSquare)) ||
4364                         ((cSquare < D1) && (c < cSquare)))
4365                     {
4366                         EVAL_TERM(WHITE,
4367                                   ROOK,
4368                                   c,
4369                                   pos->iScore[WHITE],
4370                                   KING_TRAPPING_ROOK,
4371                                   "king trapping rook");
4372                     }
4373                 }
4374             }
4375         }
4376         else 
4377         {
4378             ASSERT(uColor == BLACK);
4379             ASSERT(IS_ON_BOARD(c));
4380             if (RANK8(c))
4381             {
4382                 cSquare = pos->cNonPawns[BLACK][0];
4383                 ASSERT(IS_ON_BOARD(cSquare));
4384                 
4385                 if (RANK8(cSquare))
4386                 {
4387                     if (((cSquare > E8) && (c > cSquare)) ||
4388                         ((cSquare < D8) && (c < cSquare)))
4389                     {
4390                         EVAL_TERM(BLACK,
4391                                   ROOK,
4392                                   c,
4393                                   pos->iScore[BLACK],
4394                                   KING_TRAPPING_ROOK,
4395                                   "king trapping rook");
4396                     }
4397                 }
4398             }
4399         }
4400     } // if low mobility
4401 }
4402
4403
4404 static void
4405 _EvalQueen(IN OUT POSITION *pos, 
4406            IN COOR c, 
4407            IN PAWN_HASH_ENTRY *pHash)
4408 /**
4409
4410 Parameters:
4411
4412     POSITION *pos,
4413     COOR c,
4414     PAWN_HASH_ENTRY *pHash,
4415
4416 Return value:
4417
4418     FLAG
4419
4420 **/
4421 {
4422     static const PMOBILITY_HELPER QMobJumpTable[2][14] = 
4423     {
4424         {
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)
4439         },
4440         {
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)
4455         },
4456     };
4457
4458     PIECE p = pos->rgSquare[c].pPiece;
4459     ULONG uColor;
4460     COOR cSquare;
4461     ULONG uTotalMobility;
4462     ULONG u;
4463     ULONG uBit;
4464     PMOBILITY_HELPER pFun;
4465     ULONG uNearKing = 0;
4466     COOR cKing;
4467
4468     ASSERT(IS_ON_BOARD(c));
4469     ASSERT(p && IS_QUEEN(p));
4470     uColor = GET_COLOR(p);
4471     ASSERT(IS_VALID_COLOR(uColor));
4472     pos->cPiece = c;
4473     cKing = pos->cNonPawns[FLIP(uColor)][0];
4474     ASSERT(IS_ON_BOARD(cKing));
4475     ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
4476     
4477     if ((FALSE == pos->fCastled[uColor]) && (pos->uMinorsAtHome[uColor] > 1))
4478     {
4479         //
4480         // Discourage queen being out too early
4481         // 
4482         if (!RANK1(c) && !RANK8(c))
4483         {
4484             ASSERT(QUEEN_OUT_EARLY[pos->uMinorsAtHome[uColor]] < 0);
4485             ASSERT(pos->uMinorsAtHome[uColor] <= 4);
4486             EVAL_TERM(uColor,
4487                       QUEEN,
4488                       c,
4489                       pos->iScore[uColor],
4490                       QUEEN_OUT_EARLY[pos->uMinorsAtHome[uColor]],
4491                       "queen out too early");
4492         }
4493     }
4494     else
4495     {
4496         //
4497         // Encourage enemy king tropism
4498         //
4499         u = DISTANCE(c, cKing);
4500         ASSERT((u <= 7) && (u > 0));
4501         EVAL_TERM(uColor,
4502                   QUEEN,
4503                   c,
4504                   pos->iScore[uColor],
4505                   QUEEN_KING_TROPISM[u],
4506                   "enemy king tropism");
4507     }
4508
4509     //
4510     // Do queen mobility
4511     //
4512     uTotalMobility = 0;
4513     u = 0;
4514     ASSERT(g_iQKDeltas[u] != 0);
4515     do
4516     {
4517         uBit = QUEEN_BIT;
4518         cSquare = c + g_iQKDeltas[u];
4519         while(IS_ON_BOARD(cSquare))
4520         {
4521             //
4522             // Toggle attack table bits.
4523             //
4524             pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
4525             
4526             //
4527             // What did we hit?
4528             //
4529             p = pos->rgSquare[cSquare].pPiece;
4530             uNearKing += (DISTANCE(cSquare, cKing) <= 1);
4531             pFun = QMobJumpTable[uColor][p];
4532             if (TRUE == (*pFun)(pos,
4533                                 cSquare,
4534                                 &uTotalMobility,
4535                                 &uBit))
4536             {
4537                 break;
4538             }
4539             cSquare += g_iQKDeltas[u];
4540         }
4541         u++;
4542     }
4543     while(g_iQKDeltas[u] != 0);
4544
4545     ASSERT(uTotalMobility <= 27);
4546     EVAL_TERM(uColor,
4547               QUEEN,
4548               c,
4549               pos->iScore[uColor],
4550               QUEEN_MOBILITY_BY_SQUARES[uTotalMobility],
4551               "queen mobility");
4552
4553     //
4554     // Look for queens with no mobility who are under attack.  These
4555     // pieces are trapped!
4556     //
4557     if (uTotalMobility == 0)
4558     {
4559         pos->cTrapped[uColor] = c;
4560     }
4561     ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
4562     ASSERT((uTotalMobility & 0x80000000) == 0);
4563     pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor], 
4564                                      uTotalMobility);
4565
4566     //
4567     // If queen points near enemy king, that's a good thing too.
4568     //
4569     ASSERT(uNearKing <= 6);
4570     EVAL_TERM(uColor,
4571               QUEEN,
4572               c,
4573               pos->iScore[uColor],
4574               (uNearKing * QUEEN_ATTACKS_SQ_NEXT_TO_KING),
4575               "pointing near enemy K");
4576 }
4577
4578 static void
4579 _EvalKing(IN OUT POSITION *pos, 
4580           IN const COOR c, 
4581           IN const PAWN_HASH_ENTRY *pHash)
4582 /**
4583
4584 Routine description:
4585
4586 Parameters:
4587
4588     POSITION *pos,
4589     COOR c,
4590     PAWN_HASH_ENTRY *pHash,
4591
4592 Return value:
4593
4594     FLAG
4595
4596 **/
4597 {
4598     PIECE p;
4599     ULONG uColor, ufColor;
4600     COOR cSquare;
4601     ULONG u, v;
4602     ULONG uCounter;
4603     BITV bvAttack;
4604     BITV bvXray;
4605     BITV bvDefend;
4606     BITV bvPattern = 0;
4607     ULONG uFlightSquares;
4608     BITBOARD bb;
4609     SCORE i;
4610     SCORE iKingScore = 0;
4611
4612     static ULONG KingFlightDefects[9] =
4613     {
4614         +4, +2, +1, 0, 0, 0, 0, 0, 0
4615     };
4616     
4617     static ULONG KingStormingPawnDefects[8] =
4618     {
4619         +0, +4, +3, +1, +0, +0, +0, +0
4620     };
4621
4622     static ULONG KingFileDefects[3] = 
4623     {
4624         +2, +1, +0
4625     };
4626
4627     static INT KingSafetyDeltas[11] = 
4628     {
4629         -17, -16, -15,
4630         -1,        +1,
4631         +15, +16, +17, -2, +2, 0
4632     };
4633     
4634     static ULONG EmptyAttackedSquare[2][11] = 
4635     {
4636         { 
4637             1, 1, 1,
4638             1,    1,
4639             2, 2, 2, 1, 1, 0
4640         },
4641         {
4642             2, 2, 2,
4643             1,    1,
4644             1, 1, 1, 1, 1, 0
4645         },
4646     };
4647
4648     static ULONG EmptyUnattackedSquare[2][11] = 
4649     {
4650         { 
4651             0, 0, 0,
4652             0,    0,
4653             1, 1, 1, 0, 0, 0
4654         },
4655         {
4656             1, 1, 1,
4657             0,    0,
4658             0, 0, 0, 0, 0, 0
4659         },
4660     };
4661     
4662     static ULONG OccupiedAttackedSquare[2] = 
4663     {
4664         1,
4665         2
4666     };
4667    
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));
4674     
4675     u = pos->uNonPawnMaterial[ufColor];
4676     ASSERT(u >= VALUE_KING);
4677     if (u < DO_KING_SAFETY_THRESHOLD)
4678     {
4679         u = 0;
4680         ASSERT(g_iQKDeltas[u] != 0);
4681         do
4682         {
4683             cSquare = c + g_iQKDeltas[u];
4684             if (IS_ON_BOARD(cSquare))
4685             {
4686                 pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uKing = 1;
4687             }
4688             u++;
4689         }
4690         while(g_iQKDeltas[u] != 0);
4691         goto skip_safety;
4692     }
4693
4694     // Prepare to do king safety
4695     uCounter = (u >= KEEP_KING_AT_HOME_THRESHOLD) * 
4696         KING_INITIAL_COUNTER_BY_LOCATION[uColor][c];
4697 #ifdef EVAL_DUMP
4698     Trace("%s Initial KS Counter: %u\n", COLOR_NAME(uColor), uCounter);
4699 #endif
4700
4701     uCounter += pos->uPiecesPointingAtKing[uColor] / 2;
4702 #ifdef EVAL_DUMP
4703     Trace("%s KS Counter after pieces pointing: %u\n", 
4704           COLOR_NAME(uColor), uCounter);
4705 #endif
4706     uFlightSquares = 0;
4707     u = 0;
4708     ASSERT(KingSafetyDeltas[u] != 0);
4709     do
4710     {
4711         cSquare = c + KingSafetyDeltas[u];
4712         if (IS_ON_BOARD(cSquare))
4713         {
4714             p = pos->rgSquare[cSquare].pPiece;
4715             
4716             cSquare |= 8;
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;
4721             
4722             if (bvAttack != 0)
4723             {
4724                 bvPattern |= (bvAttack | bvXray);
4725                 if (bvXray || (bvAttack & (bvAttack - 1)))
4726                 {
4727                     bvDefend &= ~8;
4728                 }
4729                 if (IS_EMPTY(p))
4730                 {
4731                     ASSERT(u < 11);
4732                     uCounter += EmptyAttackedSquare[uColor][u];
4733                 }
4734                 else
4735                 {
4736                     uCounter += 
4737                         OccupiedAttackedSquare[OPPOSITE_COLORS(p, uColor)];
4738                 }
4739                 uCounter += (bvDefend == 0);
4740             }
4741             else
4742             {
4743                 uCounter += (bvXray != 0);
4744                 ASSERT(u < 11);
4745                 uCounter += EmptyUnattackedSquare[uColor][u];
4746                 ASSERT((IS_EMPTY(p) == 0) || (IS_EMPTY(p) == 1));
4747                 uFlightSquares += ((IS_EMPTY(p)) && (u < 8));
4748             }
4749         }
4750         u++;
4751     }
4752     while(KingSafetyDeltas[u] != 0);
4753 #ifdef EVAL_DUMP
4754     Trace("%s KS Counter post-squares: %u\n", COLOR_NAME(uColor), uCounter);
4755 #endif
4756
4757     if (IS_ON_BOARD(c - 1))
4758     {
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));
4763
4764         // Note: open rook files are worse than open interior files
4765         uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
4766
4767         bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
4768         if (bb)
4769         {
4770             if (uColor == WHITE)
4771             {
4772                 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4773             }
4774             else
4775             {
4776                 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4777             }
4778             ASSERT(IS_ON_BOARD(cSquare));
4779             uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4780         }
4781     }
4782     
4783     u = FILE(c) + 1;
4784     v = (pHash->uCountPerFile[WHITE][u] > 0) +
4785         (pHash->uCountPerFile[BLACK][u] > 0);
4786     ASSERT((v >= 0) && (v <= 2));
4787
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];
4791     if (bb)
4792     {
4793         if (uColor == WHITE)
4794         {
4795             cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4796         }
4797         else
4798         {
4799             cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4800         }
4801         ASSERT(IS_ON_BOARD(cSquare));
4802         uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4803     }
4804
4805     if (IS_ON_BOARD(c + 1))
4806     {
4807         ASSERT((FILE(c + 1) + 1) == (u + 1));
4808         u += 1;
4809         v = (pHash->uCountPerFile[WHITE][u] > 0) +
4810             (pHash->uCountPerFile[BLACK][u] > 0);
4811         ASSERT((v >= 0) && (v <= 2));
4812         
4813         // Note: open rook files are worse than open interior files
4814         uCounter += (KingFileDefects[v] + ((v < 2) && ((u == 1) || (u == 8))));
4815         
4816         bb = pHash->bbPawnLocations[ufColor] & BBFILE[u - 1];
4817         if (bb)
4818         {
4819             if (uColor == WHITE)
4820             {
4821                 cSquare = CoorFromBitBoardRank1ToRank8(&bb);
4822             }
4823             else
4824             {
4825                 cSquare = CoorFromBitBoardRank8ToRank1(&bb);
4826             }
4827             ASSERT(IS_ON_BOARD(cSquare));
4828             uCounter += KingStormingPawnDefects[DISTANCE(cSquare, c)];
4829         }
4830     }    
4831 #ifdef EVAL_DUMP
4832     Trace("%s KS Counter post-open file/stormers: %u\n", COLOR_NAME(uColor), 
4833           uCounter);
4834 #endif
4835
4836     bvPattern >>= 3;
4837     ASSERT(bvPattern >= 0);
4838     ASSERT(bvPattern < 32);
4839     v = KING_COUNTER_BY_ATTACK_PATTERN[bvPattern];
4840     uCounter += v;
4841 #ifdef EVAL_DUMP
4842     Trace("%s KS Counter post-attack pattern: %u\n", COLOR_NAME(uColor), 
4843           uCounter);
4844 #endif
4845         
4846     ASSERT(uFlightSquares <= 8);
4847     uCounter += KingFlightDefects[uFlightSquares] * (v > 1);
4848 #ifdef EVAL_DUMP
4849     Trace("%s KS Counter post-flight sq: %u\n", COLOR_NAME(uColor), uCounter);
4850 #endif
4851
4852     //
4853     // Note: can't use pos->iReducedMaterialDownScaler here because we
4854     // are scaling it based on the _other_ side's material.
4855     //
4856     uCounter = MINU(uCounter, 41);
4857     i = KING_SAFETY_BY_COUNTER[uCounter];
4858     i *= REDUCED_MATERIAL_DOWN_SCALER[pos->uArmyScaler[ufColor]];
4859     i /= 8;
4860     EVAL_TERM(uColor,
4861               KING,
4862               c,
4863               iKingScore,
4864               i,
4865               "king safety");
4866
4867     //
4868     // Bonus for castling / penalty for loss of castle.  Also, if side has
4869     // not yet castled, be concerned with undeveloped minor pieces.
4870     //
4871     if (FALSE == pos->fCastled[uColor])
4872     {
4873         if (pos->uNonPawnCount[uColor][0] > 4)
4874         {
4875             ASSERT(pos->uMinorsAtHome[uColor] <= 4);
4876             EVAL_TERM(uColor,
4877                      0,
4878                      ILLEGAL_COOR,
4879                      pos->iScore[uColor],
4880                      UNDEVELOPED_MINORS_IN_OPENING[pos->uMinorsAtHome[uColor]],
4881                      "development");
4882             if (uColor == BLACK)
4883             {
4884                 EVAL_TERM(BLACK,
4885                           KING,
4886                           c,
4887                           iKingScore,
4888                           (KING_MISSING_ONE_CASTLE_OPTION *
4889                            ((CASTLE_BLACK_SHORT & pos->bvCastleInfo) == 0)),
4890                           "can't castle short");
4891                 EVAL_TERM(BLACK,
4892                           KING,
4893                           c,
4894                           iKingScore,
4895                           (KING_MISSING_ONE_CASTLE_OPTION *
4896                            ((CASTLE_BLACK_LONG & pos->bvCastleInfo) == 0)),
4897                           "can't castle long");
4898             }
4899             else
4900             {
4901                 ASSERT(uColor == WHITE);
4902                 EVAL_TERM(WHITE,
4903                           KING,
4904                           c,
4905                           iKingScore,
4906                           (KING_MISSING_ONE_CASTLE_OPTION *
4907                            ((CASTLE_WHITE_SHORT & pos->bvCastleInfo) == 0)),
4908                           "can't castle short");
4909                 EVAL_TERM(WHITE,
4910                           KING,
4911                           c,
4912                           iKingScore,
4913                           (KING_MISSING_ONE_CASTLE_OPTION *
4914                            ((CASTLE_WHITE_LONG & pos->bvCastleInfo) == 0)),
4915                           "can't castle long");
4916             }
4917         }
4918     }
4919     
4920  skip_safety:
4921     //
4922     // Special code for kings in the endgame
4923     // 
4924     u = pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0];
4925     if (u < 8)
4926     {
4927         //
4928         // Encourage kings to come to the center
4929         //
4930         i = KING_TO_CENTER[c];
4931         EVAL_TERM(uColor,
4932                   KING,
4933                   c,
4934                   iKingScore,
4935                   i,
4936                   "centralize king");
4937
4938         //
4939         // Kings in front of passers in the late endgame are strong...
4940         // 
4941         cSquare = FILE(c);
4942         bb = pHash->bbPasserLocations[uColor] & 
4943             (BBADJACENT_FILES[cSquare] | BBFILE[cSquare]);
4944         if (bb)
4945         {
4946             while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4947             {
4948                 if (DISTANCE(cSquare, c) == 1)
4949                 {
4950                     ASSERT(abs((INT)FILE(c) - (INT)FILE(cSquare)) <= 1);
4951                     ASSERT(abs((INT)RANK(c) - (INT)RANK(cSquare)) <= 1);
4952                     
4953                     i = 2;
4954                     i += SUPPORTED_PASSER_BY_RANK[uColor][RANK(cSquare)];
4955                     switch(uColor)
4956                     {
4957                         case WHITE:
4958                             i += 8 * (c < (cSquare - 1));
4959                             break;
4960                             
4961                         case BLACK:
4962                             i += 8 * (c > (cSquare + 1));
4963                             break;
4964                     }
4965                     EVAL_TERM(uColor,
4966                               KING,
4967                               c,
4968                               iKingScore,
4969                               i,
4970                               "supporting own passer");
4971                 }
4972             }
4973         }
4974         
4975         //
4976         // Detect kings way out of the action in KP endgames:
4977         // 
4978         // 8/8/1p6/p6k/P3K3/8/1P6/8 w - - 0 11
4979         // 
4980         if ((u == 2) && (uColor == WHITE))
4981         {
4982             i = 0;
4983             bb = (pHash->bbPawnLocations[WHITE] |
4984                   pHash->bbPawnLocations[BLACK]);
4985             while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
4986             {
4987                 i += (DISTANCE(cSquare, pos->cNonPawns[BLACK][0]) -
4988                       DISTANCE(cSquare, pos->cNonPawns[WHITE][0]));
4989             }
4990             EVAL_TERM(WHITE,
4991                       KING,
4992                       c,
4993                       iKingScore,
4994                       i * 12,
4995                       "in/out of \"action\"");
4996         }
4997     }
4998     pos->iScore[uColor] += iKingScore;
4999     pos->iTempScore = iKingScore;
5000 }
5001
5002
5003 FLAG
5004 EvalPasserRaces(IN OUT POSITION *pos, 
5005                 IN PAWN_HASH_ENTRY *pHash)
5006 /**
5007
5008 Routine description:
5009
5010     Determine if one side has a pawn that is unstoppable.
5011
5012     This is broken for positions like:
5013
5014 Parameters:
5015
5016     POSITION *pos,
5017     PAWN_HASH_ENTRY *pHash,
5018
5019 Return value:
5020
5021     void
5022
5023 **/
5024 {
5025     BITBOARD bb[2];
5026     ULONG uColor;
5027     int d1;
5028     COOR cQueen;
5029     COOR cKing, c;
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]))
5039     {
5040         return(FALSE);
5041     }
5042     ASSERT((pos->uNonPawnCount[WHITE][0] == 1) ||
5043            (pos->uNonPawnCount[BLACK][0] == 1))
5044     FOREACH_COLOR(uColor)
5045     {
5046         if (pos->uNonPawnCount[FLIP(uColor)][0] == 1)
5047         {
5048             d1 = 16 * g_iAhead[uColor];
5049             ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
5050             if (bb[uColor])
5051             {
5052                 while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(
5053                                       &(bb[uColor]))))
5054                 {
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))
5062                     {
5063                         // TODO: something clever here about protected pawns
5064                         continue;
5065                     }
5066
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)))
5073                     {
5074                         uPawnDist--;
5075                     }
5076                     ASSERT((uPawnDist >= 1) && (uPawnDist <= 6));
5077                     
5078                     uKingDist = DISTANCE(cKing, cQueen);
5079                     if (uKingDist > 0) 
5080                     {
5081                         uKingDist -= (pos->uToMove == FLIP(uColor));
5082                     }
5083                     ASSERT((uKingDist >= 0) && (uPawnDist <= 7));
5084                     
5085                     if (uPawnDist < uKingDist)
5086                     {
5087                         uRacerDist[uColor] = MINU(uRacerDist[uColor],
5088                                                   uPawnDist);
5089                     }
5090                     
5091                     cKing = pos->cNonPawns[uColor][0];
5092                     ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
5093                     ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uColor);
5094                     
5095                     uFriendDist = DISTANCE(cKing, cQueen);
5096                     if ((uFriendDist <= 1) && (DISTANCE(cKing, c) <= 1))
5097                     {
5098                         if (FILE(c) != FILE(cKing))
5099                         {
5100                             uRacerDist[uColor] = MINU(uRacerDist[uColor],
5101                                                       uPawnDist);
5102                         }
5103                         else if ((FILE(cKing) != A) &&
5104                                  (FILE(cKing) != H))
5105                         {
5106                             uRacerDist[uColor] = MINU(uRacerDist[uColor],
5107                                                       (uPawnDist + 1));
5108                         }
5109                     }
5110                     fDontCountMeOut[uColor] = TRUE;
5111                     
5112                     // 
5113                     // TODO: winning connected passers
5114                     //
5115                 }
5116             }
5117         }
5118     }
5119
5120     if ((uRacerDist[WHITE] < uRacerDist[BLACK]) && 
5121         (FALSE == fDontCountMeOut[BLACK]))
5122     {
5123         EVAL_TERM(WHITE,
5124                   PAWN,
5125                   ILLEGAL_COOR,
5126                   pos->iScore[WHITE],
5127                   RACER_WINS_RACE - uRacerDist[WHITE] * 4,
5128                   "winning racer pawn");
5129         return(TRUE);
5130     }
5131     else if ((uRacerDist[BLACK] < uRacerDist[WHITE]) &&
5132              (FALSE == fDontCountMeOut[WHITE]))
5133     {
5134         EVAL_TERM(BLACK,
5135                   PAWN,
5136                   ILLEGAL_COOR,
5137                   pos->iScore[BLACK],
5138                   RACER_WINS_RACE - uRacerDist[BLACK] * 4,
5139                   "winning racer pawn");
5140         return(TRUE);
5141     }
5142     return(FALSE);
5143 }
5144
5145
5146 static void 
5147 _EvalPassers(IN OUT POSITION *pos, 
5148              IN PAWN_HASH_ENTRY *pHash)
5149 /**
5150
5151 Routine description:
5152
5153 Parameters:
5154
5155     POSITION *pos,
5156     PAWN_HASH_ENTRY *pHash,
5157
5158 Return value:
5159
5160     void
5161
5162 **/
5163 {
5164     ULONG u;
5165     ULONG uColor;
5166     COOR c;
5167     COOR cSquare;
5168     BITBOARD bb;
5169     PIECE p;
5170     SCORE i;
5171     ULONG uNumPassers[2] = { 0, 0 };
5172     int d1;
5173
5174     ASSERT(pHash->bbPasserLocations[WHITE] |
5175            pHash->bbPasserLocations[BLACK]);
5176     
5177     FOREACH_COLOR(uColor)
5178     {
5179         bb = pHash->bbPasserLocations[uColor];
5180         if (bb != 0)
5181         {
5182             uNumPassers[uColor] = CountBits(bb);
5183             ASSERT(uNumPassers[uColor] > 0);
5184             d1 = 16 * g_iAhead[uColor];
5185             ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
5186             
5187             while(IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bb)))
5188             {
5189                 //
5190                 // Consider the control of the square in front of the passer
5191                 //
5192                 cSquare = c + d1;
5193                 ASSERT(IS_ON_BOARD(cSquare));
5194                 u = _WhoControlsSquareFast(pos, cSquare);
5195                 if (u == FLIP(uColor))
5196                 {
5197                     EVAL_TERM(uColor,
5198                               PAWN,
5199                               c,
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");
5204                 }
5205                 else if (u == (ULONG)-1)
5206                 {
5207                     p = pos->rgSquare[cSquare].pPiece;
5208                     if (!IS_EMPTY(p) && (OPPOSITE_COLORS(p, uColor)))
5209                     {
5210                         ASSERT(GET_COLOR(p) != uColor);
5211                         EVAL_TERM(uColor,
5212                                   PAWN,
5213                                   c,
5214                                   pos->iScore[uColor],
5215                                   -(PASSER_BY_RANK[uColor][RANK(c)] / 4),
5216                                   "enemy occupies sq ahead");
5217                     }
5218                 }
5219 #ifdef DEBUG
5220                 else
5221                 {
5222                     ASSERT(u == uColor);
5223                 }
5224 #endif
5225                 
5226                 //
5227                 // Consider distance from friend king / enemy king
5228                 //
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)))) {
5234                     // 
5235                     // The enemy king is ahead of the passer
5236                     //
5237                     i += FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
5238                 }
5239                 else
5240                 {
5241                     // 
5242                     // The enemy king is behind the passer
5243                     //
5244                     i += 10 + DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
5245                 }
5246                 i *= PASSER_MATERIAL_UP_SCALER[pos->uArmyScaler[FLIP(uColor)]];
5247                 i /= 8;
5248                 EVAL_TERM(uColor,
5249                           PAWN,
5250                           c,
5251                           pos->iScore[uColor],
5252                           i,
5253                           "passer distance to kings");
5254                 
5255                 //
5256                 // If a side is a piece down then the other side's passers
5257                 // are even more dangerous.
5258                 //
5259                 if (pos->uNonPawnCount[uColor][0] > 
5260                     pos->uNonPawnCount[FLIP(uColor)][0])
5261                 {
5262                     i = (PASSER_BY_RANK[uColor][RANK(c)] / 2);
5263                     EVAL_TERM(uColor,
5264                               PAWN,
5265                               c,
5266                               pos->iScore[uColor],
5267                               i,
5268                               "passer and piece up");
5269                 }
5270
5271                 //
5272                 // TODO: For connected passers vs KR, consult the oracle
5273                 //
5274             }
5275         }
5276     }
5277     
5278     //
5279     // Game stage bonus
5280     // 
5281     u = pos->uArmyScaler[BLACK];
5282     EVAL_TERM(WHITE,
5283               PAWN,
5284               ILLEGAL_COOR,
5285               pos->iScore[WHITE],
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];
5290     EVAL_TERM(BLACK,
5291               PAWN,
5292               ILLEGAL_COOR,
5293               pos->iScore[BLACK],
5294               uNumPassers[BLACK] * PASSER_BONUS_AS_MATERIAL_COMES_OFF[u],
5295               "passer value material");
5296     ASSERT(PASSER_BONUS_AS_MATERIAL_COMES_OFF[u] >= 0);
5297 }
5298
5299
5300 static void 
5301 _EvalBadTrades(IN OUT POSITION *pos)
5302 /**
5303
5304 Routine description:
5305
5306 Parameters:
5307
5308     POSITION *pos,
5309
5310 Return value:
5311
5312     void
5313
5314 **/
5315 {
5316     ULONG uAhead, uBehind;
5317     ULONG uMagnitude;
5318     
5319     //
5320     // See who is ahead
5321     //
5322     ASSERT(pos->uNonPawnMaterial[WHITE] != pos->uNonPawnMaterial[BLACK]);
5323     uAhead = (pos->uNonPawnMaterial[WHITE] > pos->uNonPawnMaterial[BLACK]);
5324     uBehind = FLIP(uAhead);
5325 #ifdef DEBUG
5326     if (pos->uNonPawnMaterial[WHITE] > pos->uNonPawnMaterial[BLACK])
5327     {
5328         ASSERT(uAhead == WHITE);
5329         ASSERT(uBehind == BLACK);
5330     }
5331     else
5332     {
5333         ASSERT(pos->uNonPawnMaterial[BLACK] > pos->uNonPawnMaterial[WHITE]);
5334         ASSERT(uAhead == BLACK);
5335         ASSERT(uBehind == WHITE);
5336     }
5337 #endif
5338     uMagnitude = ((pos->uNonPawnMaterial[uAhead] + 
5339                    pos->uNonPawnCount[uAhead][0] * 128) -
5340                   (pos->uNonPawnMaterial[uBehind] +
5341                    pos->uNonPawnCount[uBehind][0] * 128));
5342     uMagnitude /= 128;
5343     uMagnitude -= (uMagnitude != 0);
5344     ASSERT(!(uMagnitude & 0x80000000));
5345     uMagnitude = MINU(2, uMagnitude);
5346     ASSERT(uMagnitude <= 2);
5347
5348     //
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.
5357     //
5358     EVAL_TERM(uAhead,
5359               0,
5360               ILLEGAL_COOR,
5361               pos->iScore[uAhead],
5362               ((pos->uPawnCount[uAhead] != 0) *
5363                TRADE_PIECES[uMagnitude][pos->uNonPawnCount[uBehind][0]]),
5364               "trade pieces");
5365     ASSERT(TRADE_PIECES[uMagnitude][pos->uNonPawnCount[uBehind][0]] > 0);
5366     EVAL_TERM(uAhead,
5367               0,
5368               ILLEGAL_COOR,
5369               pos->iScore[uAhead],
5370               DONT_TRADE_PAWNS[uMagnitude][pos->uPawnCount[uAhead]],
5371               "don't trade pawns");
5372 }
5373
5374 static void
5375 _EvalLookForDanger(IN OUT SEARCHER_THREAD_CONTEXT *ctx)
5376 /**
5377
5378 Routine description:
5379
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.
5387     
5388     Note: This routine only considers side to move.
5389     
5390     Also Note: this routine does not find pawns that are en prise, only
5391     pieces.
5392
5393 Parameters:
5394
5395     SEARCHER_THREAD_CONTEXT *ctx
5396
5397 Return value:
5398
5399     void
5400     
5401 **/
5402 {
5403     COOR c;
5404     ULONG u;
5405     POSITION *pos = &ctx->sPosition;
5406     ULONG uSide = pos->uToMove;
5407 #ifdef DEBUG
5408     PIECE p;
5409 #endif
5410
5411     for (u = 1;
5412          u < pos->uNonPawnCount[uSide][0];
5413          u++)
5414     {
5415         c = pos->cNonPawns[uSide][u];
5416 #ifdef DEBUG
5417         ASSERT(IS_ON_BOARD(c));
5418         p = pos->rgSquare[c].pPiece;
5419         ASSERT(p);
5420         ASSERT(GET_COLOR(p) == uSide);
5421         ASSERT(!IS_PAWN(p));
5422 #endif
5423         if (_WhoControlsSquareFast(pos, c) == FLIP(uSide))
5424         {
5425             StoreEnprisePiece(pos, c);
5426         }
5427     }
5428 }
5429
5430
5431 static void 
5432 _EvalTrappedPieces(IN OUT SEARCHER_THREAD_CONTEXT *ctx)
5433 /**
5434
5435 Routine description:
5436
5437 Parameters:
5438
5439     SEARCHER_THREAD_CONTEXT *ctx
5440
5441 Return value:
5442
5443     static void
5444
5445 **/
5446 {
5447     COOR c;
5448     ULONG uColor;
5449     POSITION *pos = &ctx->sPosition;
5450 #ifdef DEBUG
5451     PIECE p;
5452 #endif
5453
5454     FOREACH_COLOR(uColor)
5455     {
5456         c = pos->cTrapped[uColor];
5457         if (IS_ON_BOARD(c))
5458         {
5459             if (_WhoControlsSquareFast(pos, c) == FLIP(uColor))
5460             {
5461 #ifdef DEBUG
5462                 p = pos->rgSquare[c].pPiece;
5463                 ASSERT(p);
5464                 ASSERT(!IS_PAWN(p));
5465                 ASSERT(GET_COLOR(p) == uColor);
5466 #endif
5467                 if (OPPOSITE_COLORS(uColor, pos->uToMove))
5468                 {
5469                     StoreEnprisePiece(pos, c);
5470                 }
5471                                 else
5472                                 {
5473                     StoreTrappedPiece(pos, c);
5474                                 }
5475             }
5476         }
5477     }
5478 }
5479
5480
5481 static void
5482 _EvalBishopPairs(IN POSITION *pos)
5483 /*++
5484
5485 Routine description:
5486
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.
5489
5490 Parameters:
5491
5492     IN POSITION *pos - position
5493
5494 Return value:
5495
5496     static void
5497
5498 --*/
5499 {
5500     ULONG uPawnSum = pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK];
5501     FLAG fPair;
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));
5510     EVAL_TERM(BLACK,
5511               0,
5512               ILLEGAL_COOR,
5513               pos->iScore[BLACK],
5514               BISHOP_PAIR[fPair][uPawnSum],
5515               "bishop pair");
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));
5523     EVAL_TERM(WHITE,
5524               0,
5525               ILLEGAL_COOR,
5526               pos->iScore[WHITE],
5527               BISHOP_PAIR[fPair][uPawnSum],
5528               "bishop pair");
5529 }
5530
5531
5532
5533 SCORE 
5534 Eval(IN SEARCHER_THREAD_CONTEXT *ctx, 
5535      IN SCORE iAlpha, 
5536      IN SCORE iBeta)
5537 /**
5538
5539 Routine description:
5540
5541 Parameters:
5542
5543     SEARCHER_THREAD_CONTEXT *ctx,
5544     SCORE iAlpha,
5545     SCORE iBeta,
5546
5547 Return value:
5548
5549     SCORE
5550
5551 **/
5552 {
5553     static const PEVAL_HELPER JumpTable[] =
5554     {
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)
5569     };
5570     ULONG uDefer[2][2];
5571     COOR cDefer[2][2][10];
5572     POSITION *pos = &(ctx->sPosition);
5573     SCORE iScoreForSideToMove;
5574     SCORE iAlphaMargin, iBetaMargin;
5575     PAWN_HASH_ENTRY *pHash;
5576     COOR c;
5577     PIECE p;
5578     ULONG u;
5579     ULONG uColor;
5580     BITBOARD bb;
5581     FLAG fDeferred;
5582 #ifdef EVAL_TIME
5583     UINT64 uTimer = SystemReadTimeStampCounter();
5584 #endif
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));
5591
5592     pos->uMinMobility[BLACK] = pos->uMinMobility[WHITE] = 100;
5593     pos->cTrapped[BLACK] = pos->cTrapped[WHITE] = ILLEGAL_COOR;
5594     
5595 #ifdef EVAL_HASH
5596     //
5597     // Check the eval hash
5598     // 
5599     iScoreForSideToMove = ProbeEvalHash(ctx);
5600     if (iScoreForSideToMove != INVALID_SCORE) 
5601     {
5602         INC(ctx->sCounters.tree.u64EvalHashHits);
5603         goto end;
5604     }
5605 #endif
5606
5607     pos->iScore[BLACK] = 
5608         (pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]);
5609     pos->iScore[WHITE] = 
5610         (pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]);
5611 #ifdef EVAL_DUMP
5612     EvalTraceClear();
5613     Trace("Material:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5614 #endif
5615
5616     //
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!!!
5622     //
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]));
5629 #ifdef EVAL_DUMP
5630     Trace("After pawns:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5631 #endif
5632     
5633     //
5634     // Look for won passers races.  Note: This code cannot trust the
5635     // state of the attack tables yet!
5636     //
5637     if ((pos->uNonPawnCount[WHITE][0] == 1) || 
5638         (pos->uNonPawnCount[BLACK][0] == 1))
5639     {
5640         (void)EvalPasserRaces(pos, pHash);
5641 #ifdef EVAL_DUMP
5642         Trace("After passer races:\n%d\t\t%d\n", pos->iScore[WHITE], 
5643               pos->iScore[BLACK]);
5644 #endif
5645     }
5646     
5647     //
5648     // Bad trade code.  Right.  Note: this code cannot trust the state
5649     // of the attack tables...
5650     //
5651     if (pos->uNonPawnMaterial[WHITE] != pos->uNonPawnMaterial[BLACK])
5652     {
5653         _EvalBadTrades(pos);
5654 #ifdef EVAL_DUMP
5655         Trace("After bad trades:\n%d\t\t%d\n", pos->iScore[WHITE], 
5656               pos->iScore[BLACK]);
5657 #endif
5658     }
5659
5660     //
5661     // Bishop pairs.  Again... Note: this code cannot trust the state
5662     // of the attack tables.
5663     //
5664     _EvalBishopPairs(pos);
5665 #ifdef EVAL_DUMP
5666     Trace("After bishop pair bonus:\n%d\t\t%d\n", pos->iScore[WHITE], 
5667           pos->iScore[BLACK]);
5668 #endif
5669
5670 #ifdef LAZY_EVAL
5671     //
5672     // Compute an estimate of the score for the side to move based on the
5673     // eval terms we have already considered:
5674     // 
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
5680     //     6. Bishop pairs
5681     //
5682     iScoreForSideToMove = (pos->iScore[pos->uToMove] - 
5683                            pos->iScore[FLIP(pos->uToMove)]);
5684     ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
5685
5686     //
5687     // Eval has not considered several potentially large terms:
5688     // 
5689     //     1. Piece positional components (such as mobility, trapped)
5690     //     2. King safety penalties
5691     //     3. Other miscellaneous bonuses/penalties
5692     //
5693     // We build two "margins" to account for these components of the
5694     // score.
5695     // 
5696     iAlphaMargin = iBetaMargin = (50 + (SCORE)ctx->uPositional);
5697     
5698     //
5699     // If (score + alpha_margin) is already > alpha -OR-
5700     //    (score - beta_margin) is already < beta 
5701     // 
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.
5705     // 
5706     if ((iScoreForSideToMove + iAlphaMargin < iAlpha) ||
5707         (iScoreForSideToMove - iBetaMargin > iBeta))
5708     {
5709         //
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
5713         // pawns.
5714         // 
5715         _QuicklyEstimateKingSafetyTerm(pos, &iAlphaMargin, &iBetaMargin);
5716         _QuicklyEstimatePasserBonuses(pos, pHash, &iAlphaMargin, &iBetaMargin);
5717         
5718         if ((iScoreForSideToMove + iAlphaMargin <= iAlpha) ||
5719             (iScoreForSideToMove - iBetaMargin >= iBeta))
5720         {
5721             ctx->uPositional = MINU(200, ctx->uPositional);
5722             INC(ctx->sCounters.tree.u64LazyEvals);
5723             goto end;
5724         }
5725     }
5726 #endif
5727
5728     //
5729     // If we have to clear/populate the attack table, do it now that
5730     // we know we aren't taking a lazy exit.
5731     //
5732     if (TRUE == fDeferred)
5733     {
5734         _PopulatePawnAttackBits(pos);
5735     }
5736     
5737     //
5738     // Pre-compute some common terms used in per-piece evals:
5739     //
5740     // This is a scaler based on the size of the army for each side.
5741     //
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;
5756
5757     //
5758     // This is a "position is closed|open" number.
5759     //
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);
5765
5766     //
5767     // Evaluate individual pieces.
5768     //
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];
5775          u++)
5776     {
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));
5783
5784         if (p & 0x4)
5785         {
5786             ASSERT(IS_BISHOP(p) || IS_KNIGHT(p));
5787             
5788             //
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.
5795             //
5796             ASSERT(JumpTable[p]);
5797             (void)(JumpTable[p])(pos, c, pHash);
5798 #ifdef EVAL_DUMP
5799             Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5800                   pos->iScore[WHITE], pos->iScore[BLACK]);
5801 #endif
5802         }
5803         else
5804         {
5805             ASSERT(IS_ROOK(p) || IS_QUEEN(p));
5806             cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
5807         }
5808     }
5809     
5810     uColor = FLIP(uColor);
5811     ASSERT(uColor != pos->uToMove);
5812     for (u = 1;
5813          u < pos->uNonPawnCount[uColor][0];
5814          u++)
5815     {
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));
5822         if (p & 0x4)
5823         {
5824             //
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!
5831             //
5832             ASSERT(JumpTable[p]);
5833             (void)(JumpTable[p])(pos, c, pHash);
5834 #ifdef EVAL_DUMP
5835             Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5836                   pos->iScore[WHITE], pos->iScore[BLACK]);
5837 #endif
5838         }
5839         else
5840         {
5841             ASSERT(IS_ROOK(p) || IS_QUEEN(p));
5842             cDefer[uColor][IS_QUEEN(p)][uDefer[uColor][IS_QUEEN(p)]++] = c;
5843         }
5844     }
5845     
5846     //
5847     // Evaluate any rook(s) for side on move then for side not on move.
5848     // 
5849     uColor = FLIP(uColor);
5850     for (u = 0;
5851          u < uDefer[uColor][0];
5852          u++)
5853     {
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);
5859 #ifdef EVAL_DUMP
5860         p = BLACK_ROOK | uColor;
5861         Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5862               pos->iScore[WHITE], pos->iScore[BLACK]);
5863 #endif
5864     }
5865     
5866     uColor = FLIP(uColor);
5867     for (u = 0;
5868          u < uDefer[uColor][0];
5869          u++)
5870     {
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);
5876 #ifdef EVAL_DUMP
5877         p = BLACK_ROOK | uColor;
5878         Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5879               pos->iScore[WHITE], pos->iScore[BLACK]);
5880 #endif
5881     }
5882
5883     //
5884     // Evaluate any queen(s) for side on move then for side not on move.
5885     // 
5886     uColor = FLIP(uColor);
5887     for (u = 0;
5888          u < uDefer[uColor][1];
5889          u++)
5890     {
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);
5896 #ifdef EVAL_DUMP
5897         p = BLACK_ROOK | uColor;
5898         Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5899               pos->iScore[WHITE], pos->iScore[BLACK]);
5900 #endif
5901     }
5902     
5903     uColor = FLIP(uColor);
5904     for (u = 0;
5905          u < uDefer[uColor][1];
5906          u++)
5907     {
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);
5913 #ifdef EVAL_DUMP
5914         p = BLACK_ROOK | uColor;
5915         Trace("After %s:\n%d\t\t%d\n", PieceAbbrev(p),
5916               pos->iScore[WHITE], pos->iScore[BLACK]);
5917 #endif
5918     }
5919     
5920     //
5921     // Evaluate the two kings last.
5922     //
5923     c = pos->cNonPawns[BLACK][0];
5924 #ifdef DEBUG
5925     ASSERT(IS_ON_BOARD(c));
5926     p = pos->rgSquare[c].pPiece;
5927     ASSERT(IS_VALID_PIECE(p));
5928     ASSERT(GET_COLOR(p) == BLACK);
5929     ASSERT(IS_KING(p));
5930     ASSERT(JumpTable[p]);
5931 #endif
5932     _EvalKing(pos, c, pHash);
5933     ctx->sPlyInfo[ctx->uPly].iKingScore[BLACK] = pos->iTempScore;
5934 #ifdef EVAL_DUMP
5935     Trace("After *k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5936 #endif
5937     
5938     c = pos->cNonPawns[WHITE][0];
5939 #ifdef DEBUG
5940     ASSERT(IS_ON_BOARD(c));
5941     p = pos->rgSquare[c].pPiece;
5942     ASSERT(IS_VALID_PIECE(p));
5943     ASSERT(GET_COLOR(p) == WHITE);
5944     ASSERT(IS_KING(p));
5945     ASSERT(JumpTable[p]);
5946 #endif
5947     _EvalKing(pos, c, pHash);
5948     ctx->sPlyInfo[ctx->uPly].iKingScore[WHITE] = pos->iTempScore;
5949 #ifdef EVAL_DUMP
5950     Trace("After .k:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
5951 #endif
5952     
5953     //
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.
5957     //
5958     bb = (pHash->bbPasserLocations[WHITE] | pHash->bbPasserLocations[BLACK]);
5959     if (0 != bb)
5960     {
5961         _EvalPassers(pos, pHash);
5962 #ifdef EVAL_DUMP
5963         Trace("After passers:\n%d\t\t%d\n", pos->iScore[WHITE], 
5964               pos->iScore[BLACK]);
5965 #endif
5966     }
5967
5968     //
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.
5973     //
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);
5978
5979     //
5980     // B over N in the endgame with 2 pawn wings.
5981     // 
5982     if ((pos->uNonPawnCount[WHITE][0] <= 2) &&
5983         (pos->uNonPawnCount[BLACK][0] <= 2))
5984     {
5985         if ((pos->uNonPawnCount[WHITE][BISHOP] > 0) &&
5986             (pos->uNonPawnCount[BLACK][BISHOP] > 0))
5987         {
5988             if ((pos->uNonPawnCount[BLACK][0] == 2) &&
5989                 (pos->uNonPawnCount[WHITE][0] == 2))
5990             {
5991                 ASSERT(pos->uNonPawnCount[BLACK][BISHOP] == 1);
5992                 ASSERT(pos->uNonPawnCount[WHITE][BISHOP] == 1);
5993                 if (pos->uWhiteSqBishopCount[BLACK] +
5994                     pos->uWhiteSqBishopCount[WHITE] == 1)
5995                 {
5996                     pos->iScore[WHITE] /= 2;
5997                     pos->iScore[BLACK] /= 2;
5998                 }
5999             }        
6000         }
6001         else
6002         {
6003             //
6004             // At least one side has no bishop.  Look for positions
6005             // with two pawn wings where having a bishop is an
6006             // advantage.
6007             //
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))
6016             {
6017                 if ((pos->uNonPawnCount[BLACK][BISHOP] == 0) &&
6018                     (pos->uNonPawnCount[WHITE][BISHOP] > 0))
6019                 {
6020                     EVAL_TERM(WHITE,
6021                               BISHOP,
6022                               0x88,
6023                               pos->iScore[WHITE],
6024                               BISHOP_OVER_KNIGHT_IN_ENDGAME *
6025                               pos->uNonPawnCount[WHITE][BISHOP],
6026                               "endgame w/ 2 pawn flanks");
6027                 }
6028                 else if ((pos->uNonPawnCount[BLACK][BISHOP] > 0) &&
6029                          (pos->uNonPawnCount[WHITE][BISHOP] == 0))
6030                 {
6031                     EVAL_TERM(BLACK,
6032                               BISHOP,
6033                               0x88,
6034                               pos->iScore[BLACK],
6035                               BISHOP_OVER_KNIGHT_IN_ENDGAME *
6036                               pos->uNonPawnCount[BLACK][BISHOP],
6037                               "endgame w/ 2 pawn flanks");
6038                 }
6039             }
6040         }
6041 #ifdef EVAL_DUMP
6042         Trace("After BOOC / BvsN:\n%d\t\t%d\n", 
6043               pos->iScore[WHITE], pos->iScore[BLACK]);
6044 #endif
6045     }
6046
6047     //
6048     // Roll in the reduced material down scaler terms.
6049     //
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;
6060
6061     //
6062     // Almost done
6063     //
6064     iScoreForSideToMove = (pos->iScore[pos->uToMove] - 
6065                            pos->iScore[FLIP(pos->uToMove)]);
6066 #ifdef EVAL_DUMP
6067     Trace("At the end:\n%d\t\t%d\n", pos->iScore[WHITE], 
6068           pos->iScore[BLACK]);
6069 #endif
6070     
6071     //
6072     // TODO: detect and discourage blocked positions?
6073     //
6074
6075     //
6076     // TODO: drive the score towards zero as we approach a 50 move w/o
6077     // progress draw.
6078     //
6079
6080     //
6081     // Adjust dynamic positional component.
6082     //
6083     iAlphaMargin = abs(pos->iMaterialBalance[pos->uToMove] - iScoreForSideToMove);
6084     if ((ULONG)iAlphaMargin > ctx->uPositional)
6085     {
6086         ctx->uPositional = (ULONG)iAlphaMargin;
6087     }
6088     else
6089     {
6090         ctx->uPositional -= (ctx->uPositional - (ULONG)iAlphaMargin) / 4;
6091         ctx->uPositional = MAXU(ctx->uPositional, VALUE_PAWN);
6092     }
6093     g_Options.iLastEvalScore = iScoreForSideToMove;
6094     
6095 #ifdef EVAL_TIME
6096     ctx->sCounters.tree.u64CyclesInEval += (SystemReadTimeStampCounter() - 
6097                                             uTimer);
6098 #endif
6099     INC(ctx->sCounters.tree.u64FullEvals);
6100
6101 #ifdef EVAL_HASH
6102     //
6103     // Store in eval hash.
6104     //
6105     StoreEvalHash(ctx, iScoreForSideToMove);
6106 #endif
6107
6108  end:
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);
6118 }