Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / recogn.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     recogn.c
8
9 Abstract:
10
11     This code is based on an article by Ernst A. Heinz: "Efficient
12     Interior-Node Recognition" * ICCA Journal Volume 21, No. 3, pp
13     156-167 (also "Scalable Search in Computer Chess" pp 65-81).  This
14     code also borrows ideas from Thorsten Greiner's AMY chess program.
15     
16 Author:
17
18     Scott Gasch ([email protected]) 16 Oct 2005
19
20 Revision History:
21
22 **/
23
24 #include "chess.h"
25
26 extern ULONG g_uIterateDepth;
27 static COOR QUEENING_SQUARE_BY_COLOR_FILE[2][8] = 
28
29     { A1, B1, C1, D1, E1, F1, G1, H1 },
30     { A8, B8, C8, D8, E8, F8, G8, H8 } 
31 };
32
33 #define RECOGN_INDEX(w, b) \
34     (((b) | (w)) + (32 * ((w) && (b))))
35
36 typedef ULONG RECOGNIZER(SEARCHER_THREAD_CONTEXT *ctx, SCORE *piScore);
37
38 static RECOGNIZER *g_pRecognizers[64];
39 static BITV g_bvRecognizerAvailable[32];
40
41 static ULONG 
42 _MakeMaterialSig(IN FLAG fPawn, 
43                  IN FLAG fKnight,
44                  IN FLAG fBishop,
45                  IN FLAG fRook, 
46                  IN FLAG fQueen) 
47 /**
48
49 Routine description:
50
51     Make a material signature ULONG out of flags representing the
52     presence of pawns, knights, bishops, rooks, queens on the board.
53
54 Parameters:
55
56     FLAG fPawn,
57     FLAG fKnight,
58     FLAG fBishop,
59     FLAG fRook,
60     FLAG fQueen
61
62 Return value:
63
64     static ULONG
65
66 **/
67 {
68     ULONG x;
69     
70     ASSERT(IS_VALID_FLAG(fPawn));
71     ASSERT(IS_VALID_FLAG(fKnight));
72     ASSERT(IS_VALID_FLAG(fBishop));
73     ASSERT(IS_VALID_FLAG(fRook));
74     ASSERT(IS_VALID_FLAG(fQueen));
75
76     x = fPawn | (fKnight << 1) | (fBishop << 2) | (fRook << 3) | (fQueen << 4);
77     
78     ASSERT((0 <= x) && (x <= 31));
79     return(x);
80 }
81
82
83 #ifdef DEBUG
84
85
86 static FLAG
87 _TablebasesSaySideWins(IN SEARCHER_THREAD_CONTEXT *ctx, 
88                        IN ULONG uSide)
89 {
90     SCORE iScore;
91     if (TRUE == ProbeEGTB(ctx, &iScore))
92     {
93         if (ctx->sPosition.uToMove == uSide) 
94         {
95             return iScore > 0;
96         } 
97         else 
98         {
99             return iScore < 0;
100         }
101     } 
102     return TRUE;
103 }
104
105 static FLAG
106 _TablebasesSayDraw(IN SEARCHER_THREAD_CONTEXT *ctx) 
107 {
108     SCORE iScore;
109     if (TRUE == ProbeEGTB(ctx, &iScore)) 
110     {
111         return iScore == 0;
112     }
113     return TRUE;
114 }
115
116 static FLAG
117 _TablebasesSayDrawOrWin(IN SEARCHER_THREAD_CONTEXT *ctx, 
118                         IN ULONG uSide) 
119 {
120     SCORE iScore;
121     if (TRUE == ProbeEGTB(ctx, &iScore)) 
122     {
123         return ((iScore == 0) || 
124                 ((iScore > 0) && (ctx->sPosition.uToMove == uSide)) ||
125                 ((iScore < 0) && (ctx->sPosition.uToMove != uSide)));
126     }
127     return TRUE;
128 }
129
130
131 static FLAG 
132 _SanityCheckRecognizers(IN SEARCHER_THREAD_CONTEXT *ctx, 
133                         IN SCORE iScore, 
134                         IN ULONG uVal) {
135     ULONG uToMove = ctx->sPosition.uToMove;
136     switch(uVal) {
137         case UNRECOGNIZED:
138             return TRUE;
139         case RECOGN_EXACT:
140             if (iScore == 0) {
141                 return _TablebasesSayDraw(ctx);
142             } else if (iScore > 0) {
143                 return _TablebasesSaySideWins(ctx, uToMove);
144             } else {
145                 ASSERT(iScore < 0);
146                 return _TablebasesSaySideWins(ctx, !uToMove);
147             }
148         case RECOGN_LOWER:
149             if (iScore == 0) {
150                 return _TablebasesSayDrawOrWin(ctx, uToMove);
151             } else if (iScore > 0) {
152                 return _TablebasesSaySideWins(ctx, uToMove);
153             } else {
154                 ASSERT(iScore < 0);
155                 return _TablebasesSaySideWins(ctx, !uToMove);
156             }
157         case RECOGN_UPPER:
158             if (iScore == 0) {
159                 return _TablebasesSayDrawOrWin(ctx, !uToMove);
160             } else if (iScore > 0) {
161                 return _TablebasesSayDrawOrWin(ctx, !uToMove);
162             } else {
163                 ASSERT(iScore < 0);
164                 return _TablebasesSaySideWins(ctx, !uToMove);
165             }
166         default:
167                         ASSERT(FALSE);
168                         return FALSE;
169     }
170 }
171
172 static FLAG 
173 _NothingBut(IN POSITION *pos, 
174             IN PIECE p, 
175             IN ULONG uColor)
176 /**
177
178 Routine description:
179
180     Support routine to assert that nothing but the piece bits
181     enumerated in parameter p are present in the position pos for side
182     uColor.
183
184 Parameters:
185
186     POSITION *pos,
187     PIECE p,
188     ULONG uColor
189
190 Return value:
191
192     #ifdef DEBUG
193 static FLAG
194
195 **/
196 {
197     static PIECE q[] = { KNIGHT, BISHOP, ROOK, QUEEN };
198     ULONG u;
199    
200     if (!(p & PAWN))
201     {
202         if (pos->uPawnCount[uColor] > 0) return(FALSE);
203     }
204
205     for (u = 0; u < ARRAY_LENGTH(q); u++)
206     {
207         if (!(p & q[u]))
208         {
209             if (pos->uNonPawnCount[uColor][q[u]] > 0) return(FALSE);
210         }
211     }
212     return(TRUE);
213 }
214 #endif
215
216 static ULONG 
217 _RecognizeKK(IN SEARCHER_THREAD_CONTEXT *ctx, 
218              IN OUT SCORE *piScore)
219 /**
220
221 Routine description:
222
223     Encode the knowledge that two lone kings on the board are a draw.
224
225 Parameters:
226
227     POSITION *pos,
228     SCORE *piScore
229
230 Return value:
231
232     static ULONG
233
234 **/
235 {
236     *piScore = 0;
237     return(RECOGN_EXACT);
238 }
239
240 static ULONG 
241 _RecognizeKBK(IN SEARCHER_THREAD_CONTEXT *ctx, 
242               IN OUT SCORE *piScore)
243 /**
244
245 Routine description:
246
247     Attempt to recognize KB*KB+ positions.
248
249 Parameters:
250
251     POSITION *pos,
252     SCORE *piScore
253
254 Return value:
255
256     static ULONG
257
258 **/
259 {
260     ULONG uStrong;
261     ULONG uBishops;
262     COOR cWeakKing;
263     ULONG u;
264     ULONG uAdjacent;
265     POSITION *pos = &ctx->sPosition;
266     
267     ASSERT((pos->uNonPawnCount[WHITE][0] <= 3) &&
268            (pos->uNonPawnCount[BLACK][0] <= 3));
269     ASSERT(_NothingBut(pos, BISHOP, WHITE));
270     ASSERT(_NothingBut(pos, BISHOP, BLACK));
271
272     //
273     // Recognize KBKB as a draw unless there's a cornered king (in
274     // which case it may be a mate-in-1)
275     // 
276     if ((pos->uNonPawnCount[WHITE][0] == 2) &&
277         (pos->uNonPawnCount[BLACK][0] == 2))
278     {
279         if ((CORNER_DISTANCE(pos->cNonPawns[WHITE][0]) != 0) &&
280             (CORNER_DISTANCE(pos->cNonPawns[BLACK][0]) != 0))
281         {
282             *piScore = 0;
283             return(RECOGN_EXACT);
284         }
285     }
286     
287     //
288     // Otherwise we want to deal with KB+ vs lone K.  KBKBB etc are
289     // too hard to recognize.
290     // 
291     if ((pos->uNonPawnCount[WHITE][0] != 1) &&
292         (pos->uNonPawnCount[BLACK][0] != 1))
293     {
294         return(UNRECOGNIZED);
295     }
296     
297     //
298     // If we get here then one side has no pieces (except the king).
299     // 
300     uStrong = BLACK;
301     if (pos->uNonPawnCount[WHITE][0] > 1)
302     {
303         uStrong = WHITE;
304     }
305     ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
306     ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
307
308     //
309     // KB vs K is a draw, KB+ vs K is still a draw if all bishops are the
310     // same color.
311     // 
312     uBishops = pos->uNonPawnCount[uStrong][BISHOP];
313     if ((uBishops == 1) ||
314         (pos->uWhiteSqBishopCount[uStrong] == 0) ||
315         (pos->uWhiteSqBishopCount[uStrong] == uBishops))
316     {
317         *piScore = 0;
318         return(RECOGN_EXACT);
319     }
320     
321     //
322     // If we get here the strong side has more than one bishop and has
323     // at least one bishop on each color.
324     // 
325
326     //
327     // If the weak king is next to a strong side piece, fail to
328     // recognize since the weak king may take the bishop with the
329     // move.  Note: we allow the weak king to be adjacent to up to one
330     // enemy bishop as long as it's the strong side's turn to move.
331     // 
332     cWeakKing = pos->cNonPawns[FLIP(uStrong)][0];
333     ASSERT(DISTANCE(cWeakKing, pos->cNonPawns[uStrong][0]) > 1);
334     uAdjacent = 0;
335     for (u = 1; u < pos->uNonPawnCount[uStrong][0]; u++)
336     {
337         uAdjacent += DISTANCE(cWeakKing, pos->cNonPawns[uStrong][u] == 1);
338     }
339     if (uAdjacent > 1)
340     {
341         return(UNRECOGNIZED);
342     }
343
344     //
345     // If it's the weak side's turn and the strong king is close
346     // enough that the weak side may be stalemated, fail to recognize.
347     //
348     if (pos->uToMove != uStrong)
349     {
350         ASSERT(pos->uToMove == FLIP(uStrong));
351         if (uAdjacent == 1)
352         {
353             return(UNRECOGNIZED);
354         }
355         
356         ASSERT(IS_ON_BOARD(pos->cNonPawns[uStrong][0]));
357         ASSERT(IS_KING(pos->rgSquare[pos->cNonPawns[uStrong][0]].pPiece));
358         u = DISTANCE(cWeakKing, pos->cNonPawns[uStrong][0]);
359         ASSERT(u != 1);
360         if ((u == 2) && (ON_EDGE(cWeakKing)))
361         {
362             return(UNRECOGNIZED);
363         }
364     }
365     
366     //
367     // This is a recognized win for the strong side.  Compute a score
368     // that encourages cornering the weak king and making progress
369     // towards a checkmate.
370     // 
371     *piScore = (pos->iMaterialBalance[uStrong] + VALUE_QUEEN - 
372                 (u * 16) - (CORNER_DISTANCE(cWeakKing) * 32));
373     ASSERT(IS_VALID_SCORE(*piScore));
374     if (pos->uToMove != uStrong)
375     {
376         *piScore *= -1;
377         return(RECOGN_UPPER);
378     }
379     return(RECOGN_LOWER);
380 }
381
382 static ULONG 
383 _RecognizeKNK(IN SEARCHER_THREAD_CONTEXT *ctx, 
384               IN OUT SCORE *piScore)
385 /**
386
387 Routine description:
388
389     Recognize KN*KN+ positions.
390
391 Parameters:
392
393     POSITION *pos,
394     SCORE *piScore
395
396 Return value:
397
398     static ULONG
399
400 **/
401 {
402     POSITION *pos = &ctx->sPosition;
403     ULONG uStrong;
404
405     ASSERT((pos->uNonPawnCount[WHITE][0] <= 3) &&
406            (pos->uNonPawnCount[BLACK][0] <= 3));
407     ASSERT(_NothingBut(pos, KNIGHT, WHITE));
408     ASSERT(_NothingBut(pos, KNIGHT, BLACK));
409     
410     //
411     // KNKN is a draw unless someone has a K in the corner (in which case,
412     // with the friend knight in the way, there's a possible mate)
413     // 
414     if ((pos->uNonPawnCount[WHITE][0] == 2) &&
415         (pos->uNonPawnCount[BLACK][0] == 2))
416     {
417         if ((CORNER_DISTANCE(pos->cNonPawns[WHITE][0]) != 0) &&
418             (CORNER_DISTANCE(pos->cNonPawns[BLACK][0]) != 0))
419         {
420             *piScore = 0;
421             return(RECOGN_EXACT);
422         }
423         return(UNRECOGNIZED);
424     }
425     
426     //
427     // KNNKN etc... unrecognized.  Heinz says "exceptional wins possible for
428     // any side by mates in seven or less moves."  TODO: add this knowledge.
429     // 
430     if ((pos->uNonPawnCount[WHITE][0] != 1) ||
431         (pos->uNonPawnCount[BLACK][0] != 1))
432     {
433         return(UNRECOGNIZED);
434     }
435     
436     //
437     // If we get here somebody has no pieces (except a lone king).
438     // 
439     uStrong = WHITE;
440     if (pos->uNonPawnCount[BLACK][0] > 1)
441     {
442         uStrong = BLACK;
443     }
444     ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
445     ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
446
447     //
448     // Call KNNK a draw unless the weak K is on the edge of the board
449     // where a checkmate is possible (e.g. 8/8/8/8/8/N2N4/4K3/2k5 b - -)
450     // Everything else in here is a draw.
451     //
452     ASSERT(pos->uNonPawnCount[uStrong][0] < 4);
453     if (ON_EDGE(pos->cNonPawns[FLIP(uStrong)][0])) 
454     {
455         return(UNRECOGNIZED);
456     }
457     *piScore = 0;
458     return(RECOGN_EXACT);
459 }
460
461
462 static ULONG 
463 _RecognizeKBNK(IN SEARCHER_THREAD_CONTEXT *ctx, 
464                IN OUT SCORE *piScore)
465 /**
466
467 Routine description:
468
469 Parameters:
470
471     POSITION *pos,
472     SCORE *piScore
473
474 Return value:
475
476     static ULONG
477
478 **/
479 {
480     ULONG uStrong;
481     COOR cWeakKing;
482     COOR cKnight;
483     ULONG u;
484     ULONG uDist;
485     ULONG uAdjacent;
486     POSITION *pos = &ctx->sPosition;
487
488     ASSERT((pos->uNonPawnCount[WHITE][0] <= 3) &&
489            (pos->uNonPawnCount[BLACK][0] <= 3));
490     ASSERT(_NothingBut(pos, BISHOP | KNIGHT, WHITE));
491     ASSERT(_NothingBut(pos, BISHOP | KNIGHT, BLACK));
492     
493     if ((pos->uNonPawnCount[WHITE][0] > 1) &&
494         (pos->uNonPawnCount[BLACK][0] > 1))
495     {
496         //
497         // Do not recognize stuff like KNNKB or KNKBB etc...
498         // 
499         if (pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0] > 4)
500         {
501             return(UNRECOGNIZED);
502         }
503         
504         //
505         // This is KNKB; unless someone's king is on the edge,
506         // recognize a draw.
507         // 
508         ASSERT((pos->uNonPawnCount[WHITE][0] == 2) &&
509                (pos->uNonPawnCount[BLACK][0] == 2));
510         if (ON_EDGE(pos->cNonPawns[WHITE][0]) ||
511             ON_EDGE(pos->cNonPawns[BLACK][0]))
512         {
513             return(UNRECOGNIZED);
514         }
515         *piScore = 0;
516         return(RECOGN_EXACT);
517     }
518
519     //
520     // If we get here we are in a KBNK endgame.
521     // 
522     uStrong = WHITE;
523     if (pos->uNonPawnCount[BLACK][0] > 1)
524     {
525         uStrong = BLACK;
526     }
527     ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
528     ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
529     cWeakKing = pos->cNonPawns[FLIP(uStrong)][0];
530     ASSERT(IS_ON_BOARD(cWeakKing));
531     ASSERT(IS_KING(pos->rgSquare[cWeakKing].pPiece));
532
533     //
534     // Don't recognize anything where the N is in a corner near the
535     // lone king.  It's possible for the lone king to trap it there
536     // thus drawing the game.
537     //
538     cKnight = pos->cNonPawns[uStrong][KNIGHT];
539     if ((CORNER_DISTANCE(cKnight) == 0) &&
540         (DISTANCE(cWeakKing, cKnight) == 1))
541     {
542         return(UNRECOGNIZED);
543     }
544     
545     //
546     // Don't recognize anything if the weak king is next to a strong side's
547     // piece.
548     // 
549     uAdjacent = 0;
550     for (u = 1; u < pos->uNonPawnCount[uStrong][0]; u++)
551     {
552         uAdjacent = (DISTANCE(pos->cNonPawns[uStrong][u], cWeakKing) == 1);
553     }
554     if (!uAdjacent) 
555     {
556         return(UNRECOGNIZED);
557     }
558
559     //
560     // Don't recognize if the two kings are close enough to each other
561     // that there might be a stalemate if the weak side is on move and
562     // on the edge.
563     // 
564     if (pos->uToMove != uStrong)
565     {
566         ASSERT(pos->uToMove == FLIP(uStrong));
567         if (uAdjacent == 1)
568         {
569             return(UNRECOGNIZED);
570         }
571
572         ASSERT(IS_ON_BOARD(pos->cNonPawns[uStrong][0]));
573         ASSERT(IS_KING(pos->rgSquare[pos->cNonPawns[uStrong][0]].pPiece));
574         u = DISTANCE(cWeakKing, pos->cNonPawns[uStrong][0]);
575         ASSERT(u != 1);
576         if ((u == 2) && (ON_EDGE(cWeakKing)))
577         {
578             return(UNRECOGNIZED);
579         }
580     }
581
582     //
583     // Calculate a score that grabs the search's attention and makes
584     // progress towards driving the weak king to the correct corner to
585     // mate him.
586     // 
587     if (pos->uWhiteSqBishopCount[uStrong] > 0)
588     {
589         uDist = WHITE_CORNER_DISTANCE(cWeakKing);
590     }
591     else
592     {
593         uDist = BLACK_CORNER_DISTANCE(cWeakKing);
594     }
595     ASSERT((0 <= uDist) && (uDist <= 7));
596     
597     *piScore = (pos->iMaterialBalance[uStrong] + (7 * VALUE_PAWN)
598                 - (uDist * 32) - (u * 16));
599     ASSERT(IS_VALID_SCORE(*piScore));
600     if (pos->uToMove != uStrong)
601     {
602         *piScore *= -1;
603         return(RECOGN_UPPER);
604     }
605     return(RECOGN_LOWER);
606 }
607
608
609 static ULONG 
610 _RecognizeKNKP(IN SEARCHER_THREAD_CONTEXT *ctx, 
611                IN OUT SCORE *piScore)
612 /**
613
614 Routine description:
615
616     Recognize KN+KP+ positions.
617
618 Parameters:
619
620     POSITION *pos,
621     SCORE *piScore
622
623 Return value:
624
625     static ULONG
626
627 **/
628 {
629     ULONG uStrong;
630     POSITION *pos = &ctx->sPosition;
631     
632     ASSERT((pos->uNonPawnCount[WHITE][0] <= 3) &&
633            (pos->uNonPawnCount[BLACK][0] <= 3));
634     ASSERT(_NothingBut(pos, PAWN | KNIGHT, WHITE));
635     ASSERT(_NothingBut(pos, PAWN | KNIGHT, BLACK));
636
637     //
638     // Call the side with knight(s) "strong"
639     //
640     uStrong = WHITE;
641     if (pos->uNonPawnCount[BLACK][0] > 1)
642     {
643         uStrong = BLACK;
644     }
645     ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
646     ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
647
648     //
649     // Don't recognize KNNKP or KNKP with K on edge
650     // 
651     if ((pos->uNonPawnCount[uStrong][KNIGHT] > 2) ||
652         (ON_EDGE(pos->cNonPawns[FLIP(uStrong)][0])))
653     {
654         return(UNRECOGNIZED);
655     }
656
657     //
658     // This is at least a draw for the side with the pawn(s) and at
659     // best a draw for the side with the knight(s)
660     // 
661     *piScore = 0;
662     if (pos->uToMove == uStrong)
663     {
664         return(RECOGN_UPPER);
665     }
666     return(RECOGN_LOWER);
667 }
668
669
670 static ULONG
671 _RecognizeKBKP(IN SEARCHER_THREAD_CONTEXT *ctx, 
672                IN OUT SCORE *piScore)
673 /**
674
675 Routine description:
676
677     Recognize KB+P*KP+ positions including knowledge about "wrong color
678     bishop(s)".
679
680 Parameters:
681
682     POSITION *pos,
683     SCORE *piScore
684
685 Return value:
686
687     static ULONG
688
689 **/
690 {
691     ULONG uStrong;
692     BITBOARD bb;
693     ULONG u;
694     COOR c;
695     COOR cWeakKing;
696     POSITION *pos = &ctx->sPosition;
697
698     ASSERT((pos->uNonPawnCount[WHITE][0] <= 3) &&
699            (pos->uNonPawnCount[BLACK][0] <= 3));
700     ASSERT(_NothingBut(pos, PAWN | BISHOP, WHITE));
701     ASSERT(_NothingBut(pos, PAWN | BISHOP, BLACK));
702
703     //
704     // Call the side with bishop(s) "strong"
705     //
706     uStrong = WHITE;
707     if (pos->uNonPawnCount[BLACK][BISHOP] > 0)
708     {
709         uStrong = BLACK;
710     }
711     ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
712     ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
713
714     cWeakKing = pos->cNonPawns[FLIP(uStrong)][0];
715     ASSERT(IS_ON_BOARD(cWeakKing));
716     ASSERT(IS_KING(pos->rgSquare[cWeakKing].pPiece));
717
718     //
719     // Construct a strong side bitboard of pawn locations
720     // 
721     bb = 0ULL;
722     for (u = 0; u < pos->uPawnCount[uStrong]; u++)
723     {
724         c = pos->cPawns[uStrong][u];
725         ASSERT(IS_ON_BOARD(c));
726         bb |= COOR_TO_BB(c);
727     }
728     
729     if ((pos->uNonPawnCount[BLACK][0] + pos->uPawnCount[BLACK] > 1) &&
730         (pos->uNonPawnCount[WHITE][0] + pos->uPawnCount[WHITE] > 1))
731     {
732         //
733         // Neither side has a lone king.  This is either KBKP+ or
734         // KBP+KP+.
735         // 
736         if (pos->uPawnCount[uStrong] > 0)
737         {
738             //
739             // Strong side can maybe take an adjacent pawn and survive the
740             // bad bishop.
741             // 
742             if (uStrong == pos->uToMove)
743             {
744                 return(UNRECOGNIZED);
745             }
746             
747             //
748             // Make sure the strong side has the right color bishop
749             // for his pawns.
750             //
751             if (uStrong == WHITE)
752             {
753                 if (!(bb & ~BBFILE[A]) &&
754                     (pos->uWhiteSqBishopCount[WHITE] == 0) &&
755                     (DISTANCE(cWeakKing, A8) <= 1))
756                 {
757                     goto at_best_draw_for_strong;
758                 }
759                 
760                 if (!(bb & ~BBFILE[H]) &&
761                     (pos->uWhiteSqBishopCount[WHITE] == 
762                      pos->uNonPawnCount[WHITE][BISHOP]) &&
763                     (DISTANCE(cWeakKing, H8) <= 1))
764                 {
765                     goto at_best_draw_for_strong;
766                 }
767             }
768             else
769             {
770                 if (!(bb & ~BBFILE[A]) &&
771                     (pos->uWhiteSqBishopCount[BLACK] == 
772                      pos->uNonPawnCount[BLACK][BISHOP]) &&
773                     (DISTANCE(cWeakKing, A1) <= 1))
774                 {
775                     goto at_best_draw_for_strong;
776                 }
777                 
778                 if (!(bb & ~BBFILE[H]) &&
779                     (pos->uWhiteSqBishopCount[BLACK] == 0) &&
780                     (DISTANCE(cWeakKing, H1) <= 1))
781                 {
782                     goto at_best_draw_for_strong;
783                 }
784             }
785             return(UNRECOGNIZED);
786         }
787         else
788         {
789             //
790             // Strong side has no pawns... there's a mate-in-1 here if
791             // the weak king is stuck in the corner.
792             //
793             if ((pos->uNonPawnCount[uStrong][BISHOP] > 1) ||
794                 (CORNER_DISTANCE(cWeakKing) == 0))
795             {
796                 return(UNRECOGNIZED);
797             }
798             goto at_best_draw_for_strong;
799         }
800     } 
801     else 
802     {
803         //
804         // KBPK: make sure the bishop is the right color.  This time
805         // there is no need to check for on-move.
806         // 
807         ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
808         ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
809
810         if (uStrong == WHITE)
811         {
812             if (!(bb & ~BBFILE[A]) &&
813                 (pos->uWhiteSqBishopCount[WHITE] == 0) &&
814                 (DISTANCE(cWeakKing, A8) <= 1))
815             {
816                 goto draw;
817             }
818             if (!(bb & ~BBFILE[H]) &&
819                 (pos->uWhiteSqBishopCount[WHITE] ==
820                  pos->uNonPawnCount[WHITE][BISHOP]) &&
821                 (DISTANCE(cWeakKing, H8) <= 1))
822             {
823                 goto draw;
824             }
825         } 
826         else 
827         {
828             if (!(bb & ~BBFILE[A]) &&
829                 (pos->uWhiteSqBishopCount[BLACK] == 
830                  pos->uNonPawnCount[BLACK][BISHOP]) &&
831                 (DISTANCE(cWeakKing, A1) <= 1))
832             {
833                 goto draw;
834             }
835             if (!(bb & ~BBFILE[H]) &&
836                 (pos->uWhiteSqBishopCount[BLACK] == 0) &&
837                 (DISTANCE(cWeakKing, H1) <= 1))
838             {
839                 goto draw;
840             }
841         }
842         return(UNRECOGNIZED);
843     }
844 #ifdef DEBUG
845     UtilPanic(SHOULD_NOT_GET_HERE, 
846               NULL, NULL, NULL, NULL,
847               __FILE__, __LINE__);
848 #endif
849
850  at_best_draw_for_strong:
851     *piScore = 0;
852     if (pos->uToMove == uStrong)
853     {
854         return(RECOGN_UPPER);
855     }
856     return(RECOGN_LOWER);
857
858  draw:
859     *piScore = 0;
860     return(RECOGN_EXACT);
861 }
862
863 static void
864 _GetPassersCriticalSquares(IN ULONG uColor,
865                            IN COOR cPawn, 
866                            IN OUT COOR *cSquare)
867 /**
868
869 Routine description:
870
871     In an effort to classify KPK positions I read some stuff in
872     "Pandolfini's Endgame Course" about critical squares.  A critical
873     square of a passed pawn is one that, if occupied by the friendly
874     king, is sufficient to queen that pawn by force.  This code is a
875     helper routing for the KPK recognizer that returns the critical
876     square given a pawn's location for color uColor.
877
878     Note: rook pawns only have one critical square so this code
879     returns the same square three times in this case.
880
881 Parameters:
882
883     ULONG uColor,
884     COOR cPawn,
885     COOR *cSquare
886
887 Return value:
888
889     static void
890
891 **/
892 {
893     static COOR cCriticalSquare[2][128] = 
894     {
895         {    
896             0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,   0,0,0,0,0,0,0,0,
897             0x61, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x66,   0,0,0,0,0,0,0,0,
898             0x61, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x66,   0,0,0,0,0,0,0,0,
899             0x61, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x66,   0,0,0,0,0,0,0,0,
900             0x61, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x66,   0,0,0,0,0,0,0,0,
901             0x61, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x66,   0,0,0,0,0,0,0,0,
902             0x61, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x66,   0,0,0,0,0,0,0,0,
903             0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,   0,0,0,0,0,0,0,0,
904         },
905         {    
906             0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,   0,0,0,0,0,0,0,0,
907             0x11, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x16,   0,0,0,0,0,0,0,0,
908             0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16,   0,0,0,0,0,0,0,0,
909             0x11, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x16,   0,0,0,0,0,0,0,0,
910             0x11, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x16,   0,0,0,0,0,0,0,0,
911             0x11, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x16,   0,0,0,0,0,0,0,0,
912             0x11, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x16,   0,0,0,0,0,0,0,0,
913             0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,   0,0,0,0,0,0,0,0,
914         } 
915     };
916     ULONG uFile = FILE(cPawn);
917
918     ASSERT(IS_VALID_COLOR(uColor));
919     ASSERT(IS_ON_BOARD(cPawn));
920     ASSERT((RANK(cPawn) != 1) && (RANK(cPawn) != 8));
921     
922     if ((uFile == A) || (uFile == H))
923     {
924         cSquare[0] = cCriticalSquare[uColor][cPawn];
925         cSquare[1] = cCriticalSquare[uColor][cPawn];
926         cSquare[2] = cCriticalSquare[uColor][cPawn];
927         goto end;
928     }
929     cSquare[1] = cCriticalSquare[uColor][cPawn];
930     cSquare[0] = cSquare[1] - 1;
931     cSquare[2] = cSquare[1] + 1;
932     
933  end:
934     ASSERT(cSquare[0] != 0);
935     ASSERT(cSquare[1] != 0);
936     ASSERT(cSquare[2] != 0);
937     ASSERT(IS_ON_BOARD(cSquare[0]));
938     ASSERT(IS_ON_BOARD(cSquare[1]));
939     ASSERT(IS_ON_BOARD(cSquare[2]));
940 }
941
942
943 static ULONG 
944 _RecognizeKPK(IN SEARCHER_THREAD_CONTEXT *ctx, 
945               IN OUT SCORE *piScore)
946 /**
947
948 Routine description:
949
950     Attempt to recognize KP+KP* positions.
951
952 Parameters:
953
954     POSITION *pos,
955     SCORE *piScore
956
957 Return value:
958
959     static ULONG
960
961 **/
962 {
963     ULONG uStrong;
964     ULONG uWeak;
965     COOR cPawn, cQueen;
966     COOR cCritical[3];
967     ULONG uDist[2];
968     ULONG u;
969     PAWN_HASH_ENTRY *pHash;
970     POSITION *pos = &ctx->sPosition;
971
972     ASSERT(pos->uNonPawnCount[WHITE][0] == 1);
973     ASSERT(pos->uNonPawnCount[BLACK][0] == 1);
974     ASSERT(_NothingBut(pos, PAWN, WHITE));
975     ASSERT(_NothingBut(pos, PAWN, BLACK));
976
977     //
978     // Look to see if one side has a winning passed pawn
979     //
980     pHash = PawnHashLookup(ctx);
981     ASSERT(pHash != NULL);
982     if (pHash->u64Key == pos->u64PawnSig)
983     {
984         pos->iScore[BLACK] = pos->iScore[WHITE] = 0;
985         if (TRUE == EvalPasserRaces(pos, pHash))
986         {
987             //
988             // Someone wins.
989             //
990             ASSERT((pos->iScore[BLACK] == 0) || (pos->iScore[WHITE] == 0));
991             ASSERT((pos->iScore[BLACK] != 0) || (pos->iScore[WHITE] != 0));
992             if (pos->iScore[BLACK] > 0)
993             {
994                 ASSERT(pos->iScore[WHITE] == 0);
995                 *piScore = (pos->iMaterialBalance[BLACK] + 2 * VALUE_PAWN +
996                             pos->iScore[BLACK]);
997                 ASSERT(IS_VALID_SCORE(*piScore));
998                 if (pos->uToMove == WHITE)
999                 {
1000                     *piScore *= -1;
1001                     return(RECOGN_UPPER);
1002                 }
1003                 return(RECOGN_LOWER);
1004             }
1005             else
1006             {
1007                 ASSERT(pos->iScore[WHITE] > 0);
1008                 *piScore = (pos->iMaterialBalance[WHITE] + 2 * VALUE_PAWN +
1009                             pos->iScore[WHITE]);
1010                 ASSERT(IS_VALID_SCORE(*piScore));
1011                 if (pos->uToMove == BLACK)
1012                 {
1013                     *piScore *= -1;
1014                     return(RECOGN_UPPER);
1015                 }
1016                 return(RECOGN_LOWER);
1017             }
1018         }
1019     }
1020
1021     //
1022     // No one has a winning passer or we did not find the hash entry.
1023     //
1024     if ((pos->uPawnCount[WHITE] > 0) && (pos->uPawnCount[BLACK] > 0))
1025     {
1026         return(UNRECOGNIZED);
1027     }
1028
1029     //
1030     // If we get here then no one has a winning passer and one side
1031     // has only a lone king -- no pawns.  Do some more "sophisticated"
1032     // analysis looking for a won passer.  Also: this is at best a
1033     // draw for the weak side.
1034     //
1035     uStrong = WHITE;
1036     if (pos->uPawnCount[WHITE] == 0)
1037     {
1038         uStrong = BLACK;
1039     }
1040     ASSERT(pos->uPawnCount[uStrong] > 0);
1041     uWeak = FLIP(uStrong);
1042     ASSERT(pos->uPawnCount[uWeak] == 0);
1043         
1044     if (pos->uPawnCount[uStrong] > 1)
1045     {
1046         *piScore = 0;
1047         if (pos->uToMove == uStrong)
1048         {
1049             return(RECOGN_LOWER);
1050         }
1051         return(RECOGN_UPPER);
1052     }
1053
1054     //
1055     // The side with pawns has only one pawn, do some more
1056     // sophisticated analysis here to spot winning KPK
1057     // configurations earlier by using "critical squares"
1058     // 
1059     ASSERT(pos->uPawnCount[uStrong] == 1);
1060     cPawn = pos->cPawns[uStrong][0];
1061     ASSERT(IS_ON_BOARD(cPawn));
1062     ASSERT(IS_PAWN(pos->rgSquare[cPawn].pPiece));
1063             
1064     //
1065     // Step 1: the strong king must be closer to the pawn than
1066     // the weak king.
1067     //
1068     uDist[uStrong] = DISTANCE(pos->cNonPawns[uStrong][0], cPawn);
1069     ASSERT((1 <= uDist[uStrong]) && (uDist[uStrong] <= 7));
1070     uDist[uWeak] = DISTANCE(pos->cNonPawns[uWeak][0], cPawn);
1071     ASSERT((1 <= uDist[uWeak]) && (uDist[uWeak] <= 7));
1072     if (uDist[uStrong] <= uDist[uWeak])
1073     {
1074         //
1075         // Step 2: the strong king must be closer to one of the
1076         // passer's critical squares than the weak king.
1077         //
1078         _GetPassersCriticalSquares(uStrong, cPawn, cCritical);
1079         for (u = 0; u < 3; u++)
1080         {
1081             uDist[uStrong] = DISTANCE(pos->cNonPawns[uStrong][0], 
1082                                       cCritical[u]);
1083             ASSERT((0 <= uDist[uStrong]) && (uDist[uStrong] <= 7));
1084             uDist[uWeak] = DISTANCE(pos->cNonPawns[uWeak][0], 
1085                                     cCritical[u]);
1086             
1087             //
1088             // Assume if the weak side is on move he will move
1089             // towards the critical square.  Also assume that
1090             // in so doing he will increase the path that the
1091             // strong king must take to get to the critical
1092             // square.
1093             //
1094             if (uDist[uWeak] > 0) {
1095                 uDist[uWeak] -= (pos->uToMove == uWeak);
1096             }
1097             if (uDist[uStrong] > 0) {
1098                 uDist[uStrong] += (pos->uToMove == uWeak) * 2;
1099             }
1100             ASSERT((0 <= uDist[uWeak]) && (uDist[uWeak] <= 7));
1101             if (uDist[uStrong] < uDist[uWeak])
1102             {
1103                 cQueen = 
1104                     QUEENING_SQUARE_BY_COLOR_FILE[uStrong][FILE(cPawn)];
1105                 *piScore = (pos->iMaterialBalance[uStrong] +
1106                             VALUE_QUEEN + (2 * VALUE_PAWN) -
1107                             (RANK_DISTANCE(cPawn, cQueen) * 32));
1108                 if (pos->uToMove == uWeak)
1109                 {
1110                     *piScore *= -1;
1111                     return(RECOGN_UPPER);
1112                 }
1113                 return(RECOGN_LOWER);
1114             }
1115         }
1116     }
1117
1118     //
1119     // If we get here then the weak king is as close to or
1120     // closer to the lone passer than the strong king -or- the
1121     // weak king is as close to or closer to the passer's
1122     // critical squares than the strong king.  This may still
1123     // be won for the strong side but we don't know -- the
1124     // logic is ugly.  This is still at best drawn for the
1125     // weak side though.
1126     //
1127     *piScore = 0;
1128     if (pos->uToMove == uStrong)
1129     {
1130         return(RECOGN_LOWER);
1131     }
1132     return(RECOGN_UPPER);
1133 }
1134
1135
1136 static void 
1137 _NewRecognizer(IN RECOGNIZER *pFunct, 
1138                IN ULONG uWhiteSig, 
1139                IN ULONG uBlackSig)
1140 /**
1141
1142 Routine description:
1143
1144     Register a recognizer function.
1145
1146 Parameters:
1147
1148     RECOGNIZER *pFunct,
1149     ULONG uWhiteSig,
1150     ULONG uBlackSig
1151
1152 Return value:
1153
1154     static void
1155
1156 **/
1157 {
1158     g_bvRecognizerAvailable[uWhiteSig] |= (1 << uBlackSig);
1159     g_bvRecognizerAvailable[uBlackSig] |= (1 << uWhiteSig);
1160     g_pRecognizers[RECOGN_INDEX(uWhiteSig, uBlackSig)] = pFunct;
1161 }
1162
1163 void 
1164 InitializeInteriorNodeRecognizers(void)
1165 /**
1166
1167 Routine description:
1168
1169     Init this recognizer module
1170
1171 Parameters:
1172
1173     void
1174
1175 Return value:
1176
1177     void
1178
1179 **/
1180 {
1181     memset(g_pRecognizers, 0, sizeof(g_pRecognizers));
1182     memset(g_bvRecognizerAvailable, 0, sizeof(g_bvRecognizerAvailable));
1183
1184     // KK                           P  N  B  R  Q
1185     _NewRecognizer(_RecognizeKK,
1186                    _MakeMaterialSig(0, 0, 0, 0, 0),
1187                    _MakeMaterialSig(0, 0, 0, 0, 0));
1188
1189     // KB+K                         P  N  B  R  Q    
1190     _NewRecognizer(_RecognizeKBK,
1191                    _MakeMaterialSig(0, 0, 1, 0, 0),
1192                    _MakeMaterialSig(0, 0, 0, 0, 0));
1193
1194     // KB+KB+                       P  N  B  R  Q
1195     _NewRecognizer(_RecognizeKBK,
1196                    _MakeMaterialSig(0, 0, 1, 0, 0),
1197                    _MakeMaterialSig(0, 0, 1, 0, 0));
1198     
1199     // KN+K                         P  N  B  R  Q    
1200     _NewRecognizer(_RecognizeKNK,
1201                    _MakeMaterialSig(0, 1, 0, 0, 0), 
1202                    _MakeMaterialSig(0, 0, 0, 0, 0));
1203
1204     // KN+KN+                       P  N  B  R  Q        
1205     _NewRecognizer(_RecognizeKNK, 
1206                    _MakeMaterialSig(0, 1, 0, 0, 0), 
1207                    _MakeMaterialSig(0, 1, 0, 0, 0));
1208
1209     // KN+KB+                       P  N  B  R  Q    
1210     _NewRecognizer(_RecognizeKBNK, 
1211                    _MakeMaterialSig(0, 1, 0, 0, 0), 
1212                    _MakeMaterialSig(0, 0, 1, 0, 0));
1213
1214     // KN+B+K                       P  N  B  R  Q    
1215     _NewRecognizer(_RecognizeKBNK, 
1216                    _MakeMaterialSig(0, 1, 1, 0, 0), 
1217                    _MakeMaterialSig(0, 0, 0, 0, 0));
1218
1219     // KN+KP+                       P  N  B  R  Q    
1220     _NewRecognizer(_RecognizeKNKP, 
1221                    _MakeMaterialSig(1, 0, 0, 0, 0), 
1222                    _MakeMaterialSig(0, 1, 0, 0, 0));
1223
1224     // KB+KP+                       P  N  B  R  Q    
1225     _NewRecognizer(_RecognizeKBKP, 
1226                    _MakeMaterialSig(1, 0, 0, 0, 0), 
1227                    _MakeMaterialSig(0, 0, 1, 0, 0));
1228     
1229     // KP+B+KP+                     P  N  B  R  Q    
1230     _NewRecognizer(_RecognizeKBKP, 
1231                    _MakeMaterialSig(1, 0, 1, 0, 0), 
1232                    _MakeMaterialSig(1, 0, 0, 0, 0));
1233     
1234
1235     // KP+B+K                       P  N  B  R  Q
1236     _NewRecognizer(_RecognizeKBKP, 
1237                    _MakeMaterialSig(1, 0, 1, 0, 0), 
1238                    _MakeMaterialSig(0, 0, 0, 0, 0));
1239
1240     // KP+K                         P  N  B  R  Q    
1241     _NewRecognizer(_RecognizeKPK, 
1242                    _MakeMaterialSig(0, 0, 0, 0, 0), 
1243                    _MakeMaterialSig(1, 0, 0, 0, 0));
1244
1245     // KP+KP+                       P  N  B  R  Q
1246     _NewRecognizer(_RecognizeKPK, 
1247                    _MakeMaterialSig(1, 0, 0, 0, 0), 
1248                    _MakeMaterialSig(1, 0, 0, 0, 0));
1249 }
1250
1251
1252 ULONG 
1253 RecognLookup(IN SEARCHER_THREAD_CONTEXT *ctx,
1254              IN OUT SCORE *piScore,
1255              IN FLAG fProbeEGTB)
1256 /**
1257
1258 Routine description:
1259
1260     This is the interface to the recogn module; it is called from
1261     Search and Qsearch.  Its job is to: 1. check high speed internal
1262     node recognizer functions if a recognizable material signature is
1263     present on the board and 2. probe on-disk EGTB files if no useful
1264     recognizer result is found.
1265
1266 Parameters:
1267
1268     SEARCHER_THREAD_CONTEXT *ctx,
1269     SCORE *piScore,
1270     FLAG fProbeEGTB
1271
1272 Return value:
1273
1274     ULONG
1275
1276 **/
1277 {
1278     ULONG uVal;
1279     POSITION *pos = &ctx->sPosition;
1280     ULONG uSig[2];
1281     RECOGNIZER *pRec;
1282     SCORE iScore;
1283
1284     //
1285     // Try interior node recognizers
1286     // 
1287     if ((pos->uNonPawnCount[WHITE][0] <= 3) &&
1288         (pos->uNonPawnCount[BLACK][0] <= 3))
1289     {
1290         uSig[BLACK] = _MakeMaterialSig((pos->uPawnCount[BLACK] > 0),
1291                                        (pos->uNonPawnCount[BLACK][KNIGHT] > 0),
1292                                        (pos->uNonPawnCount[BLACK][BISHOP] > 0),
1293                                        (pos->uNonPawnCount[BLACK][ROOK] > 0),
1294                                        (pos->uNonPawnCount[BLACK][QUEEN] > 0));
1295         uSig[WHITE] = _MakeMaterialSig((pos->uPawnCount[WHITE] > 0),
1296                                        (pos->uNonPawnCount[WHITE][KNIGHT] > 0),
1297                                        (pos->uNonPawnCount[WHITE][BISHOP] > 0),
1298                                        (pos->uNonPawnCount[WHITE][ROOK] > 0),
1299                                        (pos->uNonPawnCount[WHITE][QUEEN] > 0));
1300         pRec = g_pRecognizers[RECOGN_INDEX(uSig[WHITE], uSig[BLACK])];
1301         if (NULL != pRec)
1302         {
1303             if (g_bvRecognizerAvailable[uSig[WHITE]] & (1 << uSig[BLACK]))
1304             {
1305                 uVal = pRec(ctx, &iScore);
1306                 if (UNRECOGNIZED != uVal)
1307                 {
1308                     *piScore = iScore;
1309                     ASSERT((-NMATE < iScore) && (iScore < +NMATE));
1310                     ASSERT(_SanityCheckRecognizers(ctx, iScore, uVal));
1311                     return(uVal);
1312                 }
1313             }
1314         }
1315     }
1316
1317     //
1318     // Try EGTB probe as long as some conditions are met
1319     // 
1320     if ((FALSE != fProbeEGTB) &&
1321         ((pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0] +
1322           pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK]) <= 5))
1323     {
1324         if (TRUE == ProbeEGTB(ctx, &iScore))
1325         {
1326             //
1327             // We have an exact score from EGTB but if it's a mate in N
1328             // we still have to adjust it for the present ply. 
1329             //
1330             if (iScore >= +NMATE) {
1331                 iScore -= ctx->uPly;
1332             }
1333             else if (iScore <= -NMATE) {
1334                 iScore += ctx->uPly;
1335             }
1336 #ifdef DEBUG
1337             else 
1338             {
1339                 ASSERT(iScore == 0); // iDrawValue[side]
1340             }
1341 #endif
1342             *piScore = iScore;
1343             return(RECOGN_EXACT);
1344         }
1345     }
1346     return(UNRECOGNIZED);
1347 }