Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
recog.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 //
3 // FILE: recog.cpp
4 // Endgame knowledge recognition methods
5 //
6 // Part of: Scid (Shane's Chess Information Database)
7 // Version: 3.5
8 //
9 // Notice: Copyright (c) 2002-2003 Shane Hudson. All rights reserved.
10 //
11 // Author: Shane Hudson (sgh@users.sourceforge.net)
12 //
13 //////////////////////////////////////////////////////////////////////
14 
15 #include "engine.h"
16 #include "recog.h"
17 #include "sqmove.h"
18 
19 // The Recognizer class provides score bound information for chess
20 // endgames.
21 namespace Recognizer {
22 static int KPK(Position* pos);
23 static int KBBK(Position* pos);
24 static int KBNK(Position* pos);
25 static int KBPK(Position* pos);
26 static int KRKB(Position* pos);
27 static int KRKN(Position* pos);
28 static int KMKP(Position* pos);
29 static int KQKP(Position* pos);
30 static int KRKP(Position* pos);
31 static int KRPKR(Position* pos);
32 } // namespace Recognizer
33 
34 static const int DRAW = recogValue (SCORE_EXACT, 0);
35 static const int UNKNOWN = recogValue (SCORE_NONE, 0);
36 
37 
38 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39 // Recognizer::Recognize
40 // Checks the current position for a recognized endgame.
41 // Returns a recognition value, which contains a regular score
42 // for the position and a score flag indicating if the score
43 // is exact, an upper bound, a lower bound, or useless.
44 int
46 {
47  uint npieces = pos->TotalMaterial();
48  const byte* material = pos->GetMaterial();
49 
50  if (npieces > 6) { return UNKNOWN; }
51 
52  // TODO: Speed up this code which selects the appropriate recognizer.
53  // TODO: We should maintain a material signature (or hash code) in
54  // TODO: the position and then we could use a small lookup table here
55  // TODO: find the appropriate recognizer quickly.
56 
57  if (npieces == 3) {
58  if (material[WB] == 1 || material[BB] == 1) { return DRAW; }
59  if (material[WN] == 1 || material[BN] == 1) { return DRAW; }
60  if (material[WP] == 1 || material[BP] == 1) { return KPK(pos); }
61  return UNKNOWN;
62  }
63  if (npieces == 5) {
64  // KRP-KR:
65  if (material[WR] == 1 && material[WP] == 1 && material[BR] == 1) {
66  return KRPKR(pos);
67  }
68  if (material[BR] == 1 && material[BP] == 1 && material[WR] == 1) {
69  return KRPKR(pos);
70  }
71  // Bishop and 2 pawns on same rook file with bishop of wrong color:
72  if (material[WB] == 1 && material[WP] == 2) { return KBPK(pos); }
73  if (material[BB] == 1 && material[BP] == 2) { return KBPK(pos); }
74  return UNKNOWN;
75  }
76  if (npieces == 6) {
77  // Bishop and 3 pawns on same rook file with bishop of wrong color:
78  if (material[WB] == 1 && material[WP] == 3) { return KBPK(pos); }
79  if (material[BB] == 1 && material[BP] == 3) { return KBPK(pos); }
80  return UNKNOWN;
81  }
82  if (npieces <= 2) { return DRAW; } // Lone kings.
83 
84  // If we get here, there are four pieces (including kings and pawns)
85  ASSERT (npieces == 4);
86 
87  // Positions with pawns:
88  if (material[WP] == 1) {
89  if (material[BQ] == 1) { return KQKP(pos); }
90  if (material[BR] == 1) { return KRKP(pos); }
91  if (material[BB] == 1 || material[BN] == 1) { return KMKP(pos); }
92  if (material[WB] == 1) { return KBPK(pos); }
93  return UNKNOWN;
94  }
95  if (material[BP] == 1) {
96  if (material[WQ] == 1) { return KQKP(pos); }
97  if (material[WR] == 1) { return KRKP(pos); }
98  if (material[WB] == 1 || material[WN] == 1) { return KMKP(pos); }
99  if (material[BB] == 1) { return KBPK(pos); }
100  return UNKNOWN;
101  }
102 
103  if (material[WB] == 2 || material[BB] == 2) { return KBBK(pos); }
104  if (material[WB] == 1 && material[WN] == 1) { return KBNK(pos); }
105  if (material[BB] == 1 && material[BN] == 1) { return KBNK(pos); }
106  if (material[WR] == 1 && material[BB] == 1) { return KRKB(pos); }
107  if (material[BR] == 1 && material[WB] == 1) { return KRKB(pos); }
108  if (material[WR] == 1 && material[BN] == 1) { return KRKN(pos); }
109  if (material[BR] == 1 && material[WN] == 1) { return KRKN(pos); }
110 
111  // KBKB, KBKN, KNKN and KNNK are all draws, but may have a
112  // trivial mate-in-one if the non-side-to-move king is in a corner:
113  if (material[WN] == 2 || material[BN] == 2
114  || (material[WB] == 1 && material[BB] == 1)
115  || (material[WB] == 1 && material[BN] == 1)
116  || (material[WN] == 1 && material[BB] == 1)
117  || (material[WN] == 1 && material[BN] == 1)) {
118  squareT wk = pos->GetKingSquare(WHITE);
119  squareT bk = pos->GetKingSquare(BLACK);
120  colorT stm = pos->GetToMove();
121  if (stm == WHITE && square_IsCornerSquare(bk)) { return UNKNOWN; }
122  if (stm == BLACK && square_IsCornerSquare(wk)) { return UNKNOWN; }
123  return DRAW;
124  }
125 
126  return UNKNOWN;
127 }
128 
129 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
130 // Recognizer::KPK
131 // Returns a recognition score for King and one Pawn vs King.
132 int
133 Recognizer::KPK (Position * pos)
134 {
135  const byte* material = pos->GetMaterial();
136  squareT wk, bk, wp;
137  colorT stm = pos->GetToMove();
138 
139  // Find piece squares with White having the pawn:
140  if (material[WP] == 1) {
141  wk = pos->GetKingSquare(WHITE);
142  bk = pos->GetKingSquare(BLACK);
143  squareT * sqlist = pos->GetList(WHITE);
144  wp = sqlist[1];
145  } else {
146  ASSERT (material[BP] == 1);
147  wk = square_FlipRank(pos->GetKingSquare(BLACK));
148  bk = square_FlipRank(pos->GetKingSquare(WHITE));
149  squareT * sqlist = pos->GetList(BLACK);
150  wp = square_FlipRank(sqlist[1]);
151  stm = color_Flip(stm);
152  }
153 
154  // Find pawn, king and enemy king rank and file values:
155  rankT wpRank = square_Rank(wp); fyleT wpFyle = square_Fyle(wp);
156  rankT wkRank = square_Rank(wk); rankT wkFyle = square_Fyle(wk);
157  rankT bkRank = square_Rank(bk); rankT bkFyle = square_Fyle(bk);
158 
159  // Find value to use if it is a win:
160  int winScore = 500 + 5 * wpRank;
161  int winValue = recogValue (SCORE_LOWER, winScore);
162  int lossValue = recogValue (SCORE_UPPER, -winScore);
163 
164  // If the enemy king is behind or equal to the pawn rank: win or unknown
165  if (bkRank <= wpRank) {
166  if ((stm == WHITE && wpRank > bkRank)
167  || (stm == BLACK && wpRank > bkRank + 1)) {
168  // Runaway pawn wins:
169  return (stm == WHITE) ? winValue : lossValue;
170  }
171  // Cannot easily determine the result of this position:
172  return UNKNOWN;
173  }
174 
175  // Black king is clearly the closest king to the pawn: draw
176  uint wdist = square_Distance (wk, wp);
177  uint bdist = square_Distance (bk, wp);
178  if (stm == WHITE) { bdist++; }
179  if (bdist + 1 < wdist && bdist + wpRank <= RANK_8 + 1) { return DRAW; }
180 
181  // Black king in front of a rook pawn: safe draw.
182  if ((wpFyle == A_FYLE || wpFyle == H_FYLE) && wpFyle == bkFyle) {
183  return DRAW;
184  }
185  // King the two squares in front of any pawn before the 6th rank: draw
186  if (wpRank < RANK_6 && wpFyle == bkFyle
187  && (wpRank + 1 == bkRank || wpRank + 2 == bkRank)) {
188  return DRAW;
189  }
190  // Pawn on 6th rank, enemy king blocking it on 7th: draw
191  if (wpRank == RANK_6 && wpFyle == bkFyle && wpRank + 1 == bkRank) {
192  return DRAW;
193  }
194 
195  // White king two ranks in front of the pawn, on the same file or an
196  // adjacent file: win
197  if (wpRank + 2 == wkRank && wpFyle != A_FYLE && wpFyle != H_FYLE && wdist < bdist) {
198  int fileDiff = (int)wpFyle - (int)wkFyle;
199  if (fileDiff >= -1 && fileDiff <= 1) {
200  return (stm == WHITE) ? winValue : lossValue;
201  }
202  }
203 
204  // Pawn-King-space-EnemyKing formation, draw if pawn is before 5th rank
205  // and side with the pawn is to move; otherwise a win.
206  if (wpFyle == wkFyle && wpFyle == bkFyle
207  && wpRank+1 == wkRank && wpRank+3 == bkRank) {
208  if (wpRank < RANK_5 && stm == WHITE) {
209  return DRAW;
210  }
211  return (stm == WHITE) ? winValue : lossValue;
212  }
213 
214  // No key KPK position was found:
215  return UNKNOWN;
216 }
217 
218 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
219 // Recognizer::KBBK
220 // Returns a recognition score for King and two Bishops vs King.
221 int
222 Recognizer::KBBK (Position * pos)
223 {
224  const byte* material = pos->GetMaterial();
225  squareT wk, bk, wb1, wb2;
226  colorT stm = pos->GetToMove();
227 
228  // Set up piece squares so that White has the bishops:
229  if (material[WB] == 2) {
230  wk = pos->GetKingSquare(WHITE);
231  bk = pos->GetKingSquare(BLACK);
232  squareT * sqlist = pos->GetList(WHITE);
233  wb1 = sqlist[1];
234  wb2 = sqlist[2];
235  } else {
236  ASSERT (material[BB] == 2);
237  wk = square_FlipRank(pos->GetKingSquare(BLACK));
238  bk = square_FlipRank(pos->GetKingSquare(WHITE));
239  squareT * sqlist = pos->GetList(BLACK);
240  wb1 = square_FlipRank(sqlist[1]);
241  wb2 = square_FlipRank(sqlist[2]);
242  stm = color_Flip(stm);
243  }
244 
245  // If the bishops are of the same square color, it is a draw:
246  if (square_Color(wb1) == square_Color(wb2)) { return DRAW; }
247 
248  // If the lone king is to move and is next to a bishop, or on the
249  // edge of the board with the enemy king nearby, it may be a draw
250  // by capturing a bishop or by stalemate:
251  if (stm == BLACK) {
252  if (square_Adjacent (bk, wb1)) { return UNKNOWN; }
253  if (square_Adjacent (bk, wb2)) { return UNKNOWN; }
254  if (square_IsEdgeSquare(bk) && square_Distance(wk, bk) == 2) {
255  return UNKNOWN;
256  }
257  }
258 
259  // Compute the lone king distances used for scoring:
260  int bkCorner = square_Distance (bk, square_NearestCorner (bk));
261  int kingDist = square_Distance (bk, wk);
262 
263  // Return a suitable winning score:
264  int score = 900 + (25 * bkCorner) - (10 * kingDist);
265  int winValue = recogValue (SCORE_LOWER, score);
266  int lossValue = recogValue (SCORE_UPPER, -score);
267  return (stm == WHITE) ? winValue : lossValue;
268 }
269 
270 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
271 // Recognizer::KBNK
272 // Returns a recognition score for King, Bishop and Knight vs King.
273 int
274 Recognizer::KBNK (Position * pos)
275 {
276  const byte* material = pos->GetMaterial();
277  const pieceT* board = pos->GetBoard();
278  squareT wk, bk, wb, wn;
279  colorT stm = pos->GetToMove();
280 
281  // Set up piece squares so that White has the bishop and knight:
282  if (material[WB] == 1) {
283  wk = pos->GetKingSquare(WHITE);
284  bk = pos->GetKingSquare(BLACK);
285  squareT * sqlist = pos->GetList(WHITE);
286  wb = sqlist[1];
287  wn = sqlist[2];
288  if (board[wb] != WB) { squareT temp = wb; wb = wn; wn = temp; }
289  } else {
290  ASSERT (material[BB] == 1 && material[BN] == 1);
291  wk = square_FlipRank(pos->GetKingSquare(BLACK));
292  bk = square_FlipRank(pos->GetKingSquare(WHITE));
293  squareT * sqlist = pos->GetList(BLACK);
294  wb = sqlist[1];
295  wn = sqlist[2];
296  if (board[wb] != BB) { squareT temp = wb; wb = wn; wn = temp; }
297  wb = square_FlipRank(wb);
298  wn = square_FlipRank(wn);
299  stm = color_Flip(stm);
300  }
301 
302  // If the lone king attacks a piece, the result is unclear:
303  if (square_Adjacent (wb, bk) || square_Adjacent (wn, bk)) {
304  return UNKNOWN;
305  }
306 
307  // If the lone king is to move and possible stalemate, unclear result:
308  if (stm == BLACK && square_IsEdgeSquare(bk)) {
309  return UNKNOWN;
310  }
311 
312  // If the knight is near a corner, it could be trapped, unclear result:
313  if ((square_Distance (wn, A1) < 2 || square_Distance (wn, A8) < 2 ||
314  square_Distance (wn, H1) < 2 || square_Distance (wn, H8) < 2)
315  && square_Distance (bk, wn) < 4) {
316  return UNKNOWN;
317  }
318 
319  // If the lone king can fork the bishop and knight, unclear result:
320  if (stm == BLACK && square_Distance(wb, wn) < 3
321  && square_Distance (bk, wb) < 3 && square_Distance (bk, wn) < 3
322  && square_Distance (wk, wb) > 1 && square_Distance (wk, wn) > 1 ) {
323  return UNKNOWN;
324  }
325 
326  // Find lone king distance from the appropriate corner
327  squareT corner1 = A1; squareT corner2 = H8;
328  if (square_Color(wb) == WHITE) { corner1 = H1; corner2 = A8; }
329  int cornerDist = square_Distance (bk, corner1);
330  int cornerDist2 = square_Distance (bk, corner2);
331  if (cornerDist2 < cornerDist) { cornerDist = cornerDist2; }
332  int kingDist = square_Distance (wk, bk);
333 
334  // Return an appropriate winning or losing score:
335  int winScore = 700 - 25 * cornerDist - 10 * kingDist;
336  int winValue = recogValue (SCORE_LOWER, winScore);
337  int lossValue = recogValue (SCORE_UPPER, -winScore);
338  return (stm == WHITE) ? winValue : lossValue;
339 }
340 
341 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
342 // Recognizer::KBPK
343 // Returns a recognition score for King, Bishop and Pawn(s) vs King.
344 // Recognizes draws with wrong-color bishop for rook pawn(s).
345 int
346 Recognizer::KBPK (Position * pos)
347 {
348  const byte* material = pos->GetMaterial();
349  squareT /* wk, */ bk;
350  fyleT wrongFile = A_FYLE; // Wrong-color bishop rook-pawn file.
351  // Set up piece squares so that White has the bishop and pawn(s),
352  // and make sure all pawns are on the wrong rook-pawn file:
353  if (material[WB] == 1) {
354  // wk = pos->GetKingSquare(WHITE);
355  bk = pos->GetKingSquare(BLACK);
356  if (pos->SquareColorCount(WB,WHITE) == 1) { wrongFile = H_FYLE; }
357  if (pos->FyleCount(WP, wrongFile) != material[WP]) { return UNKNOWN; }
358  } else {
359  ASSERT (material[BB] == 1);
360  // wk = square_FlipRank(pos->GetKingSquare(BLACK));
361  bk = square_FlipRank(pos->GetKingSquare(WHITE));
362  if (pos->SquareColorCount(BB,BLACK) == 1) { wrongFile = H_FYLE; }
363  if (pos->FyleCount(BP, wrongFile) != material[BP]) { return UNKNOWN; }
364  }
365  // OK, we have it set up so white has the bishop and pawns, and we
366  // know all pawns are on the wrong rook-pawn file. So recognise a
367  // draw if the black king controls the queening square:
368  squareT promoSq = square_Make (wrongFile, RANK_8);
369  if (bk == promoSq || square_Adjacent (bk, promoSq)) { return DRAW; }
370  // The black king does not control the queening square, so no draw yet:
371  return UNKNOWN;
372 }
373 
374 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
375 // Recognizer::KRKB
376 // Returns a recognition score for King and Rook vs King and Bishop.
377 // Contains simple rules covering many drawn positions, which were
378 // checked using tablebases.
379 int
380 Recognizer::KRKB (Position * pos)
381 {
382  const byte* material = pos->GetMaterial();
383  squareT wk, bk, wr, bb;
384  colorT stm = pos->GetToMove();
385 
386  // Find piece squares with White having the rook:
387  wk = pos->GetKingSquare(WHITE);
388  bk = pos->GetKingSquare(BLACK);
389  squareT * sqlist = pos->GetList(WHITE);
390  wr = sqlist[1];
391  sqlist = pos->GetList(BLACK);
392  bb = sqlist[1];
393  if (material[WB] == 1) {
394  squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t);
395  t = wr; wr = square_FlipRank(bb); bb = square_FlipRank(t);
396  stm = color_Flip(stm);
397  }
398 
399  // Flip board so the black king is in the 10-square a1-d1-d4 triangle:
400  if (square_Rank(bk) >= RANK_5) {
401  wk = square_FlipRank(wk); wr = square_FlipRank(wr);
402  bk = square_FlipRank(bk); bb = square_FlipRank(bb);
403  }
404  if (square_Fyle(bk) >= E_FYLE) {
405  wk = square_FlipFyle(wk); wr = square_FlipFyle(wr);
406  bk = square_FlipFyle(bk); bb = square_FlipFyle(bb);
407  }
408  if (bk == A2 || bk == A3 || bk == A4 || bk == B3 || bk == B4 || bk == C4) {
409  wk = square_FlipDiag(wk); wr = square_FlipDiag(wr);
410  bk = square_FlipDiag(bk); bb = square_FlipDiag(bb);
411  }
412 
413  int kingsDist = square_Distance(wk, bk);
414 
415  if (stm == WHITE) {
416  // Black king on c2/c3/d3/d4, black bishop adjacent,
417  // white king more than 2 squares away: draw.
418  if (kingsDist > 2 && square_Adjacent(bk,bb)
419  && (bk == C2 || bk == C3 || bk == D3 || bk == D4)) {
420  return DRAW;
421  }
422  } else {
423  // Black king anywhere but a1 or b1, black bishop adjacent,
424  // white king more than 2 squares away: draw.
425  if (kingsDist > 2 && square_Adjacent(bk,bb)
426  && bk != A1 && bk != B1) {
427  return DRAW;
428  }
429  // Black king not on edge or b2, not sharing a rank or file with
430  // the white rook; white king more than 2 squares away: draw.
431  if (kingsDist > 2 && !square_IsEdgeSquare(bk) && bk != B2
432  && square_Rank(bk) != square_Rank(wr)
433  && square_Fyle(bk) != square_Fyle(wr)) {
434  return DRAW;
435  }
436  }
437  return UNKNOWN;
438 }
439 
440 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
441 // Recognizer::KRKN
442 // Returns a recognition score for King and Rook vs King and Knight.
443 // Contains simple rules covering many drawn positions, which were
444 // checked using tablebases.
445 int
446 Recognizer::KRKN (Position * pos)
447 {
448  const byte* material = pos->GetMaterial();
449  squareT wk, bk, wr, bn;
450  colorT stm = pos->GetToMove();
451 
452  // Find piece squares with White having the rook:
453  wk = pos->GetKingSquare(WHITE);
454  bk = pos->GetKingSquare(BLACK);
455  squareT * sqlist = pos->GetList(WHITE);
456  wr = sqlist[1];
457  sqlist = pos->GetList(BLACK);
458  bn = sqlist[1];
459  if (material[WN] == 1) {
460  squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t);
461  t = wr; wr = square_FlipRank(bn); bn = square_FlipRank(t);
462  stm = color_Flip(stm);
463  }
464 
465  // Flip board so the black king is in the 10-square a1-d1-d4 triangle:
466  if (square_Rank(bk) >= RANK_5) {
467  wk = square_FlipRank(wk); wr = square_FlipRank(wr);
468  bk = square_FlipRank(bk); bn = square_FlipRank(bn);
469  }
470  if (square_Fyle(bk) >= E_FYLE) {
471  wk = square_FlipFyle(wk); wr = square_FlipFyle(wr);
472  bk = square_FlipFyle(bk); bn = square_FlipFyle(bn);
473  }
474  if (bk == A2 || bk == A3 || bk == A4 || bk == B3 || bk == B4 || bk == C4) {
475  wk = square_FlipDiag(wk); wr = square_FlipDiag(wr);
476  bk = square_FlipDiag(bk); bn = square_FlipDiag(bn);
477  }
478 
479  int kingsDist = square_Distance(wk, bk);
480 
481  if (stm == WHITE) {
482  // Black king not on edge or b2, adjacent to black knight,
483  // not sharing a rank or file with the white rook; white king
484  // more than 2 squares away: draw.
485  if (kingsDist > 2 && !square_IsEdgeSquare(bk) && bk != B2
486  && square_Adjacent (bk, bn)
487  && square_Rank(bk) != square_Rank(wr)
488  && square_Fyle(bk) != square_Fyle(wr)) {
489  return DRAW;
490  }
491  } else {
492  // Black king anywhere but a1 or b1, adjacent to the knight,
493  // white king more than 2 squares away: draw.
494  if (bk != A1 && bk != B1 && kingsDist > 2
495  && square_Adjacent (bk, bn)) {
496  return DRAW;
497  }
498  // Black king not on edge or b2, adjacent to black knight,
499  // not sharing a rank/file with the white rook: draw.
500  if (!square_IsEdgeSquare(bk) && bk != B2
501  && square_Adjacent (bk, bn)
502  && square_Rank(bk) != square_Rank(wr)
503  && square_Fyle(bk) != square_Fyle(wr)) {
504  return DRAW;
505  }
506  // Black king anywhere but a1/b1/c1/b2, adjacent to the black
507  // knight, not sharing a rank/file with the rook; white king
508  // not adjacent to the knight: draw.
509  if (bk != A1 && bk != B1 && bk != C1 && bk != B2
510  && !square_Adjacent(wk,bn) && square_Adjacent(bk,bn)
511  && square_Rank(bk) != square_Rank(wr)
512  && square_Fyle(bk) != square_Fyle(wr)) {
513  return DRAW;
514  }
515  }
516  return UNKNOWN;
517 }
518 
519 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
520 // Recognizer::KMKP
521 // Returns a recognition score for King and Minor Piece vs King and Pawn.
522 int
523 Recognizer::KMKP (Position * pos)
524 {
525  const byte* material = pos->GetMaterial();
526  squareT wk, bk, wm, bp;
527  colorT stm = pos->GetToMove();
528 
529  // Find piece squares with White having the minor piece:
530  wk = pos->GetKingSquare(WHITE);
531  bk = pos->GetKingSquare(BLACK);
532  squareT * sqlist = pos->GetList(WHITE);
533  wm = sqlist[1];
534  sqlist = pos->GetList(BLACK);
535  bp = sqlist[1];
536  if (material[WP] == 1) {
537  squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t);
538  t = wm; wm = square_FlipRank(bp); bp = square_FlipRank(t);
539  stm = color_Flip(stm);
540  }
541 
542  // Black (the side with the pawn) can only lose to trivial mates
543  // in a corner trapped by the pawn:
544  if (stm == WHITE && square_IsCornerSquare(bk)
545  && square_Adjacent(bk, bp) && square_Distance(bk, wk) == 2) {
546  return UNKNOWN;
547  }
548 
549  // Black has at least a draw:
550  return recogValue ((stm == BLACK) ? SCORE_LOWER : SCORE_UPPER, 0);
551 }
552 
553 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
554 // Recognizer::KQKP
555 // Returns a recognition score for King and Queen vs King and Pawn.
556 // Contains rules for many draws with Queen vs a2 or c2 pawn,
557 // checked using tablebases.
558 int
559 Recognizer::KQKP (Position * pos)
560 {
561  const byte* material = pos->GetMaterial();
562  squareT wk, bk, wq, bp;
563  colorT stm = pos->GetToMove();
564 
565  // Find piece squares with White having the queen:
566  wk = pos->GetKingSquare(WHITE);
567  bk = pos->GetKingSquare(BLACK);
568  squareT * sqlist = pos->GetList(WHITE);
569  wq = sqlist[1];
570  sqlist = pos->GetList(BLACK);
571  bp = sqlist[1];
572  if (material[WQ] != 1) {
573  squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t);
574  t = wq; wq = square_FlipRank(bp); bp = square_FlipRank(t);
575  stm = color_Flip(stm);
576  }
577 
578  // There are only recognizable draws with a pawn on its 7th rank,
579  // defended by its king:
580  if (square_Rank(bp) != RANK_2 || ! square_Adjacent (bk, bp)) {
581  return UNKNOWN;
582  }
583 
584  // Make sure the pawn is on the queenside:
585  if (square_Fyle(bp) >= E_FYLE) {
586  wk = square_FlipFyle(wk); wq = square_FlipFyle(wq);
587  bk = square_FlipFyle(bk); bp = square_FlipFyle(bp);
588  }
589 
590  // Lists of squares for each (black king, black pawn) pair listing
591  // the white king squares for which white to move only draws
592  // regardless of where the white queen is:
593 
594  static const squareT drawSquares_None [] = { NULL_SQUARE };
595  static const squareT drawSquares_BPa2_BKb1 [] = {
596  G1,H1,F2,G2,H2,G3,H3,F4,G4,H4,E5,F5,G5,H5,
597  A6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
599  };
600  static const squareT drawSquares_BPa2_BKb2 [] = {
601  F1,G1,H1,G2,H2,F3,G3,H3,F4,G4,H4,F5,G5,H5,
602  A6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
603  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
604  };
605  static const squareT drawSquares_BPc2_BKc1 [] = {
606  H6,A7,B7,C7,D7,E7,F7,G7,H7,
607  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
608  };
609  static const squareT drawSquares_BPc2_BKd1 [] = {
610  F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
611  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
612  };
613  static const squareT drawSquares_BPc2_BKd2 [] = {
614  F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
615  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
616  };
617 
618  const squareT * drawSquares = drawSquares_None;
619  if (bp == A2) {
620  if (bk == B1) { drawSquares = drawSquares_BPa2_BKb1; }
621  if (bk == B2) { drawSquares = drawSquares_BPa2_BKb2; }
622  } else if (bp == C2) {
623  if (bk == C1) { drawSquares = drawSquares_BPc2_BKc1; }
624  if (bk == D1) { drawSquares = drawSquares_BPc2_BKd1; }
625  if (bk == D2) { drawSquares = drawSquares_BPc2_BKd2; }
626  }
627 
628  // Scan the list of drawn squares for the white king square:
629  while (*drawSquares != NULL_SQUARE) {
630  if (wk == *drawSquares) { return DRAW; }
631  drawSquares++;
632  }
633 
634  return UNKNOWN;
635 }
636 
637 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
638 // Recognizer::KRKP
639 // Returns a recognition score for King and Rook vs King and Pawn.
640 // Contains rules for many draws, checked using tablebases.
641 int
642 Recognizer::KRKP (Position * pos)
643 {
644  const byte* material = pos->GetMaterial();
645  squareT wk, bk, wr, bp;
646  colorT stm = pos->GetToMove();
647 
648  // Find piece squares with White having the rook:
649  wk = pos->GetKingSquare(WHITE);
650  bk = pos->GetKingSquare(BLACK);
651  squareT * sqlist = pos->GetList(WHITE);
652  wr = sqlist[1];
653  sqlist = pos->GetList(BLACK);
654  bp = sqlist[1];
655  if (material[WR] != 1) {
656  squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t);
657  t = wr; wr = square_FlipRank(bp); bp = square_FlipRank(t);
658  stm = color_Flip(stm);
659  }
660 
661  // There are only recognized draws when the pawn is defended by its king:
662  if (! square_Adjacent (bk, bp)) {
663  return UNKNOWN;
664  }
665 
666  // Make sure the pawn is on the queenside:
667  if (square_Fyle(bp) >= E_FYLE) {
668  wk = square_FlipFyle(wk); wr = square_FlipFyle(wr);
669  bk = square_FlipFyle(bk); bp = square_FlipFyle(bp);
670  }
671 
672  // Lists of squares for each (black king, black pawn) pair listing
673  // the white king squares for which white to move only draws
674  // regardless of where the white rook is:
675 
676  static const squareT drawSquares_None [] = { NULL_SQUARE };
677  static const squareT drawSquares_BPa2_BKb2 [] = {
679  };
680  static const squareT drawSquares_BPa2_BKb3 [] = {
681  E1,F1,G1,H1,D4,E4,F4,G4,H4,A5,B5,C5,D5,E5,F5,G5,H5,A6,B6,C6,
682  D6,E6,F6,G6,H6,A7,B7, NULL_SQUARE
683  };
684  static const squareT drawSquares_BPa3_BKb2 [] = {
685  E1,F1,G1,H1,E2,F2,G2,H2,D3,E3,F3,G3,H3,D4,E4,F4,G4,H4,D5,E5,
686  F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,
687  B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
688  };
689  static const squareT drawSquares_BPa3_BKb3 [] = {
690  F1,G1,H1,F2,G2,H2,F3,G3,H3,D4,E4,F4,G4,H4,D5,E5,F5,G5,H5,A6,
691  B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,
692  F8,G8,H8, NULL_SQUARE
693  };
694  static const squareT drawSquares_BPa3_BKb4 [] = {
695  G1,H1,G2,H2,G3,H3,G4,H4,D5,E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,
696  H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
697  };
698  static const squareT drawSquares_BPa4_BKa3 [] = {
699  H1,H2,H3,H4,H5,H6,H7,H8, NULL_SQUARE
700  };
701  static const squareT drawSquares_BPa4_BKa5 [] = {
702  A7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
703  };
704  static const squareT drawSquares_BPa4_BKb3 [] = {
705  G1,H1,G2,H2,G3,H3,G4,H4,E5,F5,G5,H5,E6,F6,G6,H6,A7,B7,C7,D7,
706  E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
707  };
708  static const squareT drawSquares_BPa4_BKb4 [] = {
709  H1,H2,H3,H4,H5,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,
710  C8,D8,E8,F8,G8,H8, NULL_SQUARE
711  };
712  static const squareT drawSquares_BPa4_BKb5 [] = {
713  A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
714  };
715  static const squareT drawSquares_BPa5_BKb4 [] = {
716  E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
717  };
718  static const squareT drawSquares_BPa5_BKb5 [] = {
719  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
720  };
721  static const squareT drawSquares_BPb2_BKa2 [] = {
722  E1,F1,G1,H1,E2,F2,G2,H2,E3,F3,G3,H3,D4,E4,F4,G4,H4,B5,C5,D5,
723  E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
724  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
725  };
726  static const squareT drawSquares_BPb2_BKa3 [] = {
727  F2,G2,H2,F3,G3,H3,F4,G4,H4,A5,E5,G5,H5,A6,B6,C6,D6,E6,F6,H6,
728  A7,B7,C7,D7,E7,F7,G7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
729  };
730  static const squareT drawSquares_BPb2_BKb3 [] = {
731  F2,G2,H2,F3,G3,H3,F4,G4,H4,A5,B5,C5,D5,E5,G5,H5,A6,B6,C6,D6,
732  E6,F6,H6,A7,B7,C7,D7,E7,F7,G7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
733  };
734  static const squareT drawSquares_BPb2_BKc1 [] = {
735  F1,G1,H1,F2,G2,H2,E3,F3,G3,H3,A4,D4,E4,F4,G4,H4,A5,C5,D5,E5,
736  F5,G5,H5,A6,C6,D6,E6,F6,G6,H6,A7,C7,D7,E7,F7,G7,H7,A8,C8,D8,
737  E8,F8,G8,H8, NULL_SQUARE
738  };
739  static const squareT drawSquares_BPb2_BKc2 [] = {
740  E1,E2,E3,C4,D4, NULL_SQUARE
741  };
742  static const squareT drawSquares_BPb2_BKc3 [] = {
743  E3,A5,B5,C5,D5,E5,A6,B6,C6,D6,A7,B7,C7,A8,B8,C8, NULL_SQUARE
744  };
745  static const squareT drawSquares_BPb3_BKa2 [] = {
746  F1,G1,H1,F2,G2,H2,F3,G3,H3,F4,G4,H4,E5,F5,G5,H5,B6,C6,D6,E6,
747  F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
748  };
749  static const squareT drawSquares_BPb3_BKa3 [] = {
750  G1,H1,G2,H2,G3,H3,G4,H4,G5,H5,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,
751  H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
752  };
753  static const squareT drawSquares_BPb3_BKa4 [] = {
754  H1,H2,H3,H4,H5,H6,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
755  };
756  static const squareT drawSquares_BPb3_BKb2 [] = {
757  G1,H1,G2,H2,G3,H3,G4,H4,F5,G5,H5,F6,G6,H6,A7,B7,C7,D7,E7,F7,
758  G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
759  };
760  static const squareT drawSquares_BPb3_BKb4 [] = {
761  G1,H1,G2,H2,G3,H3,G4,H4,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,
762  B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
763  };
764  static const squareT drawSquares_BPb3_BKc2 [] = {
765  F1,G1,H1,G2,H2,E3,F3,G3,H3,E4,F4,G4,H4,A5,B5,D5,E5,F5,G5,H5,
766  A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,
767  E8,F8,G8,H8, NULL_SQUARE
768  };
769  static const squareT drawSquares_BPb3_BKc3 [] = {
770  G1,H1,G2,H2,G3,H3,E4,F4,G4,H4,C5,D5,E5,F5,G5,H5,A6,B6,C6,D6,
771  E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8,
772  NULL_SQUARE
773  };
774  static const squareT drawSquares_BPb3_BKc4 [] = {
775  H1,H2,H3,H4,E5,F5,G5,H5,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,
776  G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
777  };
778  static const squareT drawSquares_BPb4_BKa3 [] = {
779  H1,H2,H3,H4,H5,H6,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
780  };
781  static const squareT drawSquares_BPb4_BKa4 [] = {
782  G7,H7,F8,G8,H8, NULL_SQUARE
783  };
784  static const squareT drawSquares_BPb4_BKa5 [] = {
785  H8, NULL_SQUARE
786  };
787  static const squareT drawSquares_BPb4_BKb3 [] = {
788  H6,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
789  };
790  static const squareT drawSquares_BPb4_BKc3 [] = {
791  H1,H2,H3,H4,E5,F5,G5,H5,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,
792  H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
793  };
794  static const squareT drawSquares_BPb4_BKc4 [] = {
795  D6,E6,F6,G6,H6,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
796  };
797  static const squareT drawSquares_BPb4_BKc5 [] = {
798  E7,F7,G7,H7,E8,F8,G8,H8, NULL_SQUARE
799  };
800  static const squareT drawSquares_BPb5_BKc4 [] = {
801  E7,F7,G7,H7,E8,F8,G8,H8, NULL_SQUARE
802  };
803  static const squareT drawSquares_BPb5_BKc5 [] = {
804  F8,G8,H8, NULL_SQUARE
805  };
806  static const squareT drawSquares_BPc2_BKb2 [] = {
807  A4,B4,B5,B6,B7,B8, NULL_SQUARE
808  };
809  static const squareT drawSquares_BPc2_BKb3 [] = {
810  A5,B5,C5,D5,A6,B6,C6,D6,B7,C7,D7,E7,B8,C8,D8,E8, NULL_SQUARE
811  };
812  static const squareT drawSquares_BPc2_BKd1 [] = {
813  G1,H1,G2,H2,F3,G3,H3,A4,B4,E4,F4,G4,H4,A5,B5,D5,E5,F5,G5,H5,
814  A6,B6,D6,E6,F6,G6,H6,A7,B7,D7,E7,F7,G7,H7,A8,B8,D8,E8,F8,G8,
815  H8, NULL_SQUARE
816  };
817  static const squareT drawSquares_BPc2_BKd3 [] = {
818  F3,B5,C5,D5,E5,F5,A6,B6,C6,D6,E6,A7,B7,C7,D7,A8,B8,C8,D8, NULL_SQUARE
819  };
820  static const squareT drawSquares_BPc3_BKb2 [] = {
821  G1,H1,G2,H2,G3,H3,G4,H4,A5,C5,D5,E5,F5,G5,H5,A6,B6,C6,D6,E6,
822  F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
823  };
824  static const squareT drawSquares_BPc3_BKb3 [] = {
825  H1,H2,H3,H4,A5,B5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,
826  F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
827  };
828  static const squareT drawSquares_BPc3_BKb4 [] = {
829  A6,B6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
830  };
831  static const squareT drawSquares_BPc3_BKc2 [] = {
832  H1,H2,H3,H4,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,
833  G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
834  };
835  static const squareT drawSquares_BPc3_BKc4 [] = {
836  H1,H2,H3,H4,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,
837  G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
838  };
839  static const squareT drawSquares_BPc3_BKd2 [] = {
840  G1,H1,H2,F3,G3,H3,F4,G4,H4,A5,B5,C5,E5,F5,G5,H5,A6,B6,C6,D6,
841  E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8,
842  NULL_SQUARE
843  };
844  static const squareT drawSquares_BPc3_BKd3 [] = {
845  H1,H2,H3,F4,G4,H4,D5,E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,
846  B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
847  };
848  static const squareT drawSquares_BPc3_BKd4 [] = {
849  F5,G5,H5,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,
850  E8,F8,G8,H8, NULL_SQUARE
851  };
852  static const squareT drawSquares_BPc4_BKb3 [] = {
853  A6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
854  };
855  static const squareT drawSquares_BPc4_BKb4 [] = {
856  A6,A7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
857  };
858  static const squareT drawSquares_BPc4_BKc3 [] = {
859  F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
860  };
861  static const squareT drawSquares_BPc4_BKd3 [] = {
862  F5,G5,H5,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,
863  F8,G8,H8, NULL_SQUARE
864  };
865  static const squareT drawSquares_BPc4_BKd4 [] = {
866  E6,F6,G6,H6,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
867  };
868  static const squareT drawSquares_BPc4_BKd5 [] = {
869  F7,G7,H7,F8,G8,H8, NULL_SQUARE
870  };
871  static const squareT drawSquares_BPd2_BKc1 [] = {
872  G1,H1,G2,H2,A3,G3,H3,A4,B4,E4,F4,G4,H4,A5,B5,E5,F5,G5,H5,A6,
873  B6,E6,F6,G6,H6,A7,B7,E7,F7,G7,H7,A8,B8,E8,F8,G8,H8, NULL_SQUARE
874  };
875  static const squareT drawSquares_BPd2_BKc3 [] = {
876  A3,A5,B5,C5,D5,E5,B6,C6,D6,E6,C7,D7,E7,F7,C8,D8,E8,F8, NULL_SQUARE
877  };
878  static const squareT drawSquares_BPd2_BKd1 [] = {
879  H1,H2,H3,A4,G4,H4,A5,B5,C5,D5,E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,
880  G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
881  };
882  static const squareT drawSquares_BPd2_BKd3 [] = {
883  H2,H3,H4,A5,B5,C5,D5,E5,F5,G5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,
884  C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
885  };
886  static const squareT drawSquares_BPd2_BKe1 [] = {
887  A1,H1,A2,H2,A3,G3,H3,A4,B4,C4,F4,G4,H4,A5,B5,C5,E5,F5,G5,H5,
888  A6,B6,C6,E6,F6,G6,H6,A7,B7,C7,E7,F7,G7,H7,A8,B8,C8,E8,F8,G8,
889  H8, NULL_SQUARE
890  };
891  static const squareT drawSquares_BPd2_BKe3 [] = {
892  G3,C5,D5,E5,F5,G5,C6,D6,E6,F6,B7,C7,D7,E7,B8,C8,D8,E8, NULL_SQUARE
893  };
894  static const squareT drawSquares_BPd3_BKc2 [] = {
895  H1,H2,A3,H3,A4,H4,A5,B5,D5,E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,
896  H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
897  };
898  static const squareT drawSquares_BPd3_BKc3 [] = {
899  A4,A5,B5,C5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,
900  A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
901  };
902  static const squareT drawSquares_BPd3_BKc4 [] = {
903  A5,A6,B6,C6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8,
904  NULL_SQUARE
905  };
906  static const squareT drawSquares_BPd3_BKd2 [] = {
907  H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,
908  D8,E8,F8,G8,H8, NULL_SQUARE
909  };
910  static const squareT drawSquares_BPd3_BKd4 [] = {
911  H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,
912  D8,E8,F8,G8,H8, NULL_SQUARE
913  };
914  static const squareT drawSquares_BPd3_BKe2 [] = {
915  H1,H2,G3,H3,G4,H4,A5,B5,C5,D5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,
916  H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
917  };
918  static const squareT drawSquares_BPd3_BKe3 [] = {
919  G4,H4,E5,F5,G5,H5,A6,B6,C6,D6,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,
920  G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
921  };
922  static const squareT drawSquares_BPd3_BKe4 [] = {
923  G5,H5,E6,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,
924  G8,H8, NULL_SQUARE
925  };
926  static const squareT drawSquares_BPd4_BKc3 [] = {
927  A5,A6,B6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
928  };
929  static const squareT drawSquares_BPd4_BKc4 [] = {
930  A6,B6,A7,B7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
931  };
932  static const squareT drawSquares_BPd4_BKc5 [] = {
933  A7,A8, NULL_SQUARE
934  };
935  static const squareT drawSquares_BPd4_BKd3 [] = {
936  A7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
937  };
938  static const squareT drawSquares_BPd4_BKd5 [] = {
939  A8,B8,F8,G8,H8, NULL_SQUARE
940  };
941  static const squareT drawSquares_BPd4_BKe3 [] = {
942  G5,H5,F6,G6,H6,A7,B7,C7,D7,E7,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,
943  H8, NULL_SQUARE
944  };
945  static const squareT drawSquares_BPd4_BKe4 [] = {
946  F6,G6,H6,F7,G7,H7,A8,B8,C8,D8,E8,F8,G8,H8, NULL_SQUARE
947  };
948  static const squareT drawSquares_BPd4_BKe5 [] = {
949  G7,H7,G8,H8, NULL_SQUARE
950  };
951 
952  const squareT * drawSquares = drawSquares_None;
953  if (bp == A2) {
954  if (bk == B2) { drawSquares = drawSquares_BPa2_BKb2; }
955  else if (bk == B3) { drawSquares = drawSquares_BPa2_BKb3; }
956  } else if (bp == A3) {
957  if (bk == B2) { drawSquares = drawSquares_BPa3_BKb2; }
958  else if (bk == B3) { drawSquares = drawSquares_BPa3_BKb3; }
959  else if (bk == B4) { drawSquares = drawSquares_BPa3_BKb4; }
960  } else if (bp == A4) {
961  if (bk == A3) { drawSquares = drawSquares_BPa4_BKa3; }
962  else if (bk == A5) { drawSquares = drawSquares_BPa4_BKa5; }
963  else if (bk == B3) { drawSquares = drawSquares_BPa4_BKb3; }
964  else if (bk == B4) { drawSquares = drawSquares_BPa4_BKb4; }
965  else if (bk == B5) { drawSquares = drawSquares_BPa4_BKb5; }
966  } else if (bp == A5) {
967  if (bk == B4) { drawSquares = drawSquares_BPa5_BKb4; }
968  else if (bk == B5) { drawSquares = drawSquares_BPa5_BKb5; }
969  } else if (bp == B2) {
970  if (bk == A2) { drawSquares = drawSquares_BPb2_BKa2; }
971  else if (bk == A3) { drawSquares = drawSquares_BPb2_BKa3; }
972  else if (bk == B3) { drawSquares = drawSquares_BPb2_BKb3; }
973  else if (bk == C1) { drawSquares = drawSquares_BPb2_BKc1; }
974  else if (bk == C2) { drawSquares = drawSquares_BPb2_BKc2; }
975  else if (bk == C3) { drawSquares = drawSquares_BPb2_BKc3; }
976  } else if (bp == B3) {
977  if (bk == A2) { drawSquares = drawSquares_BPb3_BKa2; }
978  else if (bk == A3) { drawSquares = drawSquares_BPb3_BKa3; }
979  else if (bk == A4) { drawSquares = drawSquares_BPb3_BKa4; }
980  else if (bk == B2) { drawSquares = drawSquares_BPb3_BKb2; }
981  else if (bk == B4) { drawSquares = drawSquares_BPb3_BKb4; }
982  else if (bk == C2) { drawSquares = drawSquares_BPb3_BKc2; }
983  else if (bk == C3) { drawSquares = drawSquares_BPb3_BKc3; }
984  else if (bk == C4) { drawSquares = drawSquares_BPb3_BKc4; }
985  } else if (bp == B4) {
986  if (bk == A3) { drawSquares = drawSquares_BPb4_BKa3; }
987  else if (bk == A4) { drawSquares = drawSquares_BPb4_BKa4; }
988  else if (bk == A5) { drawSquares = drawSquares_BPb4_BKa5; }
989  else if (bk == B3) { drawSquares = drawSquares_BPb4_BKb3; }
990  else if (bk == C3) { drawSquares = drawSquares_BPb4_BKc3; }
991  else if (bk == C4) { drawSquares = drawSquares_BPb4_BKc4; }
992  else if (bk == C5) { drawSquares = drawSquares_BPb4_BKc5; }
993  } else if (bp == B5) {
994  if (bk == C4) { drawSquares = drawSquares_BPb5_BKc4; }
995  else if (bk == C5) { drawSquares = drawSquares_BPb5_BKc5; }
996  } else if (bp == C2) {
997  if (bk == B2) { drawSquares = drawSquares_BPc2_BKb2; }
998  else if (bk == B3) { drawSquares = drawSquares_BPc2_BKb3; }
999  else if (bk == D1) { drawSquares = drawSquares_BPc2_BKd1; }
1000  else if (bk == D3) { drawSquares = drawSquares_BPc2_BKd3; }
1001  } else if (bp == C3) {
1002  if (bk == B2) { drawSquares = drawSquares_BPc3_BKb2; }
1003  else if (bk == B3) { drawSquares = drawSquares_BPc3_BKb3; }
1004  else if (bk == B4) { drawSquares = drawSquares_BPc3_BKb4; }
1005  else if (bk == C2) { drawSquares = drawSquares_BPc3_BKc2; }
1006  else if (bk == C4) { drawSquares = drawSquares_BPc3_BKc4; }
1007  else if (bk == D2) { drawSquares = drawSquares_BPc3_BKd2; }
1008  else if (bk == D3) { drawSquares = drawSquares_BPc3_BKd3; }
1009  else if (bk == D4) { drawSquares = drawSquares_BPc3_BKd4; }
1010  } else if (bp == C4) {
1011  if (bk == B3) { drawSquares = drawSquares_BPc4_BKb3; }
1012  else if (bk == B4) { drawSquares = drawSquares_BPc4_BKb4; }
1013  else if (bk == C3) { drawSquares = drawSquares_BPc4_BKc3; }
1014  else if (bk == D3) { drawSquares = drawSquares_BPc4_BKd3; }
1015  else if (bk == D4) { drawSquares = drawSquares_BPc4_BKd4; }
1016  else if (bk == D5) { drawSquares = drawSquares_BPc4_BKd5; }
1017  } else if (bp == D2) {
1018  if (bk == C1) { drawSquares = drawSquares_BPd2_BKc1; }
1019  else if (bk == C3) { drawSquares = drawSquares_BPd2_BKc3; }
1020  else if (bk == D1) { drawSquares = drawSquares_BPd2_BKd1; }
1021  else if (bk == D3) { drawSquares = drawSquares_BPd2_BKd3; }
1022  else if (bk == E1) { drawSquares = drawSquares_BPd2_BKe1; }
1023  else if (bk == E3) { drawSquares = drawSquares_BPd2_BKe3; }
1024  } else if (bp == D3) {
1025  if (bk == C2) { drawSquares = drawSquares_BPd3_BKc2; }
1026  else if (bk == C3) { drawSquares = drawSquares_BPd3_BKc3; }
1027  else if (bk == C4) { drawSquares = drawSquares_BPd3_BKc4; }
1028  else if (bk == D2) { drawSquares = drawSquares_BPd3_BKd2; }
1029  else if (bk == D4) { drawSquares = drawSquares_BPd3_BKd4; }
1030  else if (bk == E2) { drawSquares = drawSquares_BPd3_BKe2; }
1031  else if (bk == E3) { drawSquares = drawSquares_BPd3_BKe3; }
1032  else if (bk == E4) { drawSquares = drawSquares_BPd3_BKe4; }
1033  } else if (bp == D4) {
1034  if (bk == C3) { drawSquares = drawSquares_BPd4_BKc3; }
1035  else if (bk == C4) { drawSquares = drawSquares_BPd4_BKc4; }
1036  else if (bk == C5) { drawSquares = drawSquares_BPd4_BKc5; }
1037  else if (bk == D3) { drawSquares = drawSquares_BPd4_BKd3; }
1038  else if (bk == D5) { drawSquares = drawSquares_BPd4_BKd5; }
1039  else if (bk == E3) { drawSquares = drawSquares_BPd4_BKe3; }
1040  else if (bk == E4) { drawSquares = drawSquares_BPd4_BKe4; }
1041  else if (bk == E5) { drawSquares = drawSquares_BPd4_BKe5; }
1042  }
1043 
1044  // Scan the list of drawn squares for the white king square:
1045  while (*drawSquares != NULL_SQUARE) {
1046  if (wk == *drawSquares) { return DRAW; }
1047  drawSquares++;
1048  }
1049 
1050  return UNKNOWN;
1051 }
1052 
1053 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1054 // Recognizer::KRPKR
1055 // Returns a recognition score for King, Rook and Pawn vs King and Rook.
1056 // Contains rules for some draws, checked using tablebases.
1057 int
1058 Recognizer::KRPKR (Position * pos)
1059 {
1060 
1061  // Incomplete but correct
1062 
1063  const byte* material = pos->GetMaterial();
1064  const pieceT* board = pos->GetBoard();
1065  squareT wk, bk, wr, wp, br;
1066  colorT stm = pos->GetToMove();
1067 
1068  // Set up piece squares so that White has the pawn:
1069  if (material[WP] == 1) {
1070  wk = pos->GetKingSquare(WHITE);
1071  bk = pos->GetKingSquare(BLACK);
1072  squareT * sqlist = pos->GetList(WHITE);
1073  wr = sqlist[1];
1074  wp = sqlist[2];
1075  if (board[wr] != WR) { squareT temp = wr; wr = wp; wp = temp; }
1076  sqlist = pos->GetList(BLACK);
1077  br = sqlist[1];
1078  } else {
1079  wk = square_FlipRank(pos->GetKingSquare(BLACK));
1080  bk = square_FlipRank(pos->GetKingSquare(WHITE));
1081  squareT * sqlist = pos->GetList(BLACK);
1082  wr = sqlist[1];
1083  wp = sqlist[2];
1084  if (board[wr] != BR) { squareT temp = wr; wr = wp; wp = temp; }
1085  wr = square_FlipRank(wr);
1086  wp = square_FlipRank(wp);
1087  sqlist = pos->GetList(WHITE);
1088  br = square_FlipRank(sqlist[1]);
1089  stm = color_Flip(stm);
1090  }
1091 
1092  // Make sure the pawn is on the queenside:
1093  if (square_Fyle(wp) >= E_FYLE) {
1094  wk = square_FlipFyle(wk); wr = square_FlipFyle(wr);
1095  wp = square_FlipFyle(wp);
1096  bk = square_FlipFyle(bk); br = square_FlipFyle(br);
1097  }
1098 
1099  // Get ranks and files of piece squares:
1100  int wkRank = square_Rank(wk); int wkFyle = square_Fyle(wk);
1101  int wrRank = square_Rank(wr); int wrFyle = square_Fyle(wr);
1102  int wpRank = square_Rank(wp); int wpFyle = square_Fyle(wp);
1103  int bkRank = square_Rank(bk); int bkFyle = square_Fyle(bk);
1104  int brRank = square_Rank(br); int brFyle = square_Fyle(br);
1105 
1106  // No draws recognized if the black king is behind the pawn:
1107  if (bkRank < wpRank) { return UNKNOWN; }
1108 
1109  // We cannot recognize draws if the rooks share a rank or file:
1110  if (wrRank == brRank || wrFyle == brFyle) { return UNKNOWN; }
1111 
1112  // Designate side-to-move king,rook as sk and sr, enemy as ek and er
1113  squareT /* sk, sr, er, */ ek;
1114  int /* skRank, srRank, */ ekRank, erRank;
1115  int /* skFyle, srFyle, */ ekFyle, erFyle;
1116  if (stm == WHITE) {
1117  ek = bk; // sk = wk; sr = wr; er = br;
1118  // skRank = wkRank; skFyle = wkFyle; srRank = wrRank; srFyle = wrFyle;
1119  ekRank = bkRank; ekFyle = bkFyle; erRank = brRank; erFyle = brFyle;
1120  } else {
1121  ek = wk; /// sk = bk; sr = br; er = wr;
1122  // skRank = bkRank; skFyle = bkFyle; srRank = brRank; srFyle = brFyle;
1123  ekRank = wkRank; ekFyle = wkFyle; erRank = wrRank; erFyle = wrFyle;
1124  }
1125  uint kingDist = square_Distance (wk, bk);
1126 
1127  // No recognition if the king and rook of the side NOT to move share
1128  // a rank or file, since there may be a pin or skewer.
1129  if (ekRank == erRank || ekFyle == erFyle) { return UNKNOWN; }
1130 
1131  // No draws if the side NOT to move king and rook nearly share a
1132  // rank or file (that is, are on adjacent ranks or files) and the
1133  // king is on an edge, or the enemy king is only 2 squares away.
1134  // This can lead to loss of a rook, e.g. WK=d1 WR=a2 and ...Rh1+
1135  // or BK=d6 BR=h7 WK=d4 and Ra6+ wins the rook.
1136  if (square_IsEdgeSquare(ek) || kingDist == 2) {
1137  int rankDiff = (int)ekRank - (int)erRank;
1138  if (rankDiff >= -1 && rankDiff <= 1) { return UNKNOWN; }
1139  int fyleDiff = (int)ekFyle - (int)erFyle;
1140  if (fyleDiff >= -1 && fyleDiff <= 1) { return UNKNOWN; }
1141  }
1142 
1143  // No recognition if either king attacks the enemy rook:
1144  if (square_Adjacent (wk, br)) { return UNKNOWN; }
1145  if (square_Adjacent (bk, wr)) { return UNKNOWN; }
1146 
1147  // No recognition if the white pawn attacks the black rook:
1148  if (square_Move (wp, UP_LEFT) == br) { return UNKNOWN; }
1149  if (square_Move (wp, UP_RIGHT) == br) { return UNKNOWN; }
1150 
1151  // Philidor and more:
1152  // white pawn and king are on 5th rank or lower, on any file;
1153  // black rook has higher rank than white king and pawn, up to rank 6;
1154  // black king is on pawn file or adjacent, ranked higher than black rook;
1155  // Drawn for white or black to move.
1156 
1157  if (wpRank <= RANK_5 && wkRank <= RANK_5
1158  && brRank <= RANK_6 && brRank > wpRank && brRank > wkRank
1159  && bkRank > brRank && bkRank > RANK_4) {
1160 
1161  // Only exception: WK=a1, WP=b2, WR=b1; White may be checkmated.
1162  if (wk == A1 && wp == B2 && wr == B1) { return UNKNOWN; }
1163 
1164  // black king on the pawn file
1165  if (bkFyle == wpFyle && (brRank == RANK_6 || wrFyle != bkFyle)) {
1166  return DRAW;
1167  }
1168 
1169  // black king on adjacent file
1170  if ((bkFyle == wpFyle + 1 || bkFyle == wpFyle - 1)
1171  && brFyle != wpFyle && wrFyle != bkFyle) {
1172  return DRAW;
1173  }
1174  }
1175 
1176  // Sixth-rank pawn draws:
1177  // white pawn on 6th rank; black king on pawn file on 7th/8th rank;
1178  // black rook anywhere on 1st rank; white king on 6th rank or less;
1179  // white rook and black king are not on same rank.
1180  if (wpRank == RANK_6 && bkFyle == wpFyle && bkRank >= RANK_7
1181  && brRank == RANK_1 && wkRank <= RANK_6 && wrRank != bkRank) {
1182  // Black to move: draw
1183  if (stm == BLACK) { return DRAW; }
1184  // White to move: draw if the kings are > 2 squares apart, and
1185  // the white king and black rook do not share a rank or file.
1186  if (wkRank != brRank && wkFyle != brFyle
1187  && square_Distance(wk,bk) > 2) {
1188  return DRAW;
1189  }
1190  }
1191 
1192  // TODO: Common a-pawn draws.
1193  if (wpFyle == A_FYLE) {
1194  // ....
1195  }
1196 
1197  return UNKNOWN;
1198 }
1199 
1200 //////////////////////////////////////////////////////////////////////
1201 // EOF: recog.cpp
1202 //////////////////////////////////////////////////////////////////////
unsigned char byte
Definition: common.h:89
squareT square_FlipRank(squareT sq)
Definition: common.h:426
const squareT F5
Definition: common.h:352
const squareT F2
Definition: common.h:349
const pieceT BB
Definition: common.h:242
uint square_Distance(squareT from, squareT to)
Definition: common.h:454
const squareT C5
Definition: common.h:352
const squareT C4
Definition: common.h:351
const colorT WHITE
Definition: common.h:207
const squareT C8
Definition: common.h:355
const pieceT BN
Definition: common.h:242
const squareT B3
Definition: common.h:350
const squareT F4
Definition: common.h:351
int Recognize(Position *pos)
Definition: recog.cpp:45
const squareT F8
Definition: common.h:355
colorT square_Color(squareT sq)
Definition: common.h:410
const squareT H1
Definition: common.h:348
const squareT NULL_SQUARE
Definition: common.h:357
const squareT A4
Definition: common.h:351
byte rankT
Definition: common.h:107
const squareT D2
Definition: common.h:349
uint FyleCount(pieceT p, fyleT f) const
Definition: position.h:180
const squareT G6
Definition: common.h:353
const rankT RANK_2
Definition: common.h:360
constexpr squareT square_Move(squareT sq, directionT dir)
Definition: sqmove.h:273
#define ASSERT(f)
Definition: common.h:59
const squareT H7
Definition: common.h:354
const squareT C1
Definition: common.h:348
const rankT RANK_8
Definition: common.h:361
const directionT UP_LEFT
Definition: common.h:556
const pieceT BQ
Definition: common.h:242
squareT square_FlipDiag(squareT sq)
Definition: common.h:434
const squareT H4
Definition: common.h:351
const pieceT WQ
Definition: common.h:241
const squareT B5
Definition: common.h:352
squareT GetKingSquare(colorT c)
Definition: position.h:208
const pieceT BP
Definition: common.h:242
const colorT BLACK
Definition: common.h:208
const scoreFlagT SCORE_LOWER
Definition: engine.h:53
const squareT E7
Definition: common.h:354
rankT square_Rank(squareT sq)
Definition: common.h:390
byte fyleT
Definition: common.h:108
const fyleT H_FYLE
Definition: common.h:366
const squareT * GetList(colorT c) const
Definition: position.h:169
const squareT G5
Definition: common.h:352
bool square_IsCornerSquare(squareT sq)
Definition: common.h:475
const squareT D7
Definition: common.h:354
const squareT A8
Definition: common.h:355
colorT color_Flip(colorT c)
Definition: common.h:214
const squareT E6
Definition: common.h:353
uint TotalMaterial()
Definition: position.h:172
const squareT H6
Definition: common.h:353
const squareT A1
Definition: common.h:348
squareT square_Make(fyleT f, rankT r)
Definition: common.h:377
const squareT A7
Definition: common.h:354
const squareT B4
Definition: common.h:351
const squareT A6
Definition: common.h:353
const directionT UP_RIGHT
Definition: common.h:557
const pieceT * GetBoard() const
Definition: position.h:197
const squareT F6
Definition: common.h:353
const pieceT WB
Definition: common.h:241
const squareT G1
Definition: common.h:348
const squareT F7
Definition: common.h:354
const squareT H3
Definition: common.h:350
const fyleT E_FYLE
Definition: common.h:365
uint32_t uint
Definition: common.h:91
Definition: board.tcl:276
const squareT H2
Definition: common.h:349
const squareT B2
Definition: common.h:349
const squareT C2
Definition: common.h:349
squareT square_FlipFyle(squareT sq)
Definition: common.h:418
const squareT H5
Definition: common.h:352
const squareT H8
Definition: common.h:355
const rankT RANK_5
Definition: common.h:360
const squareT A3
Definition: common.h:350
const squareT B1
Definition: common.h:348
squareT square_NearestCorner(squareT sq)
Definition: common.h:465
const squareT G8
Definition: common.h:355
const squareT G7
Definition: common.h:354
const squareT D1
Definition: common.h:348
const squareT B8
Definition: common.h:355
bool square_IsEdgeSquare(squareT sq)
Definition: common.h:481
const scoreFlagT SCORE_NONE
Definition: engine.h:51
const squareT B7
Definition: common.h:354
const squareT E5
Definition: common.h:352
const squareT C6
Definition: common.h:353
const squareT D6
Definition: common.h:353
const squareT G3
Definition: common.h:350
const scoreFlagT SCORE_EXACT
Definition: engine.h:52
const pieceT WP
Definition: common.h:241
const squareT E2
Definition: common.h:349
uint SquareColorCount(pieceT p, colorT sqColor)
Definition: position.h:192
materialw
Definition: board.tcl:1506
colorT GetToMove() const
Definition: position.h:162
const scoreFlagT SCORE_UPPER
Definition: engine.h:54
const squareT A2
Definition: common.h:349
const squareT E8
Definition: common.h:355
const squareT D3
Definition: common.h:350
const squareT D4
Definition: common.h:351
const rankT RANK_6
Definition: common.h:360
const byte * GetMaterial() const
Definition: position.h:158
const squareT E3
Definition: common.h:350
byte colorT
Definition: common.h:104
const squareT B6
Definition: common.h:353
const pieceT BR
Definition: common.h:242
const squareT F3
Definition: common.h:350
const pieceT WN
Definition: common.h:241
const squareT E1
Definition: common.h:348
const squareT D5
Definition: common.h:352
const squareT G4
Definition: common.h:351
bool square_Adjacent(squareT from, squareT to)
Definition: common.h:677
const rankT RANK_1
Definition: common.h:360
int recogValue(scoreFlagT flag, int score)
Definition: recog.h:21
const squareT E4
Definition: common.h:351
const squareT G2
Definition: common.h:349
const fyleT A_FYLE
Definition: common.h:365
const rankT RANK_4
Definition: common.h:360
const squareT A5
Definition: common.h:352
const rankT RANK_7
Definition: common.h:361
const squareT C3
Definition: common.h:350
const squareT F1
Definition: common.h:348
const squareT C7
Definition: common.h:354
byte squareT
Definition: common.h:105
const squareT D8
Definition: common.h:355
byte pieceT
Definition: common.h:103
fyleT square_Fyle(squareT sq)
Definition: common.h:384
const pieceT WR
Definition: common.h:241