3 Copyright (c) Scott Gasch
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.
26 extern ULONG g_uIterateDepth;
27 static COOR QUEENING_SQUARE_BY_COLOR_FILE[2][8] =
29 { A1, B1, C1, D1, E1, F1, G1, H1 },
30 { A8, B8, C8, D8, E8, F8, G8, H8 }
33 #define RECOGN_INDEX(w, b) \
34 (((b) | (w)) + (32 * ((w) && (b))))
36 typedef ULONG RECOGNIZER(SEARCHER_THREAD_CONTEXT *ctx, SCORE *piScore);
38 static RECOGNIZER *g_pRecognizers[64];
39 static BITV g_bvRecognizerAvailable[32];
42 _MakeMaterialSig(IN FLAG fPawn,
51 Make a material signature ULONG out of flags representing the
52 presence of pawns, knights, bishops, rooks, queens on the board.
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));
76 x = fPawn | (fKnight << 1) | (fBishop << 2) | (fRook << 3) | (fQueen << 4);
78 ASSERT((0 <= x) && (x <= 31));
87 _TablebasesSaySideWins(IN SEARCHER_THREAD_CONTEXT *ctx,
91 if (TRUE == ProbeEGTB(ctx, &iScore))
93 if (ctx->sPosition.uToMove == uSide)
106 _TablebasesSayDraw(IN SEARCHER_THREAD_CONTEXT *ctx)
109 if (TRUE == ProbeEGTB(ctx, &iScore))
117 _TablebasesSayDrawOrWin(IN SEARCHER_THREAD_CONTEXT *ctx,
121 if (TRUE == ProbeEGTB(ctx, &iScore))
123 return ((iScore == 0) ||
124 ((iScore > 0) && (ctx->sPosition.uToMove == uSide)) ||
125 ((iScore < 0) && (ctx->sPosition.uToMove != uSide)));
132 _SanityCheckRecognizers(IN SEARCHER_THREAD_CONTEXT *ctx,
135 ULONG uToMove = ctx->sPosition.uToMove;
141 return _TablebasesSayDraw(ctx);
142 } else if (iScore > 0) {
143 return _TablebasesSaySideWins(ctx, uToMove);
146 return _TablebasesSaySideWins(ctx, !uToMove);
150 return _TablebasesSayDrawOrWin(ctx, uToMove);
151 } else if (iScore > 0) {
152 return _TablebasesSaySideWins(ctx, uToMove);
155 return _TablebasesSaySideWins(ctx, !uToMove);
159 return _TablebasesSayDrawOrWin(ctx, !uToMove);
160 } else if (iScore > 0) {
161 return _TablebasesSayDrawOrWin(ctx, !uToMove);
164 return _TablebasesSaySideWins(ctx, !uToMove);
173 _NothingBut(IN POSITION *pos,
180 Support routine to assert that nothing but the piece bits
181 enumerated in parameter p are present in the position pos for side
197 static PIECE q[] = { KNIGHT, BISHOP, ROOK, QUEEN };
202 if (pos->uPawnCount[uColor] > 0) return(FALSE);
205 for (u = 0; u < ARRAY_LENGTH(q); u++)
209 if (pos->uNonPawnCount[uColor][q[u]] > 0) return(FALSE);
217 _RecognizeKK(IN SEARCHER_THREAD_CONTEXT *ctx,
218 IN OUT SCORE *piScore)
223 Encode the knowledge that two lone kings on the board are a draw.
237 return(RECOGN_EXACT);
241 _RecognizeKBK(IN SEARCHER_THREAD_CONTEXT *ctx,
242 IN OUT SCORE *piScore)
247 Attempt to recognize KB*KB+ positions.
265 POSITION *pos = &ctx->sPosition;
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));
273 // Recognize KBKB as a draw unless there's a cornered king (in
274 // which case it may be a mate-in-1)
276 if ((pos->uNonPawnCount[WHITE][0] == 2) &&
277 (pos->uNonPawnCount[BLACK][0] == 2))
279 if ((CORNER_DISTANCE(pos->cNonPawns[WHITE][0]) != 0) &&
280 (CORNER_DISTANCE(pos->cNonPawns[BLACK][0]) != 0))
283 return(RECOGN_EXACT);
288 // Otherwise we want to deal with KB+ vs lone K. KBKBB etc are
289 // too hard to recognize.
291 if ((pos->uNonPawnCount[WHITE][0] != 1) &&
292 (pos->uNonPawnCount[BLACK][0] != 1))
294 return(UNRECOGNIZED);
298 // If we get here then one side has no pieces (except the king).
301 if (pos->uNonPawnCount[WHITE][0] > 1)
305 ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
306 ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
309 // KB vs K is a draw, KB+ vs K is still a draw if all bishops are the
312 uBishops = pos->uNonPawnCount[uStrong][BISHOP];
313 if ((uBishops == 1) ||
314 (pos->uWhiteSqBishopCount[uStrong] == 0) ||
315 (pos->uWhiteSqBishopCount[uStrong] == uBishops))
318 return(RECOGN_EXACT);
322 // If we get here the strong side has more than one bishop and has
323 // at least one bishop on each color.
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.
332 cWeakKing = pos->cNonPawns[FLIP(uStrong)][0];
333 ASSERT(DISTANCE(cWeakKing, pos->cNonPawns[uStrong][0]) > 1);
335 for (u = 1; u < pos->uNonPawnCount[uStrong][0]; u++)
337 uAdjacent += DISTANCE(cWeakKing, pos->cNonPawns[uStrong][u] == 1);
341 return(UNRECOGNIZED);
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.
348 if (pos->uToMove != uStrong)
350 ASSERT(pos->uToMove == FLIP(uStrong));
353 return(UNRECOGNIZED);
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]);
360 if ((u == 2) && (ON_EDGE(cWeakKing)))
362 return(UNRECOGNIZED);
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.
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)
377 return(RECOGN_UPPER);
379 return(RECOGN_LOWER);
383 _RecognizeKNK(IN SEARCHER_THREAD_CONTEXT *ctx,
384 IN OUT SCORE *piScore)
389 Recognize KN*KN+ positions.
402 POSITION *pos = &ctx->sPosition;
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));
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)
414 if ((pos->uNonPawnCount[WHITE][0] == 2) &&
415 (pos->uNonPawnCount[BLACK][0] == 2))
417 if ((CORNER_DISTANCE(pos->cNonPawns[WHITE][0]) != 0) &&
418 (CORNER_DISTANCE(pos->cNonPawns[BLACK][0]) != 0))
421 return(RECOGN_EXACT);
423 return(UNRECOGNIZED);
427 // KNNKN etc... unrecognized. Heinz says "exceptional wins possible for
428 // any side by mates in seven or less moves." TODO: add this knowledge.
430 if ((pos->uNonPawnCount[WHITE][0] != 1) ||
431 (pos->uNonPawnCount[BLACK][0] != 1))
433 return(UNRECOGNIZED);
437 // If we get here somebody has no pieces (except a lone king).
440 if (pos->uNonPawnCount[BLACK][0] > 1)
444 ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
445 ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
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.
452 ASSERT(pos->uNonPawnCount[uStrong][0] < 4);
453 if (ON_EDGE(pos->cNonPawns[FLIP(uStrong)][0]))
455 return(UNRECOGNIZED);
458 return(RECOGN_EXACT);
463 _RecognizeKBNK(IN SEARCHER_THREAD_CONTEXT *ctx,
464 IN OUT SCORE *piScore)
486 POSITION *pos = &ctx->sPosition;
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));
493 if ((pos->uNonPawnCount[WHITE][0] > 1) &&
494 (pos->uNonPawnCount[BLACK][0] > 1))
497 // Do not recognize stuff like KNNKB or KNKBB etc...
499 if (pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0] > 4)
501 return(UNRECOGNIZED);
505 // This is KNKB; unless someone's king is on the edge,
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]))
513 return(UNRECOGNIZED);
516 return(RECOGN_EXACT);
520 // If we get here we are in a KBNK endgame.
523 if (pos->uNonPawnCount[BLACK][0] > 1)
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));
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.
538 cKnight = pos->cNonPawns[uStrong][KNIGHT];
539 if ((CORNER_DISTANCE(cKnight) == 0) &&
540 (DISTANCE(cWeakKing, cKnight) == 1))
542 return(UNRECOGNIZED);
546 // Don't recognize anything if the weak king is next to a strong side's
550 for (u = 1; u < pos->uNonPawnCount[uStrong][0]; u++)
552 uAdjacent = (DISTANCE(pos->cNonPawns[uStrong][u], cWeakKing) == 1);
556 return(UNRECOGNIZED);
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
564 if (pos->uToMove != uStrong)
566 ASSERT(pos->uToMove == FLIP(uStrong));
569 return(UNRECOGNIZED);
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]);
576 if ((u == 2) && (ON_EDGE(cWeakKing)))
578 return(UNRECOGNIZED);
583 // Calculate a score that grabs the search's attention and makes
584 // progress towards driving the weak king to the correct corner to
587 if (pos->uWhiteSqBishopCount[uStrong] > 0)
589 uDist = WHITE_CORNER_DISTANCE(cWeakKing);
593 uDist = BLACK_CORNER_DISTANCE(cWeakKing);
595 ASSERT((0 <= uDist) && (uDist <= 7));
597 *piScore = (pos->iMaterialBalance[uStrong] + (7 * VALUE_PAWN)
598 - (uDist * 32) - (u * 16));
599 ASSERT(IS_VALID_SCORE(*piScore));
600 if (pos->uToMove != uStrong)
603 return(RECOGN_UPPER);
605 return(RECOGN_LOWER);
610 _RecognizeKNKP(IN SEARCHER_THREAD_CONTEXT *ctx,
611 IN OUT SCORE *piScore)
616 Recognize KN+KP+ positions.
630 POSITION *pos = &ctx->sPosition;
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));
638 // Call the side with knight(s) "strong"
641 if (pos->uNonPawnCount[BLACK][0] > 1)
645 ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
646 ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
649 // Don't recognize KNNKP or KNKP with K on edge
651 if ((pos->uNonPawnCount[uStrong][KNIGHT] > 2) ||
652 (ON_EDGE(pos->cNonPawns[FLIP(uStrong)][0])))
654 return(UNRECOGNIZED);
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)
662 if (pos->uToMove == uStrong)
664 return(RECOGN_UPPER);
666 return(RECOGN_LOWER);
671 _RecognizeKBKP(IN SEARCHER_THREAD_CONTEXT *ctx,
672 IN OUT SCORE *piScore)
677 Recognize KB+P*KP+ positions including knowledge about "wrong color
696 POSITION *pos = &ctx->sPosition;
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));
704 // Call the side with bishop(s) "strong"
707 if (pos->uNonPawnCount[BLACK][BISHOP] > 0)
711 ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
712 ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
714 cWeakKing = pos->cNonPawns[FLIP(uStrong)][0];
715 ASSERT(IS_ON_BOARD(cWeakKing));
716 ASSERT(IS_KING(pos->rgSquare[cWeakKing].pPiece));
719 // Construct a strong side bitboard of pawn locations
722 for (u = 0; u < pos->uPawnCount[uStrong]; u++)
724 c = pos->cPawns[uStrong][u];
725 ASSERT(IS_ON_BOARD(c));
729 if ((pos->uNonPawnCount[BLACK][0] + pos->uPawnCount[BLACK] > 1) &&
730 (pos->uNonPawnCount[WHITE][0] + pos->uPawnCount[WHITE] > 1))
733 // Neither side has a lone king. This is either KBKP+ or
736 if (pos->uPawnCount[uStrong] > 0)
739 // Strong side can maybe take an adjacent pawn and survive the
742 if (uStrong == pos->uToMove)
744 return(UNRECOGNIZED);
748 // Make sure the strong side has the right color bishop
751 if (uStrong == WHITE)
753 if (!(bb & ~BBFILE[A]) &&
754 (pos->uWhiteSqBishopCount[WHITE] == 0) &&
755 (DISTANCE(cWeakKing, A8) <= 1))
757 goto at_best_draw_for_strong;
760 if (!(bb & ~BBFILE[H]) &&
761 (pos->uWhiteSqBishopCount[WHITE] ==
762 pos->uNonPawnCount[WHITE][BISHOP]) &&
763 (DISTANCE(cWeakKing, H8) <= 1))
765 goto at_best_draw_for_strong;
770 if (!(bb & ~BBFILE[A]) &&
771 (pos->uWhiteSqBishopCount[BLACK] ==
772 pos->uNonPawnCount[BLACK][BISHOP]) &&
773 (DISTANCE(cWeakKing, A1) <= 1))
775 goto at_best_draw_for_strong;
778 if (!(bb & ~BBFILE[H]) &&
779 (pos->uWhiteSqBishopCount[BLACK] == 0) &&
780 (DISTANCE(cWeakKing, H1) <= 1))
782 goto at_best_draw_for_strong;
785 return(UNRECOGNIZED);
790 // Strong side has no pawns... there's a mate-in-1 here if
791 // the weak king is stuck in the corner.
793 if ((pos->uNonPawnCount[uStrong][BISHOP] > 1) ||
794 (CORNER_DISTANCE(cWeakKing) == 0))
796 return(UNRECOGNIZED);
798 goto at_best_draw_for_strong;
804 // KBPK: make sure the bishop is the right color. This time
805 // there is no need to check for on-move.
807 ASSERT(pos->uNonPawnCount[FLIP(uStrong)][0] == 1);
808 ASSERT(pos->uNonPawnCount[uStrong][0] > 1);
810 if (uStrong == WHITE)
812 if (!(bb & ~BBFILE[A]) &&
813 (pos->uWhiteSqBishopCount[WHITE] == 0) &&
814 (DISTANCE(cWeakKing, A8) <= 1))
818 if (!(bb & ~BBFILE[H]) &&
819 (pos->uWhiteSqBishopCount[WHITE] ==
820 pos->uNonPawnCount[WHITE][BISHOP]) &&
821 (DISTANCE(cWeakKing, H8) <= 1))
828 if (!(bb & ~BBFILE[A]) &&
829 (pos->uWhiteSqBishopCount[BLACK] ==
830 pos->uNonPawnCount[BLACK][BISHOP]) &&
831 (DISTANCE(cWeakKing, A1) <= 1))
835 if (!(bb & ~BBFILE[H]) &&
836 (pos->uWhiteSqBishopCount[BLACK] == 0) &&
837 (DISTANCE(cWeakKing, H1) <= 1))
842 return(UNRECOGNIZED);
845 UtilPanic(SHOULD_NOT_GET_HERE,
846 NULL, NULL, NULL, NULL,
850 at_best_draw_for_strong:
852 if (pos->uToMove == uStrong)
854 return(RECOGN_UPPER);
856 return(RECOGN_LOWER);
860 return(RECOGN_EXACT);
864 _GetPassersCriticalSquares(IN ULONG uColor,
866 IN OUT COOR *cSquare)
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.
878 Note: rook pawns only have one critical square so this code
879 returns the same square three times in this case.
893 static COOR cCriticalSquare[2][128] =
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,
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,
916 ULONG uFile = FILE(cPawn);
918 ASSERT(IS_VALID_COLOR(uColor));
919 ASSERT(IS_ON_BOARD(cPawn));
920 ASSERT((RANK(cPawn) != 1) && (RANK(cPawn) != 8));
922 if ((uFile == A) || (uFile == H))
924 cSquare[0] = cCriticalSquare[uColor][cPawn];
925 cSquare[1] = cCriticalSquare[uColor][cPawn];
926 cSquare[2] = cCriticalSquare[uColor][cPawn];
929 cSquare[1] = cCriticalSquare[uColor][cPawn];
930 cSquare[0] = cSquare[1] - 1;
931 cSquare[2] = cSquare[1] + 1;
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]));
944 _RecognizeKPK(IN SEARCHER_THREAD_CONTEXT *ctx,
945 IN OUT SCORE *piScore)
950 Attempt to recognize KP+KP* positions.
969 PAWN_HASH_ENTRY *pHash;
970 POSITION *pos = &ctx->sPosition;
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));
978 // Look to see if one side has a winning passed pawn
980 pHash = PawnHashLookup(ctx);
981 ASSERT(pHash != NULL);
982 if (pHash->u64Key == pos->u64PawnSig)
984 pos->iScore[BLACK] = pos->iScore[WHITE] = 0;
985 if (TRUE == EvalPasserRaces(pos, pHash))
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)
994 ASSERT(pos->iScore[WHITE] == 0);
995 *piScore = (pos->iMaterialBalance[BLACK] + 2 * VALUE_PAWN +
997 ASSERT(IS_VALID_SCORE(*piScore));
998 if (pos->uToMove == WHITE)
1001 return(RECOGN_UPPER);
1003 return(RECOGN_LOWER);
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)
1014 return(RECOGN_UPPER);
1016 return(RECOGN_LOWER);
1022 // No one has a winning passer or we did not find the hash entry.
1024 if ((pos->uPawnCount[WHITE] > 0) && (pos->uPawnCount[BLACK] > 0))
1026 return(UNRECOGNIZED);
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.
1036 if (pos->uPawnCount[WHITE] == 0)
1040 ASSERT(pos->uPawnCount[uStrong] > 0);
1041 uWeak = FLIP(uStrong);
1042 ASSERT(pos->uPawnCount[uWeak] == 0);
1044 if (pos->uPawnCount[uStrong] > 1)
1047 if (pos->uToMove == uStrong)
1049 return(RECOGN_LOWER);
1051 return(RECOGN_UPPER);
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"
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));
1065 // Step 1: the strong king must be closer to the pawn than
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])
1075 // Step 2: the strong king must be closer to one of the
1076 // passer's critical squares than the weak king.
1078 _GetPassersCriticalSquares(uStrong, cPawn, cCritical);
1079 for (u = 0; u < 3; u++)
1081 uDist[uStrong] = DISTANCE(pos->cNonPawns[uStrong][0],
1083 ASSERT((0 <= uDist[uStrong]) && (uDist[uStrong] <= 7));
1084 uDist[uWeak] = DISTANCE(pos->cNonPawns[uWeak][0],
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
1094 if (uDist[uWeak] > 0) {
1095 uDist[uWeak] -= (pos->uToMove == uWeak);
1097 if (uDist[uStrong] > 0) {
1098 uDist[uStrong] += (pos->uToMove == uWeak) * 2;
1100 ASSERT((0 <= uDist[uWeak]) && (uDist[uWeak] <= 7));
1101 if (uDist[uStrong] < uDist[uWeak])
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)
1111 return(RECOGN_UPPER);
1113 return(RECOGN_LOWER);
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.
1128 if (pos->uToMove == uStrong)
1130 return(RECOGN_LOWER);
1132 return(RECOGN_UPPER);
1137 _NewRecognizer(IN RECOGNIZER *pFunct,
1142 Routine description:
1144 Register a recognizer function.
1158 g_bvRecognizerAvailable[uWhiteSig] |= (1 << uBlackSig);
1159 g_bvRecognizerAvailable[uBlackSig] |= (1 << uWhiteSig);
1160 g_pRecognizers[RECOGN_INDEX(uWhiteSig, uBlackSig)] = pFunct;
1164 InitializeInteriorNodeRecognizers(void)
1167 Routine description:
1169 Init this recognizer module
1181 memset(g_pRecognizers, 0, sizeof(g_pRecognizers));
1182 memset(g_bvRecognizerAvailable, 0, sizeof(g_bvRecognizerAvailable));
1185 _NewRecognizer(_RecognizeKK,
1186 _MakeMaterialSig(0, 0, 0, 0, 0),
1187 _MakeMaterialSig(0, 0, 0, 0, 0));
1190 _NewRecognizer(_RecognizeKBK,
1191 _MakeMaterialSig(0, 0, 1, 0, 0),
1192 _MakeMaterialSig(0, 0, 0, 0, 0));
1195 _NewRecognizer(_RecognizeKBK,
1196 _MakeMaterialSig(0, 0, 1, 0, 0),
1197 _MakeMaterialSig(0, 0, 1, 0, 0));
1200 _NewRecognizer(_RecognizeKNK,
1201 _MakeMaterialSig(0, 1, 0, 0, 0),
1202 _MakeMaterialSig(0, 0, 0, 0, 0));
1205 _NewRecognizer(_RecognizeKNK,
1206 _MakeMaterialSig(0, 1, 0, 0, 0),
1207 _MakeMaterialSig(0, 1, 0, 0, 0));
1210 _NewRecognizer(_RecognizeKBNK,
1211 _MakeMaterialSig(0, 1, 0, 0, 0),
1212 _MakeMaterialSig(0, 0, 1, 0, 0));
1215 _NewRecognizer(_RecognizeKBNK,
1216 _MakeMaterialSig(0, 1, 1, 0, 0),
1217 _MakeMaterialSig(0, 0, 0, 0, 0));
1220 _NewRecognizer(_RecognizeKNKP,
1221 _MakeMaterialSig(1, 0, 0, 0, 0),
1222 _MakeMaterialSig(0, 1, 0, 0, 0));
1225 _NewRecognizer(_RecognizeKBKP,
1226 _MakeMaterialSig(1, 0, 0, 0, 0),
1227 _MakeMaterialSig(0, 0, 1, 0, 0));
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));
1236 _NewRecognizer(_RecognizeKBKP,
1237 _MakeMaterialSig(1, 0, 1, 0, 0),
1238 _MakeMaterialSig(0, 0, 0, 0, 0));
1241 _NewRecognizer(_RecognizeKPK,
1242 _MakeMaterialSig(0, 0, 0, 0, 0),
1243 _MakeMaterialSig(1, 0, 0, 0, 0));
1246 _NewRecognizer(_RecognizeKPK,
1247 _MakeMaterialSig(1, 0, 0, 0, 0),
1248 _MakeMaterialSig(1, 0, 0, 0, 0));
1253 RecognLookup(IN SEARCHER_THREAD_CONTEXT *ctx,
1254 IN OUT SCORE *piScore,
1258 Routine description:
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.
1268 SEARCHER_THREAD_CONTEXT *ctx,
1279 POSITION *pos = &ctx->sPosition;
1285 // Try interior node recognizers
1287 if ((pos->uNonPawnCount[WHITE][0] <= 3) &&
1288 (pos->uNonPawnCount[BLACK][0] <= 3))
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])];
1303 if (g_bvRecognizerAvailable[uSig[WHITE]] & (1 << uSig[BLACK]))
1305 uVal = pRec(ctx, &iScore);
1306 if (UNRECOGNIZED != uVal)
1309 ASSERT((-NMATE < iScore) && (iScore < +NMATE));
1310 ASSERT(_SanityCheckRecognizers(ctx, iScore, uVal));
1318 // Try EGTB probe as long as some conditions are met
1320 if ((FALSE != fProbeEGTB) &&
1321 ((pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0] +
1322 pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK]) <= 5))
1324 if (TRUE == ProbeEGTB(ctx, &iScore))
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.
1330 if (iScore >= +NMATE) {
1331 iScore -= ctx->uPly;
1333 else if (iScore <= -NMATE) {
1334 iScore += ctx->uPly;
1339 ASSERT(iScore == 0); // iDrawValue[side]
1343 return(RECOGN_EXACT);
1346 return(UNRECOGNIZED);