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