Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
position.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 //
3 // FILE: position.cpp
4 // Position class methods
5 //
6 // Part of: Scid (Shane's Chess Information Database)
7 // Version: 3.5
8 //
9 // Notice: Copyright (c) 1999-2003 Shane Hudson. All rights reserved.
10 //
11 // Author: Shane Hudson (sgh@users.sourceforge.net)
12 //
13 //////////////////////////////////////////////////////////////////////
14 
15 #include "common.h"
16 #include "position.h"
17 #include "attacks.h"
18 #include "misc.h"
19 #include "hash.h"
20 #include "sqmove.h"
21 #include "dstring.h"
22 #include "movegen.h"
23 #include <algorithm>
24 
25 static uint hashVal [16][64];
26 static uint stdStartHash = 0;
27 static uint stdStartPawnHash = 0;
28 
29 // HASH and UNHASH are identical: XOR the hash value for a (piece,square).
30 #define HASH(h,p,sq) (h) ^= hashVal[(p)][(sq)]
31 #define UNHASH(h,p,sq) (h) ^= hashVal[(p)][(sq)]
32 
33 inline void
34 Position::AddHash (pieceT p, squareT sq)
35 {
36  HASH (Hash, p, sq);
37  if (piece_Type(p) == PAWN) {
38  HASH (PawnHash, p, sq);
39  }
40 }
41 
42 inline void
43 Position::UnHash (pieceT p, squareT sq)
44 {
45  UNHASH (Hash, p, sq);
46  if (piece_Type(p) == PAWN) {
47  UNHASH (PawnHash, p, sq);
48  }
49 }
50 
51 inline void
52 Position::AddToBoard (pieceT p, squareT sq)
53 {
54  ASSERT (Board[sq] == EMPTY);
55  Board[sq] = p;
56  NumOnRank[p][square_Rank(sq)]++;
57  NumOnFyle[p][square_Fyle(sq)]++;
58  NumOnLeftDiag[p][square_LeftDiag(sq)]++;
59  NumOnRightDiag[p][square_RightDiag(sq)]++;
60  NumOnSquareColor[p][square_Color(sq)]++;
61  AddHash (p, sq);
62 }
63 
64 inline void
65 Position::RemoveFromBoard (pieceT p, squareT sq)
66 {
67  ASSERT (Board[sq] == p);
68  Board[sq] = EMPTY;
69  NumOnRank[p][square_Rank(sq)]--;
70  NumOnFyle[p][square_Fyle(sq)]--;
71  NumOnLeftDiag[p][square_LeftDiag(sq)]--;
72  NumOnRightDiag[p][square_RightDiag(sq)]--;
73  NumOnSquareColor[p][square_Color(sq)]--;
74  UnHash (p, sq);
75 }
76 
77 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78 // initHashValues:
79 // Initialises the table of Zobrist hash values.
80 static void initHashValues (void)
81 {
82  // Ensure we set up the hash values only once:
83  static int firstCall = 1;
84  if (! firstCall) { return; }
85  firstCall = 0;
86 
87 
88  // First, set all values to 0:
89  uint sq;
90  for (uint p = 0; p < 16; p++) {
91  for (sq = A1; sq <= H8; sq++) { hashVal[p][sq] = 0; }
92  }
93 
94  // Fill in the hash values for each valid [piece][square] index,
95  // using a table of pre-generated good values:
96  const unsigned int * hash = goodHashValues;
97  for (sq=A1; sq <= H8; sq++) { hashVal[WK][sq] = *hash; hash++; }
98  for (sq=A1; sq <= H8; sq++) { hashVal[WQ][sq] = *hash; hash++; }
99  for (sq=A1; sq <= H8; sq++) { hashVal[WR][sq] = *hash; hash++; }
100  for (sq=A1; sq <= H8; sq++) { hashVal[WB][sq] = *hash; hash++; }
101  for (sq=A1; sq <= H8; sq++) { hashVal[WN][sq] = *hash; hash++; }
102  for (sq=A1; sq <= H8; sq++) { hashVal[WP][sq] = *hash; hash++; }
103  for (sq=A1; sq <= H8; sq++) { hashVal[BK][sq] = *hash; hash++; }
104  for (sq=A1; sq <= H8; sq++) { hashVal[BQ][sq] = *hash; hash++; }
105  for (sq=A1; sq <= H8; sq++) { hashVal[BR][sq] = *hash; hash++; }
106  for (sq=A1; sq <= H8; sq++) { hashVal[BB][sq] = *hash; hash++; }
107  for (sq=A1; sq <= H8; sq++) { hashVal[BN][sq] = *hash; hash++; }
108  for (sq=A1; sq <= H8; sq++) { hashVal[BP][sq] = *hash; hash++; }
109 
110  // Compute the hash values for the standard starting position:
111  uint h = 0;
112  // First the pawns:
113  HASH (h,WP,A2); HASH (h,WP,B2); HASH (h,WP,C2); HASH (h,WP,D2);
114  HASH (h,WP,E2); HASH (h,WP,F2); HASH (h,WP,G2); HASH (h,WP,H2);
115  HASH (h,BP,A7); HASH (h,BP,B7); HASH (h,BP,C7); HASH (h,BP,D7);
116  HASH (h,BP,E7); HASH (h,BP,F7); HASH (h,BP,G7); HASH (h,BP,H7);
117  stdStartPawnHash = h;
118  // Now the nonpawns:
119  HASH (h,WR,A1); HASH (h,WN,B1); HASH (h,WB,C1); HASH (h,WQ,D1);
120  HASH (h,WK,E1); HASH (h,WB,F1); HASH (h,WN,G1); HASH (h,WR,H1);
121  HASH (h,BR,A8); HASH (h,BN,B8); HASH (h,BB,C8); HASH (h,BQ,D8);
122  HASH (h,BK,E8); HASH (h,BB,F8); HASH (h,BN,G8); HASH (h,BR,H8);
123  stdStartHash = h;
124 }
125 
126 
127 ///////////////////////////////////////////////////////////////////////////
128 // sqDir[][]: Array listing the direction between any two squares.
129 // For example, sqDir[A1][B2] == UP_RIGHT, and sqDir[A1][C2] == NULL_DIR.
132 {
134  // Initialise the sqDir[][] array of directions between every pair
135  // of squares.
136  squareT i, j;
137  directionT dirArray[] = { UP, DOWN, LEFT, RIGHT, UP_LEFT, UP_RIGHT,
139  // First, set everything to NULL_DIR:
140  for (i=A1; i <= NS; i++) {
141  for (j=A1; j <= NS; j++) {
142  sqDir[i][j] = NULL_DIR;
143  }
144  }
145  // Now fill in the valid directions:
146  for (i=A1; i <= H8; i++) {
147  directionT * dirptr = dirArray;
148  while (*dirptr != NULL_DIR) {
149  j = square_Move (i, *dirptr);
150  while (j != NS) {
151  sqDir[i][j] = *dirptr;
152  j = square_Move (j, *dirptr);
153  }
154  dirptr++;
155  }
156  }
157  }
159 
160 ///////////////////////////////////////////////////////////////////////////
161 // PRIVATE FUNCTIONS -- small ones are inline for speed
162 
163 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164 // Position::CalcPinsDir():
165 // Look for a pinned piece in the direction 'dir' relative to
166 // the position of the king to move.
167 //
168 inline void
169 Position::CalcPinsDir (directionT dir, pieceT attacker)
170 {
171  // Two pieces can pin along any path. A queen is always one,
172  // the other is a bishop or rook. To save calculating it here, the
173  // appropriate piece (BISHOP) or (ROOK) is passed along with the
174  // direction.
175 
176  squareT king = GetKingSquare (ToMove);
177  squareT friendly = NULL_SQUARE;
178  squareT x = king;
179  squareT last = square_Last (king, dir);
180  int delta = direction_Delta (dir);
181 
182  while (x != last) {
183  x += delta;
184  pieceT p = Board[x];
185  if (p == EMPTY) {
186  // Empty square, so keep searching.
187  } else if (piece_Color_NotEmpty(p) == ToMove) {
188  // Found a friendly piece.
189  if (friendly == NULL_SQUARE) {
190  // Found first friendly in this direction
191  friendly = x;
192  } else {
193  // Found second friendly in this direction, so stop.
194  return;
195  }
196  } else {
197  // Found an enemy piece
198  if (friendly != NULL_SQUARE) {
199  // Potential pin:
200  pieceT ptype = piece_Type(p);
201  if (ptype == QUEEN || ptype == attacker) {
202  Pinned[ListPos[friendly]] = dir;
203  }
204  }
205  return; // found an enemy piece, so end search
206  }
207  }
208  return;
209 }
210 
211 
212 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
213 // Position::AddLegalMove():
214 // Add a legal move to the move list.
215 //
216 inline void
217 Position::AddLegalMove (MoveList * mlist, squareT from, squareT to, pieceT promo)
218 {
219  ASSERT (mlist != NULL);
220  // We do NOT set the pre-move castling/ep flags, or the captured
221  // piece info, here since that is ONLY needed if the move is
222  // going to be executed with DoSimpleMove() and then undone.
223  mlist->emplace_back(from, to, promo, Board[from], Board[to]);
224 }
225 
226 
227 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228 // Position::GenSliderMoves():
229 // Generate slider moves along a direction, for a sliding
230 // piece of the specified color from the specified square.
231 // If sqset != NULL, moves must be to a square in sqset.
232 inline void
233 Position::GenSliderMoves (MoveList * mlist, colorT color, squareT fromSq,
234  directionT dir, SquareSet * sqset, bool capturesOnly)
235 {
236  squareT dest = fromSq;
237  squareT last = square_Last (fromSq, dir);
238  int delta = direction_Delta (dir);
239 
240  while (dest != last) {
241  dest += delta;
242  pieceT p = Board[dest];
243  if (p == EMPTY) {
244  if (! capturesOnly) {
245  if (sqset == NULL || sqset->Contains(dest)) {
246  AddLegalMove (mlist, fromSq, dest, EMPTY);
247  }
248  }
249  continue;
250  }
251  // We have reached a piece. Add the capture if it is an enemy.
252  if (piece_Color_NotEmpty(p) != color) {
253  if (sqset == NULL || sqset->Contains(dest)) {
254  AddLegalMove (mlist, fromSq, dest, EMPTY);
255  }
256  }
257  break;
258  }
259 }
260 
261 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
262 // Position::GenKnightMoves():
263 // Generate knight moves.
264 // If sqset != NULL, moves must be to a square in sqset.
265 inline void
266 Position::GenKnightMoves (MoveList * mlist, colorT c, squareT fromSq,
267  SquareSet * sqset, bool capturesOnly)
268 {
269  const squareT * destPtr = knightAttacks[fromSq];
270  while (true) {
271  squareT dest = *destPtr;
272  if (dest == NULL_SQUARE) { break; }
273  destPtr++;
274  pieceT p = Board[dest];
275  if (capturesOnly && p == EMPTY) { continue; }
276  if (piece_Color(p) != c) {
277  if (sqset == NULL || sqset->Contains(dest)) {
278  AddLegalMove (mlist, fromSq, dest, EMPTY);
279  }
280  }
281  }
282 }
283 
284 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
285 // Position::GenCastling():
286 // Generate the legal castling moves.
287 // Assumes the side to move is NOT in check, so the caller
288 // should verify this first.
289 //
290 void
291 Position::GenCastling (MoveList * mlist)
292 {
293  ASSERT (! IsKingInCheck());
294  squareT from = GetKingSquare(ToMove);
295  if (from != (ToMove == WHITE ? E1 : E8)) { return; }
296  squareT enemyKingSq = GetEnemyKingSquare();
297  squareT target, skip, rookSq;
298  pieceT rookPiece;
299 
300  // Try kingside first
301 
302  // Kingside Castling:
303  if (GetCastling (ToMove, KSIDE)) {
304  if (ToMove == WHITE) {
305  target = G1; skip = F1; rookSq = H1; rookPiece = WR;
306  } else {
307  target = G8; skip = F8; rookSq = H8; rookPiece = BR;
308  }
309  if (Board[target] == EMPTY && Board[skip] == EMPTY
310  && Board[rookSq] == rookPiece
311  && CalcNumChecks (target) == 0
312  && CalcNumChecks (skip) == 0
313  && ! square_Adjacent (target, enemyKingSq)) {
314  AddLegalMove (mlist, from, target, EMPTY);
315  }
316  }
317 
318  // Queenside Castling:
319  if (GetCastling (ToMove, QSIDE)) {
320  if (ToMove == WHITE) {
321  target = C1; skip = D1; rookSq = A1; rookPiece = WR;
322  } else {
323  target = C8; skip = D8; rookSq = A8; rookPiece = BR;
324  }
325  if (Board[target] == EMPTY && Board[skip] == EMPTY
326  && Board[rookSq] == rookPiece
327  && Board[target - 1] == EMPTY // B1 or B8 must be empty too!
328  && CalcNumChecks (target) == 0
329  && CalcNumChecks (skip) == 0
330  && ! square_Adjacent (target, enemyKingSq)) {
331  AddLegalMove (mlist, from, target, EMPTY);
332  }
333  }
334 }
335 
336 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337 // Position::GenKingMoves():
338 // Generate the legal King moves. Castling is generated as well, if
339 // the specified flag is true.
340 //
341 void
342 Position::GenKingMoves (MoveList * mlist, genMovesT genType, bool castling)
343 {
344  squareT kingSq = GetKingSquare();
345  squareT enemyKingSq = GetEnemyKingSquare();
346  colorT enemy = color_Flip(ToMove);
347  const squareT * destPtr;
348  pieceT king = piece_Make (ToMove, KING);
349  bool genNonCaptures = (genType & GEN_NON_CAPS);
350 
351  ASSERT (Board[kingSq] == king);
352 
353  destPtr = kingAttacks[kingSq];
354  while (*destPtr != NULL_SQUARE) {
355  // Try this move and see if it legal:
356 
357  squareT destSq = *destPtr;
358  bool addThisMove = false;
359 
360  // Only try this move if the target square has an enemy piece,
361  // or if it is empty and noncaptures are to be generated:
362  if ( (genNonCaptures && Board[destSq] == EMPTY)
363  || piece_Color (Board[destSq]) == enemy) {
364 
365  // Empty or enemy piece there, so try the move:
366  pieceT captured = Board[destSq];
367  Board[destSq] = king;
368  Board[kingSq] = EMPTY;
369 
370  // It is legal if the two kings will not be adjacent and the
371  // moving king will not be in check on its new square:
372  if (! square_Adjacent (destSq, enemyKingSq)) {
373  if (CalcNumChecks (destSq) == 0) {
374  addThisMove = true;
375  }
376  }
377  Board[kingSq] = king;
378  Board[destSq] = captured;
379  }
380  if (addThisMove) { AddLegalMove (mlist, kingSq, destSq, EMPTY); }
381  destPtr++;
382  }
383  // Now generate castling moves, if possible:
384  if (genNonCaptures && castling) { GenCastling (mlist); }
385 }
386 
387 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
388 // Position::AddPromotions():
389 // Add promotion moves.
390 // Called by GenPawnMoves() when a pawn can be promoted.
391 //
392 inline void
393 Position::AddPromotions (MoveList * mlist, squareT from, squareT dest)
394 {
395  ASSERT (piece_Type (Board[from]) == PAWN);
396  ASSERT (square_Rank (dest) == RANK_1 || square_Rank (dest) == RANK_8);
397 
398  AddLegalMove (mlist, from, dest, QUEEN);
399  AddLegalMove (mlist, from, dest, ROOK);
400  AddLegalMove (mlist, from, dest, BISHOP);
401  AddLegalMove (mlist, from, dest, KNIGHT);
402 }
403 
404 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
405 // Position::IsValidEnPassant
406 // Used to verify that an en passant pawn capture is valid.
407 // This is needed because illegal en passant captures can appear
408 // legal according to calculations of pinned pieces. For example,
409 // consider WK d5, WP e5, BP f5 (just moved there), BR h5 and
410 // the en passant capture exf6 would be illegal.
411 inline bool
412 Position::IsValidEnPassant (squareT from, squareT to)
413 {
414  ASSERT (from <= H8 && to <= H8);
415  ASSERT (to == EPTarget);
416 
417  // Check that this en passant capture is legal:
418  pieceT ownPawn = piece_Make(ToMove, PAWN);
419  pieceT enemyPawn = piece_Make (color_Flip(ToMove), PAWN);
420  squareT enemyPawnSq = (ToMove == WHITE) ? to - 8 : to + 8;
421  ASSERT (Board[from] == ownPawn);
422  ASSERT (Board[enemyPawnSq] == enemyPawn);
423  Board[from] = EMPTY;
424 
425  // PG
426  Board[to] = ownPawn;
427 
428  Board[enemyPawnSq] = EMPTY;
429  bool isValid = ! IsKingInCheck();
430 
431  //PG
432  Board[to] = EMPTY;
433 
434  Board[from] = ownPawn;
435  Board[enemyPawnSq] = enemyPawn;
436  return isValid;
437 }
438 
439 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
440 // Position::GenPawnMoves():
441 // Generate legal pawn moves.
442 // If dir != NULL_DIR, pawn MUST move in direction dir or its opposite.
443 // If sqset != NULL, pawn MUST move to a square in sqset.
444 // The dir and sq parameters are for pinned pawns and check evasions.
445 void
446 Position::GenPawnMoves (MoveList * mlist, squareT from,
447  directionT dir, SquareSet * sqset, genMovesT genType)
448 {
449  bool genNonCaptures = (genType & GEN_NON_CAPS);
450  directionT oppdir = direction_Opposite(dir);
451  directionT forward;
452  rankT promoRank;
453  rankT secondRank;
454  if (ToMove == WHITE) {
455  forward = UP; promoRank = RANK_8; secondRank = RANK_2;
456  } else {
457  forward = DOWN; promoRank = RANK_1; secondRank = RANK_7;
458  }
459  squareT dest;
460 
461  ASSERT (Board[from] == piece_Make (ToMove, PAWN));
462 
463  if (genNonCaptures
464  && (dir == NULL_DIR || dir == forward || oppdir == forward)) {
465  dest = square_Move (from, forward);
466  if (Board[dest]==EMPTY && (sqset==NULL || sqset->Contains(dest))) {
467  if (square_Rank(dest) == promoRank) {
468  AddPromotions (mlist, from, dest);
469  } else {
470  AddLegalMove (mlist, from, dest, EMPTY);
471  }
472  }
473  if (square_Rank(from) == secondRank && Board[dest] == EMPTY) {
474  dest = square_Move (dest, forward);
475  if (Board[dest]==EMPTY && (sqset==NULL || sqset->Contains(dest))) {
476  AddLegalMove (mlist, from, dest, EMPTY);
477  }
478  }
479  }
480 
481  // Now do captures: left, then right
482  // To be a possible capture, dest square must be EPTarget or hold
483  // an enemy piece.
484 #define POSSIBLE_CAPTURE(d) ((d != NULL_SQUARE) \
485  && ((piece_Color (Board[d]) == (color_Flip(ToMove))) \
486  || (d == EPTarget && IsValidEnPassant(from,d))))
487 
488  directionT capdir = forward | LEFT;
489  if (dir == NULL_DIR || dir == capdir || oppdir == capdir) {
490  dest = square_Move (from, capdir);
491  if (POSSIBLE_CAPTURE(dest) && (sqset==NULL || sqset->Contains(dest))) {
492  if (square_Rank(dest) == promoRank) {
493  AddPromotions (mlist, from, dest);
494  } else {
495  AddLegalMove (mlist, from, dest, EMPTY);
496  }
497  }
498  }
499  capdir = forward | RIGHT;
500  if (dir == NULL_DIR || dir == capdir || oppdir == capdir) {
501  dest = square_Move (from, capdir);
502  if (POSSIBLE_CAPTURE(dest) && (sqset==NULL || sqset->Contains(dest))) {
503  if (square_Rank(dest) == promoRank) {
504  AddPromotions (mlist, from, dest);
505  } else {
506  AddLegalMove (mlist, from, dest, EMPTY);
507  }
508  }
509  }
510  return;
511 }
512 
513 
514 //////////////////////////////////////////////////////////////////////
515 // PUBLIC FUNCTIONS
516 
517 
518 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
519 // Position::GetHPSig():
520 // Return the position's home pawn signature.
521 //
522 uint
524 {
525  uint hpSig = 0;
526  pieceT * b = &(Board[A2]);
527  if (*b == WP) { hpSig |= 0x8000; } b++; /* a2 */
528  if (*b == WP) { hpSig |= 0x4000; } b++; /* b2 */
529  if (*b == WP) { hpSig |= 0x2000; } b++; /* c2 */
530  if (*b == WP) { hpSig |= 0x1000; } b++; /* d2 */
531  if (*b == WP) { hpSig |= 0x0800; } b++; /* e2 */
532  if (*b == WP) { hpSig |= 0x0400; } b++; /* f2 */
533  if (*b == WP) { hpSig |= 0x0200; } b++; /* g2 */
534  if (*b == WP) { hpSig |= 0x0100; } /* h2 */
535  b = &(Board[A7]);
536  if (*b == BP) { hpSig |= 0x0080; } b++; /* a7 */
537  if (*b == BP) { hpSig |= 0x0040; } b++; /* b7 */
538  if (*b == BP) { hpSig |= 0x0020; } b++; /* c7 */
539  if (*b == BP) { hpSig |= 0x0010; } b++; /* d7 */
540  if (*b == BP) { hpSig |= 0x0008; } b++; /* e7 */
541  if (*b == BP) { hpSig |= 0x0004; } b++; /* f7 */
542  if (*b == BP) { hpSig |= 0x0002; } b++; /* g7 */
543  if (*b == BP) { hpSig |= 0x0001; } /* h7 */
544  return hpSig;
545 }
546 
548  // Setting up a valid board is left to StdStart() or Clear().
549  Board [COLOR_SQUARE] = EMPTY;
550  Board [NULL_SQUARE] = END_OF_BOARD;
551 
552  // Make sure all tables used for move generation, hashing,
553  // square tests, etc have been computed:
554  initHashValues();
555 }
556 
557 
558 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
559 // Position::Clear():
560 // Clear the board and associated structures.
561 //
562 void
564 {
565  int i;
566  for (i=A1; i <= H8; i++) { Board[i] = EMPTY; }
567  for (i=WK; i <= BP; i++) {
568  Material[i] = 0;
569  for (uint j=0; j < 8; j++) {
570  NumOnRank[i][j] = NumOnFyle[i][j] = 0;
571  }
572  for (uint d=0; d < 15; d++) {
573  NumOnLeftDiag[i][d] = NumOnRightDiag[i][d] = 0;
574  }
575  NumOnSquareColor[i][WHITE] = NumOnSquareColor[i][BLACK] = 0;
576  }
577  Count[WHITE] = Count[BLACK] = 0;
578  EPTarget = NULL_SQUARE;
579  Castling = 0;
580  Board [NULL_SQUARE] = END_OF_BOARD;
581  PlyCounter = 0;
582  HalfMoveClock = 0;
583  Hash = 0;
584  PawnHash = 0;
585  return;
586 }
587 
588 
589 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
590 // Position::StdStart():
591 // Set up the standard chess starting position. For performance the data is copied from a
592 // template.
593 //
595 {
596  static Position startPositionTemplate;
597  static bool init = true;
598 
599  if (init){
600  init = false;
601  Position* p = &startPositionTemplate;
602  p->Clear();
603  p->Material[WK] = p->Material[BK] = 1;
604  p->Material[WQ] = p->Material[BQ] = 1;
605  p->Material[WR] = p->Material[BR] = 2;
606  p->Material[WB] = p->Material[BB] = 2;
607  p->Material[WN] = p->Material[BN] = 2;
608  p->Material[WP] = p->Material[BP] = 8;
609  p->Count[WHITE] = p->Count[BLACK] = 16;
610 
611  p->AddToBoard(WK, E1); p->List[WHITE][0] = E1; p->ListPos[E1] = 0;
612  p->AddToBoard(BK, E8); p->List[BLACK][0] = E8; p->ListPos[E8] = 0;
613  p->AddToBoard(WR, A1); p->List[WHITE][1] = A1; p->ListPos[A1] = 1;
614  p->AddToBoard(BR, A8); p->List[BLACK][1] = A8; p->ListPos[A8] = 1;
615  p->AddToBoard(WN, B1); p->List[WHITE][2] = B1; p->ListPos[B1] = 2;
616  p->AddToBoard(BN, B8); p->List[BLACK][2] = B8; p->ListPos[B8] = 2;
617  p->AddToBoard(WB, C1); p->List[WHITE][3] = C1; p->ListPos[C1] = 3;
618  p->AddToBoard(BB, C8); p->List[BLACK][3] = C8; p->ListPos[C8] = 3;
619  p->AddToBoard(WQ, D1); p->List[WHITE][4] = D1; p->ListPos[D1] = 4;
620  p->AddToBoard(BQ, D8); p->List[BLACK][4] = D8; p->ListPos[D8] = 4;
621  p->AddToBoard(WB, F1); p->List[WHITE][5] = F1; p->ListPos[F1] = 5;
622  p->AddToBoard(BB, F8); p->List[BLACK][5] = F8; p->ListPos[F8] = 5;
623  p->AddToBoard(WN, G1); p->List[WHITE][6] = G1; p->ListPos[G1] = 6;
624  p->AddToBoard(BN, G8); p->List[BLACK][6] = G8; p->ListPos[G8] = 6;
625  p->AddToBoard(WR, H1); p->List[WHITE][7] = H1; p->ListPos[H1] = 7;
626  p->AddToBoard(BR, H8); p->List[BLACK][7] = H8; p->ListPos[H8] = 7;
627 
628  for (uint i=0; i < 8; i++) {
629  p->AddToBoard(WP, A2+i); p->List[WHITE][i+8] = A2+i; p->ListPos[A2+i] = i+8;
630  p->AddToBoard(BP, A7+i); p->List[BLACK][i+8] = A7+i; p->ListPos[A7+i] = i+8;
631  }
632 
633  p->Castling = 0;
634  p->SetCastling (WHITE, QSIDE, true); p->SetCastling (WHITE, KSIDE, true);
635  p->SetCastling (BLACK, QSIDE, true); p->SetCastling (BLACK, KSIDE, true);
636  p->EPTarget = NULL_SQUARE;
637  p->ToMove = WHITE;
638  p->PlyCounter = 0;
639  p->HalfMoveClock = 0;
640  p->Board [NULL_SQUARE] = END_OF_BOARD;
641  p->Hash = stdStartHash;
642  p->PawnHash = stdStartPawnHash;
643  }
644  return startPositionTemplate;
645 }
646 
647 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
648 // Position::IsStdStart
649 // Returns true if the position is the standard starting position.
650 bool Position::IsStdStart() const {
651  if (ToMove != WHITE
652  || Hash != stdStartHash || PawnHash != stdStartPawnHash
653  || GetCount(WHITE) != 16 || GetCount(BLACK) != 16
654  || RankCount(WP,RANK_2) != 8 || RankCount(BP,RANK_7) != 8
655  || RankCount(WN,RANK_1) != 2 || RankCount(BN,RANK_8) != 2
658  return false;
659  }
660  return true;
661 }
662 
663 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
664 // Position::AddPiece():
665 // Add a piece to the board and piecelist.
666 // Checks that a side cannot have more than 16 pieces or more
667 // than one king.
668 //
669 errorT
671 {
672  ASSERT (p != EMPTY);
673  colorT c = piece_Color(p);
674  if ((c != WHITE && c != BLACK) || Count[c] > 15)
675  return ERROR_PieceCount;
676 
677  if (piece_Type(p) == KING) {
678  // Check there is not already a King:
679  if (Material[p] > 0) { return ERROR_PieceCount; }
680 
681  // King is always at the start of the piecelist, so move the piece
682  // already at location 0 if there is one:
683  if (Count[c] > 0) {
684  squareT oldsq = List[c][0];
685  List[c][Count[c]] = oldsq;
686  ListPos[oldsq] = Count[c];
687  }
688  List[c][0] = sq;
689  ListPos[sq] = 0;
690  } else {
691  ListPos[sq] = Count[c];
692  List[c][Count[c]] = sq;
693  }
694  Count[c]++;
695  Material[p]++;
696  AddToBoard (p, sq);
697  return OK;
698 }
699 
700 
701 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
702 // Position::CalcPins():
703 // Calculate the pieces for the side to move that are
704 // pinned to their king. The array Pinned[] stores, for
705 // each piece, the direction in which it is pinned.
706 //
707 // For example WK on e1, WQ on e2, BQ on e7 on the e-fyle
708 // means the WQ is Pinned in the direction UP.
709 //
710 void
712 {
713  Pinned[ 0] = Pinned[ 1] = Pinned[ 2] = Pinned[ 3] = Pinned[ 4] =
714  Pinned[ 5] = Pinned[ 6] = Pinned[ 7] = Pinned[ 8] = Pinned[ 9] =
715  Pinned[10] = Pinned[11] = Pinned[12] = Pinned[13] = Pinned[14] =
716  Pinned[15] = NULL_DIR;
717 
718  squareT kingSq = GetKingSquare (ToMove);
719  colorT enemy = color_Flip (ToMove);
720  pieceT enemyQueen = piece_Make (enemy, QUEEN);
721  pieceT enemyRook = piece_Make (enemy, ROOK);
722  pieceT enemyBishop = piece_Make (enemy, BISHOP);
723 
724  // Pins and checks from Bishops/Queens/Rooks:
725  fyleT fyle = square_Fyle (kingSq);
726  if (FyleCount(enemyQueen,fyle) + FyleCount(enemyRook,fyle) > 0) {
727  CalcPinsDir (UP, ROOK);
728  CalcPinsDir (DOWN, ROOK);
729  }
730  rankT rank = square_Rank (kingSq);
731  if (RankCount(enemyQueen,rank) + RankCount(enemyRook,rank) > 0) {
732  CalcPinsDir (LEFT, ROOK);
733  CalcPinsDir (RIGHT, ROOK);
734  }
735  leftDiagT ld = square_LeftDiag (kingSq);
736  if (LeftDiagCount(enemyQueen,ld) + LeftDiagCount(enemyBishop,ld) > 0) {
737  CalcPinsDir (UP_LEFT, BISHOP);
738  CalcPinsDir (DOWN_RIGHT, BISHOP);
739  }
740  rightDiagT rd = square_RightDiag (kingSq);
741  if (RightDiagCount(enemyQueen,rd) + RightDiagCount(enemyBishop,rd) > 0) {
742  CalcPinsDir (UP_RIGHT, BISHOP);
743  CalcPinsDir (DOWN_LEFT, BISHOP);
744  }
745 }
746 
747 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
748 // Position::GenPieceMoves():
749 // Generates moves for a nonpawn, nonking piece.
750 // If sqset != NULL, moves must be to a square in sqset.<
751 void
753  SquareSet * sqset, bool capturesOnly)
754 {
755  colorT c = ToMove;
756  pieceT p = Board[fromSq];
757  pieceT ptype = piece_Type(p);
758  ASSERT (p != EMPTY && ptype != KING && ptype != PAWN);
759 
760  if (ptype == KNIGHT) {
761  GenKnightMoves (mlist, c, fromSq, sqset, capturesOnly);
762  return;
763  }
764  if (ptype != BISHOP) {
765  GenSliderMoves (mlist, c, fromSq, UP, sqset, capturesOnly);
766  GenSliderMoves (mlist, c, fromSq, DOWN, sqset, capturesOnly);
767  GenSliderMoves (mlist, c, fromSq, LEFT, sqset, capturesOnly);
768  GenSliderMoves (mlist, c, fromSq, RIGHT, sqset, capturesOnly);
769  }
770  if (ptype != ROOK) {
771  GenSliderMoves (mlist, c, fromSq, UP_LEFT, sqset, capturesOnly);
772  GenSliderMoves (mlist, c, fromSq, DOWN_LEFT, sqset, capturesOnly);
773  GenSliderMoves (mlist, c, fromSq, UP_RIGHT, sqset, capturesOnly);
774  GenSliderMoves (mlist, c, fromSq, DOWN_RIGHT, sqset, capturesOnly);
775  }
776 }
777 
778 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
779 // Position::GenerateMoves
780 // Generate the legal moves list.
781 // If the specified pieceType is not EMPTY, then only legal
782 // moves for that type of piece are generated.
783 void
785  genMovesT genType, bool maybeInCheck)
786 {
787  ASSERT(mlist != NULL);
788 
789  bool genNonCaptures = (genType & GEN_NON_CAPS);
790  bool capturesOnly = !genNonCaptures;
791 
792  uint mask = 0;
793  if (pieceType != EMPTY) {
794  mask = 1 << pieceType;
795  } else {
796  mask = (1 << KING) | (1 << QUEEN) | (1 << ROOK)
797  | (1 << BISHOP) | (1 << KNIGHT) | (1 << PAWN);
798  }
799 
800  // Use the objects own move list if none was provided:
801  mlist->Clear();
802 
803  // Compute which pieces of the side to move are pinned to the king:
804  CalcPins();
805 
806  // Determine if the side to move is in check and find where the
807  // checking pieces are, unless the caller has passed maybeInCheck=false
808  // indicating it is CERTAIN the side to move is not in check here.
809 
810  uint numChecks = 0;
811  if (maybeInCheck) {
812  SquareList checkSquares;
813  numChecks = CalcNumChecks (GetKingSquare(ToMove), &checkSquares);
814  if (numChecks > 0) {
815  // The side to move IS in check:
816  GenCheckEvasions (mlist, pieceType, genType, &checkSquares);
817  return;
818  }
819  }
820 
821  // The side to move is NOT in check. Iterate over each non-king
822  // piece, and then generate King moves last of all:
823 
824  uint npieces = Count[ToMove];
825  for (uint x = 1; x < npieces; x++) {
826  squareT sq = List[ToMove][x];
827  pieceT p = Board[sq];
828  pieceT ptype = piece_Type(p);
829  if (! (mask & (1 << ptype))) { continue; }
830  directionT pinned = Pinned[x];
831 
832  // If Pinned[x] == dir (not NULL_DIR), x can ONLY move along
833  // that direction or its opposite.
834 
835  if (pinned != NULL_DIR) { // piece x is pinned to king
836  if (ptype == PAWN) {
837  GenPawnMoves (mlist, sq, pinned, NULL, genType);
838  } else if (ptype == KNIGHT) {
839  // do nothing -- pinned knights cannot move
840  } else {
841  // Piece is a pinned Queen/Rook/Bishop. Only generate
842  // moves along the pinned direction and its opposite:
843  if (ptype == QUEEN
844  || (ptype == ROOK && !direction_IsDiagonal(pinned))
845  || (ptype == BISHOP && direction_IsDiagonal(pinned))) {
846  GenSliderMoves (mlist, ToMove, sq, pinned, NULL, capturesOnly);
847  GenSliderMoves (mlist, ToMove, sq, dirOpposite[pinned],
848  NULL, capturesOnly);
849  }
850  }
851  } else {
852  // This piece is free to move anywhere
853  if (ptype == PAWN) {
854  GenPawnMoves (mlist, sq, NULL_DIR, NULL, genType);
855  } else {
856  // Knight/Queen/Bishop/Rook:
857  GenPieceMoves (mlist, sq, NULL, capturesOnly);
858  }
859  }
860  }
861 
862  // Lastly, king moves...
863  if (mask & (1 << KING)) {
864  bool castling = !numChecks;
865  GenKingMoves (mlist, genType, castling);
866  }
867 }
868 
869 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
870 // Position::IsLegalMove
871 // Determines whether the specified move is legal in this position,
872 // without requiring move generation (except for castling moves).
873 bool
875  squareT from = sm->from;
876  squareT to = sm->to;
877  if (from > H8 || to > H8) { return false; }
878  if (from == to) { return false; }
879  pieceT mover = Board[from];
880  pieceT captured = Board[to];
881  if (piece_Color(mover) != ToMove) { return false; }
882  if (piece_Color(captured) == ToMove) { return false; }
883  if (sm->movingPiece != mover) { return false; }
884  mover = piece_Type (mover);
885  if (sm->promote != EMPTY && mover != PAWN) { return false; }
886 
887  if (mover == PAWN) {
888  rankT rfrom = square_Rank(from);
889  rankT rto = square_Rank(to);
890  if (ToMove == BLACK) { rfrom = RANK_8 - rfrom; rto = RANK_8 - rto; }
891  int rdiff = (int)rto - (int)rfrom;
892  int fdiff = (int)square_Fyle(to) - (int)square_Fyle(from);
893  if (rdiff < 1 || rdiff > 2) { return false; }
894  if (fdiff < -1 || fdiff > 1) { return false; }
895  if (fdiff == 0) { // Pawn push:
896  if (captured != EMPTY) { return false; }
897  if (rdiff == 2) { // Two-square push:
898  if (rfrom != RANK_2) { return false; }
899  // Make sure the square in between is empty:
900  squareT midsquare = from + ((to - from) / 2);
901  if (Board[midsquare] != EMPTY) { return false; }
902  }
903  } else { // Pawn capture:
904  if (rdiff != 1) { return false; }
905  if (captured == EMPTY) {
906  // It must be en passant, or illegal
907  if (to != EPTarget) { return false; }
908  }
909  }
910  // Check the promotion piece:
911  if (rto == RANK_8) {
912  pieceT p = sm->promote;
913  if (p != QUEEN && p != ROOK && p != BISHOP && p != KNIGHT) {
914  return false;
915  }
916  } else {
917  if (sm->promote != EMPTY) { return false; }
918  }
919 
920  } else if (piece_IsSlider(mover)) {
921  // Make sure the direction is valid:
922  directionT dir = sqDir[from][to];
923  if (dir == NULL_DIR) { return false; }
924  if (mover == ROOK && direction_IsDiagonal(dir)) { return false; }
925  if (mover == BISHOP && !direction_IsDiagonal(dir)) { return false; }
926  int delta = direction_Delta (dir);
927  // Make sure all the in-between squares are empty:
928  squareT dest = from + delta;
929  while (dest != to) {
930  if (Board[dest] != EMPTY) { return false; }
931  dest += delta;
932  }
933 
934  } else if (mover == KNIGHT) {
935  if (! square_IsKnightHop (from, to)) { return false; }
936 
937  } else /* (mover == KING) */ {
938  colorT enemy = color_Flip(ToMove);
939  if (square_Adjacent (to, GetKingSquare(enemy))) { return false; }
940  if (! square_Adjacent (from, to)) {
941  // The move must be castling, or illegal.
942  if (IsKingInCheck()) { return false; }
943  MoveList mlist;
944  GenCastling (&mlist);
945  return std::find(mlist.begin(), mlist.end(), cmpMove(*sm)) != mlist.end();
946  }
947  }
948 
949  // The move looks good, but does it leave the king in check?
950  squareT kingSq = (mover == KING) ? to : GetKingSquare(ToMove);
951  colorT enemy = color_Flip(ToMove);
952  DoSimpleMove (sm);
953  uint nchecks = CalcAttacks (enemy, kingSq, NULL);
954  UndoSimpleMove (sm);
955  return (nchecks == 0);
956 }
957 
958 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
959 // Position::MatchPawnMove():
960 // Sets the LegalMoves list to contain the matching pawn move,
961 // if there is one.
962 //
963 errorT
964 Position::MatchPawnMove (MoveList * mlist, fyleT fromFyle, squareT to, pieceT promote)
965 {
966  ASSERT(mlist != NULL);
967  pieceT promote2 = promote;
968 
969  mlist->Clear();
970 
971  sint diff = (int)square_Fyle(to) - (int)fromFyle;
972  if (diff < -1 || diff > 1) { return ERROR_InvalidMove; }
973  pieceT pawn;
974  rankT toRank = square_Rank(to);
975  fyleT toFyle = square_Fyle(to);
976  rankT promoteRank = (ToMove == WHITE ? RANK_8 : RANK_1);
977 
978  // from is the from square; backup is the alternative from square
979  // for a pawn move two squares forward.
980 
981  squareT from, backup = NS;
982 
983  if (ToMove == WHITE) {
984  pawn = WP;
985  if (toRank < RANK_3) { return ERROR_InvalidMove; }
986  from = square_Make(fromFyle, toRank - 1);
987  if (toRank == RANK_4 && fromFyle == toFyle) { backup = to - 16; }
988  } else {
989  pawn = BP;
990  if (toRank > RANK_6) { return ERROR_InvalidMove; }
991  from = square_Make(fromFyle, toRank + 1);
992  if (toRank == RANK_5 && fromFyle == toFyle) { backup = to + 16; }
993  }
994 
995  // See if the promotion piece is valid:
996 
997  if (toRank == promoteRank) {
998  // if (promote == EMPTY) { return ERROR_InvalidMove; }
999  if (promote == EMPTY) {
1000  // autopromote to queen
1001  promote2 = (ToMove == WHITE ? WQ : BQ);
1002  }
1003  } else {
1004  if (promote != EMPTY) { return ERROR_InvalidMove; }
1005  }
1006 
1007  if (Board[from] != pawn) {
1008  // No match; but it could be a foward-two-squares move:
1009  if (backup == NS || Board[from] != EMPTY || Board[backup] != pawn) {
1010  // A forward-two-squares move is impossible.
1011  return ERROR_InvalidMove;
1012  }
1013  from = backup;
1014  }
1015 
1016  // OK, now 'from' is the only possible from-square. Is the move legal?
1017  // We make the move on the board and see if the King is in check.
1018 
1019  uint legal = 0;
1020  if (fromFyle == toFyle) {
1021  // Not a capture:
1022 
1023  if (Board[to] != EMPTY) { return ERROR_InvalidMove; }
1024  Board[to] = pawn; Board[from] = EMPTY;
1025  if (CalcNumChecks (GetKingSquare()) == 0) {
1026  legal = 1;
1027  }
1028  Board[to] = EMPTY; Board[from] = pawn;
1029 
1030  } else {
1031  // It is a capture -- is it legal?
1032 
1033  pieceT captured = Board[to];
1034  if (captured == EMPTY) {
1035  // Must be an en passant or illegal move.
1036  if (to != EPTarget) { return ERROR_InvalidMove; }
1037  squareT epSquare = square_Make(toFyle, square_Rank(from));
1038 
1039  pieceT enemyPawn = piece_Make (color_Flip(ToMove), PAWN);
1040  // If following assert fails, eptarget was corrupt
1041  ASSERT (Board[epSquare] == enemyPawn);
1042 
1043  Board[to] = pawn; Board[from] = EMPTY;
1044  Board[epSquare] = EMPTY;
1045  Material[enemyPawn] --;
1046  if (CalcNumChecks (GetKingSquare()) == 0) { legal = 1; }
1047  Board[epSquare] = enemyPawn;
1048  Board[to] = EMPTY;
1049  Board[from] = pawn;
1050  Material[enemyPawn]++;
1051 
1052  } else {
1053  if (piece_Color(captured) == ToMove) {
1054  // Capturing a friendly!
1055  return ERROR_InvalidMove;
1056  } else {
1057  // A regular capture. See if it leaves King in check:
1058  Board[to] = pawn; Board[from] = EMPTY;
1059  Material[captured]--;
1060  if (CalcNumChecks (GetKingSquare()) == 0) {
1061  legal = 1;
1062  }
1063  Material[captured]++;
1064  Board[to] = captured; Board[from] = pawn;
1065  }
1066  }
1067  }
1068 
1069  if (legal == 1) {
1070  AddLegalMove (mlist, from, to, promote2);
1071  return OK;
1072  }
1073  return ERROR_InvalidMove;
1074 }
1075 
1076 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1077 // Position::GenCheckEvasions():
1078 // Generate legal moves for the side to move when the
1079 // King is in check.
1080 //
1081 void
1082 Position::GenCheckEvasions (MoveList * mlist, pieceT mask, genMovesT genType,
1083  SquareList * checkSquares)
1084 {
1085  ASSERT(mlist != NULL);
1086  uint numChecks = checkSquares->Size();
1087 
1088  // Assert that king IS actually in check:
1089  ASSERT (numChecks > 0);
1090 
1091  bool genNonCaptures = (genType & GEN_NON_CAPS);
1092  bool capturesOnly = !genNonCaptures;
1093  mlist->Clear();
1094 
1095  squareT king = GetKingSquare (ToMove);
1096 
1097  // if it's double check, we can ONLY move the king
1098  if (numChecks == 1) {
1099  // OK, it is NOT a double check
1100  // Try to block piece/capture piece. Remember en passant!
1101  // First, generate a list of targets: squares between the king
1102  // and attacker to block, and the attacker's square.
1103 
1104  squareT attackSq = checkSquares->Get(0);
1105  directionT dir = sqDir[king][attackSq];
1106  SquareSet targets; // Set of blocking/capturing squares.
1107  targets.Add(attackSq);
1108 
1109  // Now add squares we can might be able to block on.
1110  if (dir != NULL_DIR) {
1111  squareT sq = square_Move (king, dir);
1112  while (sq != attackSq) {
1113  if (Board[sq] == EMPTY) { targets.Add(sq); }
1114  sq = square_Move (sq, dir);
1115  }
1116  }
1117 
1118  // Try each non-King piece in turn. If a piece is pinned to
1119  // the king, don't bother since it cannot possibly block or
1120  // capture the piece that is giving check!
1121 
1122  uint numPieces = Count[ToMove];
1123  for (uint p2 = 1; p2 < numPieces; p2++) {
1124  squareT from = List[ToMove][p2];
1125  pieceT p2piece = Board[from];
1126  if (Pinned[p2] != NULL_DIR) { continue; }
1127  if (mask == EMPTY || mask == piece_Type(p2piece)) {
1128  if (piece_Type(p2piece) == PAWN) {
1129  GenPawnMoves (mlist, from, NULL_DIR, &targets, genType);
1130  // Capturing a pawn en passant will only get out
1131  // of check if the pawn that moved two squares
1132  // is doing the checking. If it is not, that means
1133  // a discovered check with the last pawn move so
1134  // taking en passant cannot get out of check.
1135  if (EPTarget != NULL_SQUARE) {
1136  squareT pawnSq = (ToMove == WHITE ? EPTarget - 8 : EPTarget + 8);
1137  if (pawnSq == attackSq) {
1138  SquareSet epset;
1139  epset.Add(EPTarget);
1140  GenPawnMoves (mlist, from, NULL_DIR, &epset, genType);
1141  }
1142  }
1143  } else {
1144  GenPieceMoves (mlist, from, &targets, capturesOnly);
1145  }
1146  }
1147  } // end of search for captures/blocks
1148  }
1149 
1150  // Now king moves -- just compute them normally:
1151  if (mask == EMPTY || mask == KING) { GenKingMoves(mlist, genType, false); }
1152 
1153  return;
1154 }
1155 
1156 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1157 // Position::TreeCalcAttacks():
1158 // Calculate attack score for a side on a square,
1159 // using a recursive tree search.
1160 int
1162 {
1163  int maxScore = -2;
1164  uint moveCount = 0, zeroCount = 0;
1165  MoveList moveList;
1166  GenerateCaptures(&moveList);
1167  for (uint i=0; i < moveList.Size(); i++) {
1168  simpleMoveT *smPtr = moveList.Get(i);
1169  if (smPtr->to == target) {
1170  if (piece_IsKing(Board[target])) return -1;
1171  moveCount++;
1172  DoSimpleMove(smPtr);
1173  int score = TreeCalcAttacks(color_Flip(side), target);
1174  UndoSimpleMove(smPtr);
1175  if (!score && ++zeroCount > 1) return -2;
1176  if (score > maxScore) maxScore = score;
1177  }
1178  }
1179 
1180  if (!moveCount) return 0;
1181  if (!maxScore) return -1;
1182  return -maxScore;
1183 }
1184 
1185 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1186 // Position::CalcAttacks():
1187 // Calculate the number of attacks by a side on a square.
1188 // This function also puts a list of the attacking piece squares
1189 // in the fromSqs parameter if it is non-NULL.
1190 //
1191 // It ONLY uses the Board[] and Material[] lists of the Position, and
1192 // ASSUMES they are correct with respect to each other, but it does
1193 // NOT use the List[] or ListPos[] information.
1194 // This allows us to move pieces quickly (altering only Board[] and
1195 // Material[]) and detect whether they leave the king in check,
1196 // without having to update other information.
1197 uint
1198 Position::CalcAttacks (colorT side, squareT target, SquareList * fromSquares)
1199 {
1200  // If squares is NULL, caller doesn't want a list of the squares of
1201  // attacking pieces. To avoid comparing fromSquares with NULL every time
1202  // we find a check, we set up a local array to use instead if fromSquares
1203  // is NULL.
1204  SquareList fromSqs;
1205  if (fromSquares == NULL) { fromSquares = &fromSqs; }
1206 
1207  fromSquares->Clear();
1208  squareT sq;
1209 
1210  // Bishop/Queen/Rook attacks: look at each of the 8 directions
1211  pieceT king, queen, rook, bishop, knight;
1212  if (side == WHITE) {
1213  king = WK; queen = WQ; rook = WR; bishop = WB; knight = WN;
1214  } else {
1215  king = BK; queen = BQ; rook = BR; bishop = BB; knight = BN;
1216  }
1217 
1218  uint numQueensRooks = Material[queen] + Material[rook];
1219  uint numQueensBishops = Material[queen] + Material[bishop];
1220 
1221  // We only bother if there are any sliding pieces of each type:
1222  if (numQueensRooks > 0) {
1223  fyleT fyle = square_Fyle (target);
1224  rankT rank = square_Rank (target);
1225  directionT dirs[4];
1226  uint ndirs = 0;
1227  if (FyleCount(queen,fyle) + FyleCount(rook,fyle) > 0) {
1228  dirs[ndirs++] = UP; dirs[ndirs++] = DOWN;
1229  }
1230  if (RankCount(queen,rank) + RankCount(rook,rank) > 0) {
1231  dirs[ndirs++] = LEFT; dirs[ndirs++] = RIGHT;
1232  }
1233  for (uint i = 0; i < ndirs; i++) {
1234  directionT dir = dirs[i];
1235  int delta = direction_Delta (dir);
1236  squareT dest = target;
1237  squareT last = square_Last (target, dir);
1238 
1239  while (dest != last) {
1240  dest += delta;
1241  pieceT p = Board[dest];
1242  if (p == EMPTY) {
1243  // empty square: keep searching
1244  } else if (p == queen || p == rook) {
1245  // Found an attacking piece
1246  fromSquares->Add(dest);
1247  break;
1248  } else {
1249  // Found a piece, but not a queen or rook
1250  break;
1251  }
1252  }
1253  }
1254  }
1255 
1256  // Now diagonal sliders: Queens/Bishops:
1257  if (numQueensBishops > 0) {
1258  leftDiagT left = square_LeftDiag (target);
1259  rightDiagT right = square_RightDiag (target);
1260  directionT dirs[4];
1261  uint ndirs = 0;
1262  if (LeftDiagCount(queen,left) + LeftDiagCount(bishop,left) > 0) {
1263  dirs[ndirs++] = UP_LEFT; dirs[ndirs++] = DOWN_RIGHT;
1264  }
1265  if (RightDiagCount(queen,right) + RightDiagCount(bishop,right) > 0) {
1266  dirs[ndirs++] = UP_RIGHT; dirs[ndirs++] = DOWN_LEFT;
1267  }
1268  for (uint i = 0; i < ndirs; i++) {
1269  directionT dir = dirs[i];
1270  int delta = direction_Delta (dir);
1271  squareT dest = target;
1272  squareT last = square_Last (target, dir);
1273 
1274  while (dest != last) {
1275  dest += delta;
1276  pieceT p = Board[dest];
1277  if (p == EMPTY) {
1278  // empty square: keep searching
1279  } else if (p == queen || p == bishop) {
1280  // Found an attacking piece
1281  fromSquares->Add(dest);
1282  break;
1283  } else {
1284  // Found a piece, but not an enemy queen or bishop
1285  break;
1286  }
1287  }
1288  }
1289  }
1290 
1291  // Now knight checks: we only bother if there is a knight on the
1292  // opposite square color of the target square color.
1293  if (Material[knight] > 0
1294  && SquareColorCount(knight, color_Flip(square_Color(target))) > 0) {
1295  const squareT * destPtr = knightAttacks[target];
1296  while (true) {
1297  squareT dest = *destPtr;
1298  if (dest == NULL_SQUARE) { break; }
1299  if (Board[dest] == knight) {
1300  fromSquares->Add(dest);
1301  }
1302  destPtr++;
1303  }
1304  }
1305 
1306  // Now pawn attacks:
1307  if (side == WHITE) {
1308  if (square_Rank(target) != RANK_1) { //if (Material[WP] > 0) {
1309  sq = square_Move (target, DOWN_LEFT);
1310  if (Board[sq] == WP) {
1311  fromSquares->Add(sq);
1312  }
1313  sq = square_Move (target, DOWN_RIGHT);
1314  if (Board[sq] == WP) {
1315  fromSquares->Add(sq);
1316  }
1317  }
1318  } else {
1319  if (square_Rank(target) != RANK_8) { //if (Material[BP] > 0) {
1320  sq = square_Move (target, UP_LEFT);
1321  if (Board[sq] == BP) {
1322  fromSquares->Add(sq);
1323  }
1324  sq = square_Move (target, UP_RIGHT);
1325  if (Board[sq] == BP) {
1326  fromSquares->Add(sq);
1327  }
1328  }
1329  }
1330 
1331  // King attacks:
1332  const squareT *destPtr = kingAttacks[target];
1333  do if (Board[*destPtr] == king) fromSquares->Add(*destPtr);
1334  while (*++destPtr != NULL_SQUARE);
1335 
1336  return fromSquares->Size();
1337 }
1338 
1339 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1340 // Position::IsKingInCheckDir
1341 // Returns true if the King of the side to move is attacked
1342 // by an enemy sliding piece (Queen/Rook/Bishop) from the
1343 // specified direction.
1344 bool
1346 {
1347  ASSERT (dir != NULL_DIR);
1348  squareT kingSq = GetKingSquare(ToMove);
1349  colorT enemy = color_Flip(ToMove);
1350  bool isDiagonal = direction_IsDiagonal(dir);
1351  pieceT queen = piece_Make (enemy, QUEEN);
1352  pieceT slider = piece_Make (enemy, (isDiagonal ? BISHOP : ROOK));
1353 
1354  // First, make sure the enemy has sliding pieces that could give check:
1355  uint nSliders = PieceCount(queen) + PieceCount(slider);
1356  if (nSliders == 0) { return false; }
1357 
1358  // Now make sure the enemy has a sliding piece on the appropriate
1359  // rank, file or diagonal:
1360  fyleT fyle = square_Fyle (kingSq);
1361  rankT rank = square_Rank (kingSq);
1362  leftDiagT ldiag = square_LeftDiag (kingSq);
1363  rightDiagT rdiag = square_RightDiag (kingSq);
1364 
1365  switch (dir) {
1366  case UP:
1367  case DOWN:
1368  nSliders = FyleCount(queen,fyle) + FyleCount(slider,fyle);
1369  break;
1370  case LEFT:
1371  case RIGHT:
1372  nSliders = RankCount(queen,rank) + RankCount(slider,rank);
1373  break;
1374  case UP_LEFT:
1375  case DOWN_RIGHT:
1376  nSliders = LeftDiagCount(queen,ldiag) + LeftDiagCount(slider,ldiag);
1377  break;
1378  case UP_RIGHT:
1379  case DOWN_LEFT:
1380  nSliders = RightDiagCount(queen,rdiag) + RightDiagCount(slider,rdiag);
1381  break;
1382  }
1383  if (nSliders == 0) { return false; }
1384 
1385  // Now move along the specified direction looking for a checking piece:
1386  squareT dest = kingSq;
1387  squareT last = square_Last (kingSq, dir);
1388  int delta = direction_Delta (dir);
1389 
1390  while (dest != last) {
1391  dest += delta;
1392  pieceT p = Board[dest];
1393  if (p == EMPTY) {
1394  // empty square: keep searching
1395  } else if (p == queen || p == slider) {
1396  // Found an checking slider piece
1397  return true;
1398  } else {
1399  // Found a piece, but not an enemy queen or rook/bishop
1400  break;
1401  }
1402  }
1403 
1404  return false;
1405 }
1406 
1407 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1408 // Position::IsKingInCheck
1409 // Returns true if the king of the side to move is in check.
1410 // If the specified move is not NULL, it must be the legal move
1411 // that the opponent played to reach this position. This will
1412 // be used as a speed optimization, by skipping cases where the
1413 // move could not have left the king in check.
1414 //
1415 bool
1417 {
1418  if (sm == NULL) { return IsKingInCheck(); }
1419 
1420  squareT kingSq = GetKingSquare(ToMove);
1421  pieceT p = piece_Type (sm->movingPiece);
1422  if (sm->promote != EMPTY) { p = piece_Type(sm->promote); }
1423 
1424  // No optimization of the last move was castling:
1425  if (p == KING && square_Fyle(sm->from) == E_FYLE) {
1426  fyleT toFyle = square_Fyle(sm->to);
1427  if (toFyle == C_FYLE || toFyle == G_FYLE) {
1428  return IsKingInCheck();
1429  }
1430  }
1431  // No optimization for en passant capture:
1432  if (p == PAWN && piece_Type(sm->capturedPiece) == PAWN) {
1433  rankT fromRank = square_Rank(sm->from);
1434  rankT capturedRank = square_Rank(sm->capturedSquare);
1435  if (fromRank == capturedRank) { return IsKingInCheck(); }
1436  }
1437 
1438  if (p == PAWN) {
1439  if (ToMove == WHITE) {
1440  if (Material[BP] > 0) {
1441  squareT sq = square_Move (kingSq, UP_LEFT);
1442  if (Board[sq] == BP) { return true; }
1443  sq = square_Move (kingSq, UP_RIGHT);
1444  if (Board[sq] == BP) { return true; }
1445  }
1446  } else {
1447  if (Material[WP] > 0) {
1448  squareT sq = square_Move (kingSq, DOWN_LEFT);
1449  if (Board[sq] == WP) { return true; }
1450  sq = square_Move (kingSq, DOWN_RIGHT);
1451  if (Board[sq] == WP) { return true; }
1452  }
1453  }
1454  } else if (p == KNIGHT) {
1455  if (square_IsKnightHop (kingSq, sm->to)) { return true; }
1456  } else if (p == KING) {
1457  // A king cannot directly check its adversary.
1458  } else {
1459  // A sliding piece:
1460  directionT toDir = sqDir[kingSq][sm->to];
1461  if (toDir != NULL_DIR && IsKingInCheckDir(toDir)) { return true; }
1462  }
1463 
1464  // Now look for a discovered check from a sliding piece:
1465  directionT dir = sqDir[kingSq][sm->from];
1466  if (dir != NULL_DIR && IsKingInCheckDir(dir)) { return true; }
1467 
1468  ASSERT (IsKingInCheck() == false);
1469  return false;
1470 }
1471 
1472 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1473 // Position::Mobility
1474 // Returns the number of squares a rook or bishop of the specified
1475 // color would attack from the specified square.
1476 uint
1478 {
1479  ASSERT (p == ROOK || p == BISHOP);
1480  uint mobility = 0;
1481  directionT rookDirs[4] = { UP, DOWN, LEFT, RIGHT };
1482  directionT bishopDirs[4]
1484  directionT * dirPtr = (p == ROOK ? rookDirs : bishopDirs);
1485 
1486  for (uint i=0; i < 4; i++) {
1487  directionT dir = dirPtr[i];
1488  int delta = direction_Delta (dir);
1489  squareT dest = from;
1490  squareT last = square_Last (from, dir);
1491 
1492  while (dest != last) {
1493  dest += delta;
1494  pieceT p = Board[dest];
1495  if (p == EMPTY) { // Empty square
1496  mobility++;
1497  } else if (piece_Color(p) == color) { // Friendly piece
1498  break; // Finished with this direction.
1499  } else { // Enemy piece
1500  mobility++;
1501  break; // Finished with this direction.
1502  }
1503  }
1504  }
1505  return mobility;
1506 }
1507 
1508 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1509 // Position::IsKingInMate():
1510 // Quick check if king is in mate.
1511 //
1512 bool
1514 {
1515  SquareList checkSquares;
1516  uint numChecks = CalcNumChecks (GetKingSquare(ToMove), &checkSquares);
1517  if (numChecks == 0) { return false; }
1518  CalcPins ();
1519  MoveList mlist;
1520  GenCheckEvasions (&mlist, EMPTY, GEN_ALL_MOVES, &checkSquares);
1521  if (mlist.Size() == 0) { return true; }
1522  return false;
1523 }
1524 
1525 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1526 // Position::IsLegal()
1527 // Verifies the position as being legal.
1528 // Returns false for any of the following:
1529 // - if the two kings are adjacent;
1530 // - if there are any pawns on the 1st/8th rank;
1531 // - if the side to move is already checking the enemy king.
1532 bool
1534 {
1535  squareT stmKing = GetKingSquare();
1536  squareT enemyKing = GetEnemyKingSquare();
1537  if (square_Adjacent (stmKing, enemyKing)) { return false; }
1538  if (RankCount (WP, RANK_1) != 0) { return false; }
1539  if (RankCount (WP, RANK_8) != 0) { return false; }
1540  if (RankCount (BP, RANK_1) != 0) { return false; }
1541  if (RankCount (BP, RANK_8) != 0) { return false; }
1542  if (CalcAttacks (ToMove, enemyKing, NULL) > 0) {
1543  return false;
1544  }
1545  return true;
1546 }
1547 
1548 
1549 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1550 // Position::IsPromoMove():
1551 // Returns true if the move is a promotion move.
1552 // NOTE that the move may not actually be legal!
1553 // The arguments 'from' and 'to' can be in either order.
1554 bool
1556 {
1557  rankT seventh, eighth;
1558  pieceT pawn;
1559  if (ToMove == WHITE) { seventh = RANK_7; eighth = RANK_8; pawn = WP; }
1560  else { seventh = RANK_2; eighth = RANK_1; pawn = BP; }
1561  rankT fromR, toR;
1562  fromR = square_Rank(from);
1563  toR = square_Rank(to);
1564  if ( (fromR == seventh && toR == eighth && Board[from] == pawn) ||
1565  (toR == seventh && fromR == eighth && Board[to] == pawn) ) {
1566  return 1;
1567  }
1568  return 0;
1569 }
1570 
1571 
1572 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1573 // Position::DoSimpleMove():
1574 // Make the move on the board and update all the necessary
1575 // fields in the simpleMove structure so it can be undone.
1576 //
1577 void
1579 {
1580  ASSERT (sm != NULL);
1581  squareT from = sm->from;
1582  squareT to = sm->to;
1583  pieceT p = Board[from];
1584  pieceT ptype = piece_Type(p);
1585  colorT enemy = color_Flip(ToMove);
1586  ASSERT (p != EMPTY);
1587 
1588  // update move fields that (maybe) have not yet been set:
1589 
1590  sm->pieceNum = ListPos[from];
1591  sm->capturedPiece = Board[to];
1592  sm->capturedSquare = to;
1593  sm->castleFlags = Castling;
1594  sm->epSquare = EPTarget;
1595  sm->oldHalfMoveClock = HalfMoveClock;
1596 
1597  HalfMoveClock++;
1598  PlyCounter++;
1599 
1600  // Check for a null (empty) move:
1601  if (sm->isNullMove()) {
1602  ToMove = enemy;
1603  EPTarget = NULL_SQUARE;
1604  return;
1605  }
1606 
1607  // Handle en passant capture:
1608 
1609  if (ptype == PAWN && sm->capturedPiece == EMPTY
1610  && square_Fyle(from) != square_Fyle(to)) {
1611 
1612  // This was an EP capture. We do not need to check it was a capture
1613  // since if a pawn lands on EPTarget it must capture to get there.
1614 
1615  pieceT enemyPawn = piece_Make(enemy, PAWN);
1616  sm->capturedSquare = (ToMove == WHITE ? (to - 8) : (to + 8));
1617  ASSERT (Board[sm->capturedSquare] == enemyPawn);
1618  sm->capturedPiece = enemyPawn;
1619  }
1620 
1621  // handle captures:
1622 
1623  if (sm->capturedPiece != EMPTY) {
1624  ASSERT (piece_Type(sm->capturedPiece) != KING);
1625  sm->capturedNum = ListPos[sm->capturedSquare];
1626  // update opponents List of pieces
1627  Count[enemy]--;
1628  ListPos[List[enemy][Count[enemy]]] = sm->capturedNum;
1629  List[enemy][sm->capturedNum] = List[enemy][Count[enemy]];
1630  Material[sm->capturedPiece]--;
1631  HalfMoveClock = 0;
1632  RemoveFromBoard (sm->capturedPiece, sm->capturedSquare);
1633  }
1634 
1635  // handle promotion:
1636 
1637  if (sm->promote != EMPTY) {
1638  ASSERT (p == piece_Make(ToMove, PAWN));
1639  Material[p]--;
1640  RemoveFromBoard (p, from);
1641  p = piece_Make(ToMove, sm->promote);
1642  Material[p]++;
1643  AddToBoard (p, from);
1644  }
1645 
1646  // now make the move:
1647  List[ToMove][sm->pieceNum] = to;
1648  ListPos[to] = sm->pieceNum;
1649  RemoveFromBoard (p, from);
1650  AddToBoard (p, to);
1651 
1652  // handle Castling:
1653 
1654  if (ptype == KING && square_Fyle(from) == E_FYLE &&
1655  (square_Fyle(to) == C_FYLE || square_Fyle(to) == G_FYLE)) {
1656  squareT rookfrom, rookto;
1657  pieceT rook = piece_Make (ToMove, ROOK);
1658  if (square_Fyle(to) == C_FYLE) {
1659  rookfrom = to - 2;
1660  rookto = to + 1;
1661  } else {
1662  rookfrom = to + 1;
1663  rookto = to - 1;
1664  }
1665  ListPos[rookto] = ListPos[rookfrom];
1666  List[ToMove][ListPos[rookto]] = rookto;
1667  RemoveFromBoard (rook, rookfrom);
1668  AddToBoard (rook, rookto);
1669  }
1670 
1671  // Handle clearing of castling flags:
1672 
1673  if (Castling) {
1674  if (ptype == KING) { // The king moved.
1675  SetCastling (ToMove, QSIDE, false);
1676  SetCastling (ToMove, KSIDE, false);
1677  }
1678  // See if a rook moved or was captured:
1679  if (ToMove == WHITE) {
1680  if (from == A1) { SetCastling (WHITE, QSIDE, false); }
1681  if (from == H1) { SetCastling (WHITE, KSIDE, false); }
1682  if (to == A8) { SetCastling (BLACK, QSIDE, false); }
1683  if (to == H8) { SetCastling (BLACK, KSIDE, false); }
1684  } else {
1685  if (from == A8) { SetCastling (BLACK, QSIDE, false); }
1686  if (from == H8) { SetCastling (BLACK, KSIDE, false); }
1687  if (to == A1) { SetCastling (WHITE, QSIDE, false); }
1688  if (to == H1) { SetCastling (WHITE, KSIDE, false); }
1689  }
1690  }
1691 
1692  // Set the EPTarget square, if a pawn advanced two squares and an
1693  // enemy pawn is on a square where en passant may be possible.
1694  EPTarget = NULL_SQUARE;
1695  if (ptype == PAWN) {
1696  rankT fromRank = square_Rank(from);
1697  rankT toRank = square_Rank(to);
1698  if (fromRank == RANK_2 && toRank == RANK_4
1699  && (Board[square_Move(to,LEFT)] == BP
1700  || Board[square_Move(to,RIGHT)] == BP)) {
1701  EPTarget = square_Move(from, UP);
1702  }
1703  if (fromRank == RANK_7 && toRank == RANK_5
1704  && (Board[square_Move(to,LEFT)] == WP
1705  || Board[square_Move(to,RIGHT)] == WP)) {
1706  EPTarget = square_Move(from, DOWN);
1707  }
1708  HalfMoveClock = 0; // 50-move clock resets on pawn moves.
1709  }
1710 
1711  ToMove = enemy;
1712  return;
1713 }
1714 
1715 
1716 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1717 // Position::UndoSimpleMove():
1718 // Take back a simple move that has been made with DoSimpleMove().
1719 //
1720 void
1722 {
1723  ASSERT (m != NULL);
1724  squareT from = m->from;
1725  squareT to = m->to;
1726  pieceT p = Board[to];
1727  EPTarget = m->epSquare;
1728  Castling = m->castleFlags;
1729  HalfMoveClock = m->oldHalfMoveClock;
1730  PlyCounter--;
1731  ToMove = color_Flip(ToMove);
1732  m->pieceNum = ListPos[to];
1733 
1734  // Check for a null move:
1735  if (m->isNullMove()) {
1736  return;
1737  }
1738 
1739  // Handle a capture: insert piece back into piecelist.
1740  // This works for EP captures too, since the square of the captured
1741  // piece is in the "capturedSquare" field rather than assuming the
1742  // value of the "to" field. The only time these two fields are
1743  // different is for an en passant move.
1744 
1745  if (m->capturedPiece != EMPTY) {
1746  colorT c = color_Flip(ToMove);
1747  ListPos[List[c][m->capturedNum]] = Count[c];
1748  ListPos[m->capturedSquare] = m->capturedNum;
1749  List[c][Count[c]] = List[c][m->capturedNum];
1750  List[c][m->capturedNum] = m->capturedSquare;
1751  Material[m->capturedPiece]++;
1752  Count[c]++;
1753  }
1754 
1755  // handle promotion:
1756 
1757  if (m->promote != EMPTY) {
1758  Material[p]--;
1759  RemoveFromBoard (p, to);
1760  p = piece_Make(ToMove, PAWN);
1761  Material[p]++;
1762  AddToBoard (p, to);
1763  }
1764 
1765  // now make the move:
1766 
1767  List[ToMove][m->pieceNum] = from;
1768  ListPos[from] = m->pieceNum;
1769  RemoveFromBoard (p, to);
1770  AddToBoard (p, from);
1771  if (m->capturedPiece != EMPTY) {
1772  AddToBoard (m->capturedPiece, m->capturedSquare);
1773  }
1774 
1775  // handle Castling:
1776 
1777  if ((piece_Type(p) == KING) && square_Fyle(from) == E_FYLE
1778  && (square_Fyle(to) == C_FYLE || square_Fyle(to) == G_FYLE)) {
1779  squareT rookfrom, rookto;
1780  pieceT rook = (ToMove == WHITE? WR : BR);
1781  if (square_Fyle(to) == C_FYLE) {
1782  rookfrom = to - 2; rookto = to + 1;
1783  } else {
1784  rookfrom = to + 1; rookto = to - 1;
1785  }
1786  ListPos[rookfrom] = ListPos[rookto];
1787  List[ToMove][ListPos[rookto]] = rookfrom;
1788  RemoveFromBoard (rook, rookto);
1789  AddToBoard (rook, rookfrom);
1790  }
1791  return;
1792 }
1793 
1794 
1795 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1796 // Position::RelocatePiece():
1797 // Given a from-square and to-square, modifies the position so
1798 // the piece on the from-square is relocated to the to-square.
1799 // Returns an error if the from square is empty, or the target
1800 // square is not empty, or the relocation would otherwise
1801 // produce an illegal position (e.g. pawn on the 1st or 8th rank
1802 // or a King in check).
1803 //
1804 errorT
1806 {
1807  // Must have on-board squares:
1808  if (fromSq == NS || toSq == NS) { return ERROR; }
1809 
1810  // If squares are identical, just return success:
1811  if (fromSq == toSq) { return OK; }
1812 
1813  pieceT piece = Board[fromSq];
1814  pieceT ptype = piece_Type(piece);
1815  colorT pcolor = piece_Color(piece);
1816 
1817  // Must be relocating a nonempty piece to an empty square:
1818  if (piece == EMPTY || Board[toSq] != EMPTY) { return ERROR; }
1819 
1820  // Pawns cannot relocate to the first or last rank:
1821  if (ptype == PAWN) {
1822  rankT toRank = square_Rank(toSq);
1823  if (toRank == RANK_1 || toRank == RANK_8) { return ERROR; }
1824  }
1825 
1826  // Locate the piece index in the appropriate list of pieces:
1827  uint index = ListPos[fromSq];
1828  ASSERT(List[pcolor][index] == fromSq);
1829 
1830  // Relocate the piece:
1831  List[pcolor][index] = toSq;
1832  ListPos[toSq] = index;
1833  RemoveFromBoard (piece, fromSq);
1834  AddToBoard (piece, toSq);
1835 
1836  // Check for adjacent kings or side to move giving check:
1837  if (! IsLegal()) {
1838  // Undo the relocation and return error:
1839  List[pcolor][index] = fromSq;
1840  RemoveFromBoard (piece, toSq);
1841  AddToBoard (piece, fromSq);
1842  return ERROR;
1843  }
1844 
1845  // Relocation successful:
1846  return OK;
1847 }
1848 
1849 
1850 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1851 // Position::MaterialValue():
1852 // Returns the sum value of material for a particular side,
1853 // where piece values are:
1854 // King: 0 (since both sides always have one)
1855 // Queen: 9
1856 // Rook: 5
1857 // Bishop, Knight: 3 each
1858 // Pawn: 1
1859 uint
1861 {
1862  ASSERT (c == WHITE || c == BLACK);
1863  uint value = 0;
1864  if (c == WHITE) {
1865  value += 9 * PieceCount(WQ);
1866  value += 5 * PieceCount(WR);
1867  value += 3 * PieceCount(WB);
1868  value += 3 * PieceCount(WN);
1869  value += 1 * PieceCount(WP);
1870  } else {
1871  value += 9 * PieceCount(BQ);
1872  value += 5 * PieceCount(BR);
1873  value += 3 * PieceCount(BB);
1874  value += 3 * PieceCount(BN);
1875  value += 1 * PieceCount(BP);
1876  }
1877  return value;
1878 }
1879 
1880 
1881 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1882 // Position::MakeSANString():
1883 // Make the SAN string for a simpleMove.
1884 // The parameter 'sanFlag' indicates whether '+' and '#' symbols
1885 // should be added to checking or mating moves.
1886 //
1887 void
1889 {
1890  ASSERT (m != NULL && s != NULL);
1891 
1892  // Make sure m->pieceNum is updated:
1893  m->pieceNum = ListPos[m->from];
1894  squareT from = List[ToMove][m->pieceNum];
1895  squareT to = m->to;
1896  char * c = s;
1897  pieceT piece = Board[from];
1898  pieceT p = piece_Type(piece);
1899 
1900  if (p == PAWN) {
1901  if (square_Fyle(from) != square_Fyle(to)) { // pawn capture
1902  *c++ = square_FyleChar(from);
1903  *c++ = 'x';
1904  }
1905  *c++ = square_FyleChar(to);
1906  *c++ = square_RankChar(to);
1907  if ((square_Rank(to)==RANK_1) || (square_Rank(to)==RANK_8)) {
1908  *c++ = '=';
1909  *c++ = piece_Char(m->promote);
1910  p = piece_Type(m->promote);
1911  }
1912 
1913  } else if (p == KING) {
1914  if (m->isNullMove()) {
1915  //*c++ = 'n'; *c++ = 'u'; *c++ = 'l'; *c++ = 'l';
1916  *c++ = '-'; *c++ = '-';
1917  } else {
1918  switch (m->isCastle()) {
1919  case 0:
1920  *c++ = 'K';
1921  if (Board[to] != EMPTY)
1922  *c++ = 'x';
1923  *c++ = square_FyleChar(to);
1924  *c++ = square_RankChar(to);
1925  break;
1926  case 1:
1927  *c++ = 'O';
1928  *c++ = '-';
1929  *c++ = 'O';
1930  break;
1931  case 2:
1932  *c++ = 'O';
1933  *c++ = '-';
1934  *c++ = 'O';
1935  *c++ = '-';
1936  *c++ = 'O';
1937  break;
1938  }
1939  }
1940 
1941  } else { // Queen/Rook/Bishop/Knight
1942  *c++ = piece_Char(p);
1943 
1944  // We only need to calculate legal moves to disambiguate if there
1945  // are more than one of this type of piece.
1946  if (Material[piece] > 1) {
1947  int ambiguity = 0;
1948  for (uint i = 1, n = Count[ToMove]; i < n; i++) {
1949  squareT sq = List[ToMove][i];
1950  if (sq == from || Board[sq] != piece)
1951  continue;
1952 
1953  if (!movegen::pseudo(sq, to, ToMove, p, Board, EMPTY))
1954  continue; // Skip illegal move
1955 
1956  std::pair<pieceT, squareT> pin =
1957  movegen::opens_ray(sq, to, GetKingSquare(), Board, EMPTY);
1958  if (pin.first != INVALID_PIECE &&
1959  piece_Color_NotEmpty(Board[pin.second]) != ToMove) {
1960  pieceT pt = piece_Type(Board[pin.second]);
1961  if (pt == QUEEN || pt == pin.first)
1962  continue; // Skip pinned piece
1963  }
1964 
1965  // Ambiguity:
1966  // 1 (0001) --> need from-file (preferred) or from-rank
1967  // 3 (0011) --> need from-file
1968  // 5 (0101) --> need from-rank
1969  // 7 (0111) --> need both from-file and from-rank
1970  ambiguity |= 1;
1971  if (square_Rank(from) == square_Rank(sq)) {
1972  ambiguity |= 2; // 0b0010
1973  } else if (square_Fyle(from) == square_Fyle(sq)) {
1974  ambiguity |= 4; // 0b0100
1975  }
1976  }
1977  if (ambiguity) {
1978  if (ambiguity != 5)
1979  *c++ = square_FyleChar(from); // print from-fyle
1980  if (ambiguity >= 5)
1981  *c++ = square_RankChar(from); // print from-rank
1982  }
1983  }
1984  if (Board[to] != EMPTY)
1985  *c++ = 'x';
1986  *c++ = square_FyleChar(to);
1987  *c++ = square_RankChar(to);
1988  }
1989 
1990  bool check;
1991  if (flag != SAN_NO_CHECKTEST) {
1992  squareT oldTo = Board[to];
1993  Board[to] = Board[from];
1994  Board[from] = EMPTY;
1995  squareT enemyKingSq = GetEnemyKingSquare();
1996  check = (p != KING) &&
1997  movegen::attack(to, enemyKingSq, ToMove, p, Board, EMPTY);
1998  if (!check) {
1999  bool enpassant = (p == PAWN && oldTo == EMPTY &&
2000  square_Fyle(from) != square_Fyle(to));
2001  if (!enpassant && (p != KING || !m->isCastle()) &&
2002  !movegen::attack_slider(from, enemyKingSq, QUEEN, Board,
2003  EMPTY)) {
2004  flag = SAN_NO_CHECKTEST;
2005  }
2006 
2007  } else if (flag != SAN_MATETEST) {
2008  *c++ = '+';
2009  flag = SAN_NO_CHECKTEST;
2010  }
2011  Board[from] = Board[to];
2012  Board[to] = oldTo;
2013  }
2014 
2015  // Now do the check or mate symbol:
2016  if (flag != SAN_NO_CHECKTEST) {
2017  // Now we make the move to test for check:
2018  DoSimpleMove (m);
2019  if (check || CalcNumChecks(GetKingSquare()) > 0) {
2020  char ch = '+';
2021  if (flag == SAN_MATETEST) {
2022  MoveList mlist;
2023  GenerateMoves (&mlist);
2024  if (mlist.Size() == 0) { ch = '#'; }
2025  }
2026  *c++ = ch;
2027  }
2028  UndoSimpleMove (m);
2029  }
2030  *c = 0;
2031 }
2032 
2033 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2034 // Position::MakeUCIString():
2035 // Make the UCI string for a simpleMove.
2036 //
2037 void
2039 {
2040  ASSERT (m != NULL && s != NULL);
2041 
2042  // Make sure m->pieceNum is updated:
2043  m->pieceNum = ListPos[m->from];
2044  pieceT p = piece_Type (Board[List[ToMove][m->pieceNum]]);
2045  squareT from = List[ToMove][m->pieceNum];
2046  squareT to = m->to;
2047 
2048  char * c = s;
2049 
2050  if (from == to && to != NULL_SQUARE) {
2051  // UCI standard for null move
2052  c[0] = '0';
2053  c[1] = '0';
2054  c[2] = '0';
2055  c[3] = '0';
2056  c[4] = 0;
2057  return;
2058  }
2059 
2060  *c++ = square_FyleChar(from);
2061  *c++ = square_RankChar(from);
2062  *c++ = square_FyleChar(to);
2063  *c++ = square_RankChar(to);
2064  if (p == PAWN) {
2065  if ((square_Rank(to)==RANK_1) || (square_Rank(to)==RANK_8)) {
2066  *c++ = piece_Char(m->promote);
2067  }
2068  }
2069 
2070  *c = 0;
2071 }
2072 
2073 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2074 // Position::ReadCoordMove():
2075 // Given a move in coordinate notation,
2076 // e.g. "e2e4" or "g1f3", generates the legal move it represents.
2077 // Returns: OK or ERROR_InvalidMove.
2078 // If "reverse" is true, coordinates in reverse order are acceptable,
2079 // e.g. "f3g1" for 1.Nf3.
2080 //
2081 errorT Position::ReadCoordMove(simpleMoveT* m, const char* str, int slen,
2082  bool reverse) {
2083  ASSERT (m != NULL && str != NULL);
2084  fyleT fromFyle, toFyle;
2085  rankT fromRank, toRank;
2086  squareT from, to;
2087  pieceT promo = EMPTY;
2088 
2089  if (slen == 5) {
2090  promo = piece_FromChar(toupper(str[4]));
2091  } else if (slen != 4) { return ERROR_InvalidMove; }
2092 
2093  fromFyle = fyle_FromChar (str[0]);
2094  fromRank = rank_FromChar (str[1]);
2095  from = square_Make (fromFyle, fromRank);
2096  if (from == NS) { return ERROR_InvalidMove; }
2097 
2098  toFyle = fyle_FromChar (str[2]);
2099  toRank = rank_FromChar (str[3]);
2100  to = square_Make (toFyle, toRank);
2101  if (to == NS) { return ERROR_InvalidMove; }
2102 
2103  MoveList mlist;
2104  GenerateMoves(&mlist);
2105  for (size_t i = 0, n = mlist.Size(); i < n; i++) {
2106  simpleMoveT* sm = mlist.Get(i);
2107  if (sm->promote == promo) {
2108  if (sm->from == from && sm->to == to) {
2109  *m = *sm;
2110  return OK;
2111  }
2112  if (reverse && sm->to == from && sm->from == to) {
2113  *m = *sm;
2114  return OK;
2115  }
2116  }
2117  }
2118  return ERROR_InvalidMove;
2119 }
2120 
2121 static int trimCheck(const char* str, int slen) {
2122  while (slen > 0) { // trim mate '#' or check '+'
2123  --slen;
2124  if (str[slen] != '#' && str[slen] != '+') {
2125  ++slen;
2126  break;
2127  }
2128  }
2129  return slen;
2130 }
2131 
2132 errorT Position::ReadMovePawn(simpleMoveT* sm, const char* str, int slen,
2133  fyleT frFyle) {
2134  ASSERT(sm != NULL && str != NULL && frFyle <= H_FYLE);
2135 
2136  slen = trimCheck(str, slen);
2137  if (slen < 2)
2138  return ERROR_InvalidMove;
2139 
2140  auto is_digit = [](char ch) {
2141  return isdigit(static_cast<unsigned char>(ch));
2142  };
2143  auto is_lower = [](char ch) {
2144  return islower(static_cast<unsigned char>(ch));
2145  };
2146 
2147  if (slen >= 4 && // Check if it is a coordinates-style move ("e2e4")
2148  is_digit(str[1]) && is_lower(str[2]) && is_digit(str[3])) {
2149  return ReadCoordMove(sm, str, slen, false);
2150  }
2151 
2152  MoveList mlist;
2153  pieceT promo = EMPTY;
2154  auto last_ch = static_cast<unsigned char>(str[slen - 1]);
2155  if (!is_digit(last_ch)) {
2156  // Promotion, last char must be Q/R/B/N.
2157  promo = piece_FromChar(toupper(last_ch));
2158  if (promo != QUEEN && promo != ROOK && promo != KNIGHT &&
2159  promo != BISHOP) {
2160  return ERROR_InvalidMove;
2161  }
2162  slen--;
2163  // Accept the move even if it is of the form "a8Q" not "a8=Q":
2164  if (str[slen - 1] == '=') {
2165  slen--;
2166  }
2167  }
2168  if (slen < 2)
2169  return ERROR_InvalidMove;
2170 
2171  // Check for the compact form of capture with no rank,
2172  // e.g. "ed" or "de=Q":
2173  if (slen == 2 && (str[1] >= 'a' && str[1] <= 'h')) {
2174  auto toFyle = fyle_FromChar(str[1]);
2175  // Check each rank in turn, looking for the capture:
2176  for (rankT r = RANK_1; r <= RANK_8; r++) {
2177  auto to = square_Make(toFyle, r);
2178  if (MatchPawnMove(&mlist, frFyle, to, promo) == OK) {
2179  *sm = *(mlist.Get(0));
2180  return OK;
2181  }
2182  }
2183  // It is NOT a valid capture with no rank:
2184  return ERROR_InvalidMove;
2185  }
2186 
2187  auto toFyle = fyle_FromChar(str[slen - 2]);
2188  auto toRank = rank_FromChar(str[slen - 1]);
2189  if (toRank == NO_RANK || toFyle == NO_FYLE)
2190  return ERROR_InvalidMove;
2191 
2192  auto to = square_Make(toFyle, toRank);
2193  if (MatchPawnMove(&mlist, frFyle, to, promo) != OK)
2194  return ERROR_InvalidMove;
2195 
2196  *sm = *(mlist.Get(0));
2197  return OK;
2198 }
2199 
2200 errorT Position::ReadMoveKing(simpleMoveT* sm, const char* str, int slen) {
2201  ASSERT(sm != NULL && str != NULL);
2202 
2203  slen = trimCheck(str, slen);
2204  if (slen < 3 || slen > 6)
2205  return ERROR_InvalidMove;
2206 
2207  auto toRank = rank_FromChar(str[slen - 1]);
2208  auto toFyle = fyle_FromChar(str[slen - 2]);
2209  if (toRank == NO_RANK || toFyle == NO_FYLE)
2210  return ERROR_InvalidMove;
2211 
2212  auto target = square_Make(toFyle, toRank);
2213  squareT kingSq = GetKingSquare(ToMove);
2214  if (!movegen::valid_king(kingSq, target))
2215  return ERROR_InvalidMove;
2216 
2217  pieceT captured = Board[target];
2218  if (captured != EMPTY && (piece_Color_NotEmpty(captured) == ToMove ||
2219  piece_Type(captured) == KING)) {
2220  return ERROR_InvalidMove;
2221  }
2222 
2223  // XXX We should also check for adjacency to enemy King!!
2224  if (movegen::valid_king(GetKingSquare(color_Flip(ToMove)), target))
2225  return ERROR_InvalidMove;
2226 
2227  // Now make the move on the Board and Material lists, and see if it
2228  // leaves the King in check:
2229  auto movingPiece = piece_Make(ToMove, KING);
2230  Board[target] = movingPiece;
2231  Board[kingSq] = EMPTY;
2232  if (captured != EMPTY) {
2233  Material[captured]--;
2234  }
2235  auto nChecks = CalcNumChecks(target);
2236  if (captured != EMPTY) {
2237  Material[captured]++;
2238  }
2239  Board[target] = captured;
2240  Board[kingSq] = movingPiece;
2241  if (nChecks)
2242  return ERROR_InvalidMove;
2243 
2244  sm->from = kingSq;
2245  sm->to = target;
2246  sm->promote = EMPTY;
2247  sm->movingPiece = movingPiece;
2248  return OK;
2249 }
2250 
2251 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2252 // Position::ReadMove():
2253 // Given a move in (possibly sloppy) PGN notation,
2254 // generates the legal move it corresponds to.
2255 // Returns: OK or ERROR_InvalidMove.
2256 //
2257 errorT Position::ReadMove(simpleMoveT* sm, const char* str, int slen,
2258  pieceT piece) {
2259  ASSERT(sm != NULL && str != NULL);
2260  ASSERT(piece == QUEEN || piece == ROOK || piece == BISHOP ||
2261  piece == KNIGHT);
2262 
2263  slen = trimCheck(str, slen);
2264  if (slen < 3 || slen > 6)
2265  return ERROR_InvalidMove;
2266 
2267  auto toRank = rank_FromChar(str[slen - 1]);
2268  auto toFyle = fyle_FromChar(str[slen - 2]);
2269  if (toRank == NO_RANK || toFyle == NO_FYLE)
2270  return ERROR_InvalidMove;
2271  auto to = square_Make(toFyle, toRank);
2272 
2273  pieceT captured = Board[to];
2274  if (captured != EMPTY && (piece_Color_NotEmpty(captured) == ToMove ||
2275  piece_Type(captured) == KING)) {
2276  return ERROR_InvalidMove;
2277  }
2278 
2279  auto frFyle = NO_FYLE;
2280  auto frRank = NO_RANK;
2281  if (slen > 3) { // There is some ambiguity information in the input string.
2282  frFyle = fyle_FromChar(str[1]);
2283  frRank = rank_FromChar(str[1]);
2284  if (frRank == NO_RANK && slen > 4) {
2285  frRank = rank_FromChar(str[2]);
2286  }
2287  }
2288 
2289  // Loop through looking for pieces of the corresponding type. We start at 1
2290  // since the King is always the piece at position 0 in the list.
2291  int matchCount = 0;
2292  auto movingPiece = piece_Make(ToMove, piece);
2293  int nPieces = Material[movingPiece];
2294  squareT kingSq = GetKingSquare(ToMove);
2295  for (unsigned i = 1, n = Count[ToMove]; i < n && nPieces; i++) {
2296  auto from = List[ToMove][i];
2297  if (Board[from] != movingPiece)
2298  continue;
2299 
2300  --nPieces;
2301  if ((frFyle != NO_FYLE && frFyle != square_Fyle(from)) ||
2302  (frRank != NO_RANK && frRank != square_Rank(from)))
2303  continue;
2304 
2305  if (!movegen::pseudo(from, to, ToMove, piece, Board, EMPTY))
2306  continue;
2307 
2308  auto pin = movegen::opens_ray(from, to, kingSq, Board, EMPTY);
2309  if (pin.first != INVALID_PIECE) {
2310  auto p = Board[pin.second];
2311  if (piece_Color_NotEmpty(p) != ToMove &&
2312  (piece_Type(p) == QUEEN || piece_Type(p) == pin.first))
2313  continue;
2314  }
2315 
2316  ++matchCount;
2317  sm->from = from;
2318  sm->to = to;
2319  sm->promote = EMPTY;
2320  sm->movingPiece = movingPiece;
2321  }
2322  return (matchCount == 1) ? OK // ok.
2323  : ERROR_InvalidMove; // No match, or too many
2324  // (ambiguous) moves match.
2325 }
2326 
2327 errorT Position::ReadMoveCastle(simpleMoveT* sm, const char* str, int slen) {
2328  slen = trimCheck(str, slen);
2329 
2330  auto str_equal = [&](const char* const_str, const int len) {
2331  return slen == len && std::equal(str, str + len, const_str);
2332  };
2333 
2334  // short castle
2335  if (str_equal("O-O", 3) || str_equal("OO", 2)) {
2336  squareT kingSq = GetKingSquare(ToMove);
2337  if (kingSq != (ToMove == WHITE ? E1 : E8))
2338  return ERROR_InvalidMove;
2339 
2340  if (Board[kingSq + 1] != EMPTY || Board[kingSq + 2] != EMPTY ||
2341  CalcNumChecks(kingSq) > 0 || CalcNumChecks(kingSq + 1) > 0 ||
2342  CalcNumChecks(kingSq + 2) > 0) {
2343  return ERROR_InvalidMove;
2344  }
2345  sm->from = kingSq;
2346  sm->to = kingSq + 2;
2347  sm->promote = EMPTY;
2348  sm->movingPiece = KING;
2349  sm->capturedPiece = EMPTY;
2350  return GetCastling(ToMove, KSIDE) ? OK : ERROR_CastlingAvailability;
2351  }
2352  // long castle
2353  if (str_equal("O-O-O", 5) || str_equal("OOO", 3)) {
2354  squareT kingSq = GetKingSquare(ToMove);
2355  if (kingSq != (ToMove == WHITE ? E1 : E8))
2356  return ERROR_InvalidMove;
2357 
2358  if (Board[kingSq - 1] != EMPTY || Board[kingSq - 2] != EMPTY ||
2359  Board[kingSq - 3] != EMPTY || CalcNumChecks(kingSq) > 0 ||
2360  CalcNumChecks(kingSq - 1) > 0 || CalcNumChecks(kingSq - 2) > 0) {
2361  return ERROR_InvalidMove;
2362  }
2363  sm->from = kingSq;
2364  sm->to = kingSq - 2;
2365  sm->promote = EMPTY;
2366  sm->movingPiece = KING;
2367  sm->capturedPiece = EMPTY;
2368  return GetCastling(ToMove, QSIDE) ? OK : ERROR_CastlingAvailability;
2369  }
2370  return ERROR_InvalidMove;
2371 }
2372 
2373 errorT Position::ParseMove(simpleMoveT* sm, const char* str) {
2374  while (!isalpha(static_cast<unsigned char>(*str)) && *str != '\0') {
2375  str++; // trim left
2376  }
2377  const char* begin = str;
2378  while (!isspace(static_cast<unsigned char>(*str)) && *str != '\0') {
2379  str++; // trim right
2380  }
2381  return ParseMove(sm, begin, str);
2382 }
2383 
2384 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2385 // Position::ParseMove():
2386 // Parse a single move from SAN-style notation.
2387 //
2389  const char* strEnd) {
2390  ASSERT(str != NULL);
2391 
2392  int length = static_cast<int>(std::distance(str, strEnd));
2393  if (length < 2 || length > 9)
2394  return ERROR_InvalidMove;
2395 
2396  switch (str[0]) {
2397  case 'a':
2398  return ReadMovePawn(sm, str, length, A_FYLE);
2399  case 'b':
2400  return ReadMovePawn(sm, str, length, B_FYLE);
2401  case 'c':
2402  return ReadMovePawn(sm, str, length, C_FYLE);
2403  case 'd':
2404  return ReadMovePawn(sm, str, length, D_FYLE);
2405  case 'e':
2406  return ReadMovePawn(sm, str, length, E_FYLE);
2407  case 'f':
2408  return ReadMovePawn(sm, str, length, F_FYLE);
2409  case 'g':
2410  return ReadMovePawn(sm, str, length, G_FYLE);
2411  case 'h':
2412  return ReadMovePawn(sm, str, length, H_FYLE);
2413  case 'K':
2414  return ReadMoveKing(sm, str, length);
2415  case 'Q':
2416  return ReadMove(sm, str, length, QUEEN);
2417  case 'R':
2418  return ReadMove(sm, str, length, ROOK);
2419  case 'B':
2420  return ReadMove(sm, str, length, BISHOP);
2421  case 'N':
2422  return ReadMove(sm, str, length, KNIGHT);
2423  case 'O':
2424  return ReadMoveCastle(sm, str, length);
2425  }
2426 
2427  // Check for a null move:
2428  if ((length == 2 && std::equal(str, str + 2, "--")) ||
2429  (length == 2 && std::equal(str, str + 2, "Z0")) ||
2430  (length == 4 && std::equal(str, str + 4, "null"))) {
2431  sm->pieceNum = 0;
2432  sm->from = GetKingSquare(ToMove);
2433  sm->to = sm->from;
2434  sm->movingPiece = Board[sm->from];
2435  sm->promote = EMPTY;
2436  return OK;
2437  }
2438 
2439  // Invalid move, check for a misspelled first char:
2440  switch (str[0]) {
2441  case 'A':
2442  return ReadMovePawn(sm, str, length, A_FYLE);
2443  case 'C':
2444  return ReadMovePawn(sm, str, length, C_FYLE);
2445  case 'D':
2446  return ReadMovePawn(sm, str, length, D_FYLE);
2447  case 'E':
2448  return ReadMovePawn(sm, str, length, E_FYLE);
2449  case 'F':
2450  return ReadMovePawn(sm, str, length, F_FYLE);
2451  case 'G':
2452  return ReadMovePawn(sm, str, length, G_FYLE);
2453  case 'H':
2454  return ReadMovePawn(sm, str, length, H_FYLE);
2455  case 'P':
2456  return ParseMove(sm, str + 1, strEnd);
2457  case 'k':
2458  return ReadMoveKing(sm, str, length);
2459  case 'q':
2460  return ReadMove(sm, str, length, QUEEN);
2461  case 'r':
2462  return ReadMove(sm, str, length, ROOK);
2463  case 'n':
2464  return ReadMove(sm, str, length, KNIGHT);
2465  }
2466  return ERROR_InvalidMove;
2467 }
2468 
2469 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2470 // Position::CalcSANStrings():
2471 // Calculate the SAN string for each move in the legal moves list.
2472 //
2473 void
2475 {
2476  MoveList mlist;
2477  GenerateMoves(&mlist);
2478  for (size_t i = 0, n = mlist.Size(); i < n; i++) {
2479  MakeSANString(mlist.Get(i), sanList->list[i], flag);
2480  }
2481  sanList->num = mlist.Size();
2482  sanList->current = true;
2483 }
2484 
2485 errorT
2486 Position::ReadFromLongStr (const char * str)
2487 {
2488  pieceT pieceFromByte [256] = {EMPTY};
2489  pieceFromByte [(int) 'K'] = WK; pieceFromByte [(int) 'k'] = BK;
2490  pieceFromByte [(int) 'Q'] = WQ; pieceFromByte [(int) 'q'] = BQ;
2491  pieceFromByte [(int) 'R'] = WR; pieceFromByte [(int) 'r'] = BR;
2492  pieceFromByte [(int) 'B'] = WB; pieceFromByte [(int) 'b'] = BB;
2493  pieceFromByte [(int) 'N'] = WN; pieceFromByte [(int) 'n'] = BN;
2494  pieceFromByte [(int) 'P'] = WP; pieceFromByte [(int) 'p'] = BP;
2495 
2496  Clear();
2497  for (squareT sq=A1; sq <= H8; sq++) {
2498  if (str[sq] == '.') { continue; }
2499  pieceT p = pieceFromByte [(byte) str[sq]];
2500  if (p == EMPTY) { return ERROR_Corrupt; }
2501  if (AddPiece (p,sq) != OK) { return ERROR_Corrupt; }
2502  }
2503  switch (str[65]) {
2504  case 'w':
2505  SetToMove (WHITE);
2506  break;
2507  case 'b':
2508  SetToMove (BLACK);
2509  break;
2510  default:
2511  return ERROR_Corrupt;
2512  }
2513  return OK;
2514 }
2515 
2516 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2517 // Position::MakeLongStr():
2518 // Make a string representing the board. It will be 66 characters
2519 // long, encoding the 64 squares (in the order a1,b1,...,g8,h8
2520 // with white pieces in upper case, black pieces in lower case,
2521 // and empty squares as dots) then a space, and finally "w" or "b"
2522 // indicating the side to move. Example for the starting position:
2523 // "RNBQKBNRPPPPPPPP................................pppppppprbnqkbnr w"
2524 //
2525 void
2527 {
2528  ASSERT (str != NULL);
2529  char * s = str;
2530  for (squareT sq = A1; sq <= H8; sq++) {
2531  *s++ = PIECE_CHAR[Board[sq]];
2532  }
2533  *s++ = ' ';
2534  *s++ = (ToMove == WHITE ? 'w' : 'b');
2535  *s = 0;
2536 }
2537 
2538 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2539 // Position::ReadFromCompactStr():
2540 // Sets the position from the provided Null-terminated 33-byte
2541 // compact string.
2542 // The first 32 bytes contain the square valued, 4 bits per value,
2543 // for the square order A1, B1, ...., G8, H8.
2544 // The next byte contains the side to move, 1 for White or 2 for Black.
2545 // The final two bytes contain castling and en passant rights.
2546 // To ensure no bytes within the staring are zero-valued (so it
2547 // can be used as a regular null-terminated string), the value 1
2548 // is added to the color, castling and en passant fields.
2549 errorT
2551 {
2552  Clear();
2553  for (uint i=0; i < 32; i++) {
2554  pieceT p = str[i] >> 4;
2555  if (p != EMPTY) {
2556  if (AddPiece (p, i * 2) != OK) {
2557  return ERROR_Corrupt;
2558  }
2559  }
2560  p = str[i] & 15;
2561  if (p != EMPTY) {
2562  if (AddPiece (p, i * 2 + 1) != OK) {
2563  return ERROR_Corrupt;
2564  }
2565  }
2566  }
2567  colorT toMove = str[32] - 1;
2568  if (toMove != WHITE && toMove != BLACK) {
2569  return ERROR_Corrupt;
2570  }
2571  ToMove = toMove;
2572  Castling = str[33] - 1;
2573  EPTarget = str[34] - 1;
2574  return OK;
2575 }
2576 
2577 void
2579 {
2580  for (uint i=0; i < 32; i++) {
2581  uint i2 = i << 1;
2582  cboard[i] = (byte)(Board[i2] << 4) | Board[i2+1];
2583  }
2584  cboard[32] = 1 + ToMove;
2585  cboard[33] = 1 + Castling;
2586 
2587  // Check that there really is an enemy pawn that might
2588  // be able to capture to the en passant square. For example,
2589  // if the EP square is c6 but there is no white pawn on
2590  // b5 or d5, then en passant should be ignored.
2591 
2592  squareT ep = EPTarget;
2593  if (ToMove == WHITE) {
2594  if (Board[square_Move (ep, DOWN_LEFT)] != WP &&
2595  Board[square_Move (ep, DOWN_RIGHT)] != WP) { ep = NULL_SQUARE; }
2596 
2597  } else {
2598  if (Board[square_Move (ep, UP_LEFT)] != BP &&
2599  Board[square_Move (ep, UP_RIGHT)] != BP) { ep = NULL_SQUARE; }
2600 
2601  }
2602  cboard[34] = 1 + ep;
2603  cboard[35] = 0;
2604 }
2605 
2606 void
2608 {
2609  for (uint i=0; i < 32; i++) {
2610  uint i2 = i << 1;
2611  // Flip 1st rank to 8th, etc:
2612  i2 = ((7 - (i2)/8) * 8 + ((i2) % 8));
2613  cboard[i] = (byte)(PIECE_FLIP[Board[i2]] << 4) |
2614  (byte)(PIECE_FLIP[Board[i2+1]]);
2615  }
2616  cboard[32] = 1 + color_Flip(ToMove);
2617  cboard[33] = 1 + Castling;
2618  cboard[34] = 1 + EPTarget;
2619  cboard[35] = 0;
2620 }
2621 
2622 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2623 // Position::ReadFromFEN():
2624 // Setup the position from a FEN string.
2625 // Note: the slashes usually found in Fen strings to mark the start
2626 // of a new row do not need to be present, but if they are, they must
2627 // appear at the actual start of a new row or the string will be
2628 // considered corrupt.
2629 //
2630 // IMPORTANT: the shortcut of having a two-digit number to represent
2631 // a number of empty rows (e.g. "/24/" instead of "/8/8/8/") is NOT
2632 // accepted by this function.
2633 //
2634 // It is not considered an error for the halfmove clock or fullmove
2635 // counter to be invalid, so this routine can also read positions
2636 // from EPD lines (which only share the first four fields with FEN).
2637 errorT
2638 Position::ReadFromFEN (const char * str)
2639 {
2640  auto is_space = [](char ch) {
2641  return isspace(static_cast<unsigned char>(ch));
2642  };
2643 
2644  // pieceFromByte[] converts a character to its piece, e.g. 'k' -> BK.
2645  static pieceT pieceFromByte [256];
2646 
2647  // fenSqToRealSquare[] converts a fen square (0 to 63) to its real
2648  // square. E.g: [0] -> A8, [1] -> B8, .... [63] -> H1.
2649  static squareT fenSqToRealSquare [64];
2650 
2651  // Note the first Call to set up the static arrays only once:
2652  static int firstCall = 1;
2653 
2654  ASSERT (str != NULL);
2655  const char * s = str;
2656  int count = 0;
2657 
2658  if (firstCall) {
2659  firstCall = 0;
2660 
2661  // Set up pieceFromByte[]:
2662  for (int i=0; i < 256; i++) { pieceFromByte[i] = EMPTY; }
2663  pieceFromByte [(int) 'K'] = WK; pieceFromByte [(int) 'k'] = BK;
2664  pieceFromByte [(int) 'Q'] = WQ; pieceFromByte [(int) 'q'] = BQ;
2665  pieceFromByte [(int) 'R'] = WR; pieceFromByte [(int) 'r'] = BR;
2666  pieceFromByte [(int) 'B'] = WB; pieceFromByte [(int) 'b'] = BB;
2667  pieceFromByte [(int) 'N'] = WN; pieceFromByte [(int) 'n'] = BN;
2668  pieceFromByte [(int) 'P'] = WP; pieceFromByte [(int) 'p'] = BP;
2669 
2670  // Set up fenSqToRealSq[]:
2671  for (int sq=0; sq < 64; sq++) {
2672  fenSqToRealSquare [sq] = (squareT)((7 - (sq)/8) * 8 + ((sq) % 8));
2673  }
2674  }
2675 
2676  Clear ();
2677  while (count < 64) {
2678  if (*s == '/') {
2679  // A FEN string does not have to contain '/'s but if one
2680  // appears anywhere except the start of a row, it is an error:
2681 
2682  if (count % 8) { return ERROR_InvalidFEN; }
2683 
2684  } else if (*s > '0' && *s < '9') {
2685  count += (*s - '0');
2686 
2687  } else {
2688  pieceT p = pieceFromByte [(byte) *s];
2689  if (p == EMPTY) { return ERROR_InvalidFEN; }
2690  if (AddPiece (p, fenSqToRealSquare[count]) != OK) {
2691  return ERROR_InvalidFEN;
2692  }
2693  count++;
2694  }
2695  s++;
2696  }
2697  if (Material[WK] != 1 || Material[BK] != 1) { return ERROR_InvalidFEN; }
2698 
2699  // Now the side to move:
2700  while (is_space(*s)) { s++; }
2701  switch (*s) {
2702  case 'w':
2703  SetToMove (WHITE);
2704  break;
2705  case 'b':
2706  SetToMove (BLACK);
2707  break;
2708  default:
2709  return ERROR_InvalidFEN;
2710  }
2711  s++;
2712 
2713  if (! IsLegal()) { return ERROR_InvalidFEN; }
2714 
2715  // Now the castling flags:
2716  while (is_space(*s)) { s++; }
2717  if (*s == '-') {
2718  s++; // do nothing
2719  } else if (*s == 0) {
2720  // The FEN has no castling field, so just guess that
2721  // castling is possible whenever a king and rook are
2722  // still on their starting squares:
2723  if (Board[E1] == WK) {
2724  if (Board[A1] == WR) { SetCastling (WHITE, QSIDE, true); }
2725  if (Board[H1] == WR) { SetCastling (WHITE, KSIDE, true); }
2726  }
2727  if (Board[E8] == BK) {
2728  if (Board[A8] == BR) { SetCastling (BLACK, QSIDE, true); }
2729  if (Board[H8] == BR) { SetCastling (BLACK, KSIDE, true); }
2730  }
2731  } else {
2732  while (!is_space(*s) && *s != 0) {
2733  switch (*s) {
2734  case 'Q':
2735  SetCastling (WHITE, QSIDE, true);
2736  break;
2737  case 'q':
2738  SetCastling (BLACK, QSIDE, true);
2739  break;
2740  case 'K':
2741  SetCastling (WHITE, KSIDE, true);
2742  break;
2743  case 'k':
2744  SetCastling (BLACK, KSIDE, true);
2745  break;
2746  default:
2747  return ERROR_InvalidFEN;
2748  }
2749  s++;
2750  }
2751  }
2752 
2753  // Now the EP target:
2754  while (is_space(*s)) { s++; }
2755  if (*s == 0) {
2756  // do nothing
2757  } else if (*s == '-') {
2758  EPTarget = NULL_SQUARE;
2759  s++; // No EP target
2760  } else {
2761  char fylec = *s; s++;
2762  if (fylec < 'a' || fylec > 'h') {
2763  return ERROR_InvalidFEN;
2764  }
2765  char rankc = *s; s++;
2766  if (rankc != '3' && rankc != '6') {
2767  return ERROR_InvalidFEN;
2768  }
2769  EPTarget = square_Make(fyle_FromChar(fylec), rank_FromChar(rankc));
2770  }
2771 
2772  // Now the capture/pawn halfmove clock:
2773  while (is_space(*s)) { s++; }
2774  if (*s) {
2775  HalfMoveClock = (ushort) atoi(s);
2776  }
2777  while (!is_space(*s) && *s != 0) { s++; }
2778 
2779  // Finally, the fullmove counter:
2780  while (is_space(*s)) { s++; }
2781  if (*s) {
2782  int i = atoi(s);
2783  if (i >= 1) {
2784  PlyCounter = (i - 1) * 2;
2785  }
2786  }
2787  if (ToMove == BLACK) { PlyCounter++; }
2788  return OK;
2789 }
2790 
2791 
2792 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2793 // Position::PrintFEN():
2794 // Print the FEN representation of the position.
2795 // If flags == FEN_COMPACT, only the board and side-to-move fields
2796 // are printed, in compact form (no slashes between rows).
2797 // If flags == FEN_BOARD, only the board and side-to-move fields
2798 // are printed.
2799 // If flags == FEN_CASTLING_EP, the castling and en passant fields
2800 // are also printed.
2801 // If flags == FEN_ALL_FIELDS, all fields are printed including
2802 // the halfmove clock and ply counter.
2803 //
2804 void Position::PrintFEN(char* str, uint flags) const {
2805  ASSERT (str != NULL);
2806  uint emptyRun, iRank, iFyle;
2807  for (iRank = 0; iRank < 8; iRank++) {
2808  const pieceT* pBoard = &(Board[(7 - iRank) * 8]);
2809  emptyRun = 0;
2810  if (iRank > 0 && flags > FEN_COMPACT) { *str++ = '/'; }
2811  for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
2812  if (*pBoard != EMPTY) {
2813  if (emptyRun) { *str++ = (byte) emptyRun + '0'; }
2814  emptyRun = 0;
2815  *str++ = PIECE_CHAR[*pBoard];
2816  } else {
2817  emptyRun++;
2818  }
2819  }
2820  if (emptyRun) { *str++ = (byte) emptyRun + '0'; }
2821  }
2822 
2823  if (flags > FEN_COMPACT) { *str++ = ' '; }
2824  *str++ = (ToMove == WHITE ? 'w' : 'b');
2825  *str = 0;
2826 
2827  if (flags >= FEN_CASTLING_EP) {
2828  // Add the castling flags and EP flag as well:
2829  *str++ = ' ';
2830  if (Castling == 0) {
2831  *str++ = '-';
2832  } else {
2833  if (GetCastling (WHITE, KSIDE)) { *str++ = 'K'; }
2834  if (GetCastling (WHITE, QSIDE)) { *str++ = 'Q'; }
2835  if (GetCastling (BLACK, KSIDE)) { *str++ = 'k'; }
2836  if (GetCastling (BLACK, QSIDE)) { *str++ = 'q'; }
2837  }
2838  *str++ = ' ';
2839 
2840  // Now the EP target square:
2841  if (EPTarget == NULL_SQUARE) {
2842  *str++ = '-';
2843  } else {
2844  *str++ = square_FyleChar (EPTarget);
2845  *str++ = square_RankChar (EPTarget);
2846  }
2847  *str = 0;
2848 
2849  if (flags >= FEN_ALL_FIELDS) {
2850  // Also print the Halfmove and ply counters:
2851  *str++ = ' ';
2852  sprintf (str, "%d %d", HalfMoveClock, (PlyCounter / 2) + 1);
2853  }
2854  }
2855  return;
2856 }
2857 
2858 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2859 // Position::DumpHtmlBoard():
2860 // Prints the board in a format for use in HTML documents.
2861 // Assumes that the HTML document will be in a directory that
2862 // has a subdirectory bitmapsDir with files "bwr.gif", etc.
2863 // The numeric arguments are the pixel width and height for each
2864 // square -- if zero, then the bitmaps are not scaled.
2865 
2866 // The following values define the available HTML styles.
2867 // Style 0 has 40x40 non-transparent images in the "bitmaps" directory.
2868 // Style 1 has 36x35 non-transparent images in the "bitmaps2" directory.
2869 
2870 struct htmlStyleT {
2871  const char * dir; // directory containing images.
2872  uint width; // width value specified in <img> tag.
2873  uint height; // height value specified in <img> tag.
2874  bool transparent; // True if the style uses transparent images,
2875  // with square colors set by "bgcolor".
2876 };
2877 
2878 void
2879 Position::DumpHtmlBoard (DString * dstr, uint style, const char * dir, bool flip)
2880 {
2881  const uint HTML_DIAG_STYLES = 2;
2882  htmlStyleT hs [HTML_DIAG_STYLES];
2883  hs[0].dir = "bitmaps"; hs[0].width = 40; hs[0].height = 40;
2884  hs[1].dir = "bitmaps2"; hs[1].width = 36; hs[1].height = 35;
2885  if (style >= HTML_DIAG_STYLES) { style = 0; }
2886 
2887  uint width = hs[style].width;
2888  uint height = hs[style].height;
2889  uint iRank, iFyle;
2890  pieceT * pBoard;
2891  if (dir == NULL) { dir = hs[style].dir; }
2892 
2893  dstr->Append ("<br><br><center>\n");
2894  dstr->Append ("<table Border=1 CellSpacing=0 CellPadding=0>\n");
2895  for (iRank = 0; iRank < 8; iRank++) {
2896  dstr->Append ("<tr>\n");
2897  pBoard = &(Board[(7 - iRank) * 8]);
2898  for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
2899  pieceT piece = *pBoard;
2900  if (flip) { piece = Board[iRank * 8 + (7 - iFyle)]; }
2901  dstr->Append (" <td><img border=0 ");
2902  if (width > 0) {
2903  char temp[40];
2904  sprintf (temp, "width=%u ", width);
2905  dstr->Append (temp);
2906  }
2907  if (height > 0) {
2908  char temp[40];
2909  sprintf (temp, "height=%u ", height);
2910  dstr->Append (temp);
2911  }
2912  dstr->Append ("src=\"");
2913  dstr->Append (dir);
2914  dstr->AddChar ('/');
2915  bool lightSq = ((iRank % 2) == (iFyle % 2));
2916  if (lightSq) {
2917  dstr->AddChar ('w');
2918  } else {
2919  dstr->AddChar ('b');
2920  }
2921  if (piece == EMPTY) {
2922  dstr->Append ("sq.gif");
2923  } else {
2924  colorT c = piece_Color(piece);
2925  dstr->AddChar (c == WHITE ? 'w' : 'b');
2926  dstr->AddChar (tolower (PIECE_CHAR[piece]));
2927  dstr->Append (".gif");
2928  }
2929  dstr->Append ("\" alt=\"");
2930  if (piece == EMPTY) {
2931  if (! lightSq) { dstr->Append ("::"); }
2932  } else {
2933  colorT c = piece_Color(piece);
2934  dstr->AddChar (c == WHITE ? 'W' : 'B');
2935  dstr->AddChar (toupper (PIECE_CHAR[piece]));
2936  }
2937  dstr->Append ("\"></td>\n");
2938  }
2939  dstr->Append ("</tr>\n");
2940  }
2941  dstr->Append ("</table>\n");
2942  //if (ToMove == WHITE) {
2943  // dstr->Append ("<br><b>White to move.</b>\n");
2944  //} else {
2945  // dstr->Append ("<br><b>Black to move.</b>\n");
2946  //}
2947  dstr->Append("</center><br>");
2948 }
2949 
2950 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2951 // Position::DumpLatexBoard():
2952 // Prints the board in a format used by a chess package that is
2953 // available for the LaTeX or TeX typesetting language.
2954 void
2956 {
2957  uint iRank, iFyle;
2958  pieceT * pBoard;
2959  dstr->Append ("\\board{");
2960  for (iRank = 0; iRank < 8; iRank++) {
2961  pBoard = &(Board[(7 - iRank) * 8]);
2962  for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
2963  pieceT piece = *pBoard;
2964  if (flip) { piece = Board[iRank * 8 + (7 - iFyle)]; }
2965  if (piece != EMPTY) {
2966  dstr->AddChar (PIECE_CHAR[piece]);
2967  } else { // put a space or a '*':
2968  dstr->AddChar (((iRank % 2) == (iFyle % 2)) ? ' ' : '*');
2969  }
2970  }
2971  if (iRank < 7) {
2972  dstr->Append ("}\n {");
2973  } else { dstr->AddChar ('}'); }
2974  }
2975 }
2976 
2977 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2978 // Position::Compare():
2979 // Compare another position with this one.
2980 //
2981 sint
2983 {
2984  int i = 32;
2985  byte *p1, *p2;
2986  p1 = Board;
2987  p2 = p->Board;
2988  while (i && *p1 == *p2) {
2989  i--; p1++; p2++;
2990  }
2991  if (p1 < p2) { return -1; }
2992  if (p1 > p2) { return 1; }
2993  return (ToMove - p->GetToMove());
2994 }
2995 
2996 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2997 // Position::GetSquares
2998 // Adds to the provided square list all squares containing the specified
2999 // piece, and return the number of pieces of that type on the board.
3000 uint
3002 {
3003  colorT color = piece_Color(piece);
3004  squareT * squares = GetList(color);
3005  uint npieces = GetCount(color);
3006  for (uint i=0; i < npieces; i++) {
3007  squareT sq = squares[i];
3008  pieceT p = Board[sq];
3009  if (p == piece) { sqlist->Add (sq); }
3010  }
3011  return Material[piece];
3012 }
3013 
3014 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3015 // Position::Random
3016 // Given a string such as "KRPKR" or "KRP-kr", sets up a
3017 // random position with that material configuration.
3018 inline squareT
3019 randomSquare (void) { return rand() % 64; }
3020 
3021 inline squareT
3022 randomPawnSquare (void) { return (rand() % 48) + A2; }
3023 
3024 errorT
3026 {
3027  pieceT pieces [32]; // List of pieces excluding kings
3028  uint nPieces[2] = {0, 0}; // Number of pieces per side excluding kings.
3029  uint total = 0; // Total number of pieces excluding kings.
3030 
3031  colorT side = WHITE;
3032 
3033  // The material string must start with a king:
3034  if (toupper(*material) != 'K') { return ERROR_Corrupt; }
3035  material++;
3036 
3037  // Read the material string:
3038  while (1) {
3039  char ch = toupper(*material);
3040  if (ch == 0) { break; }
3041  switch (ch) {
3042  case 'K':
3043  if (side == BLACK) { return ERROR_Corrupt; } // Seen third king!
3044  side = BLACK;
3045  break;
3046  case 'Q': case 'R': case 'B': case 'N': case 'P':
3047  if (nPieces[side] >= 15) { return ERROR_Corrupt; }
3048  nPieces[side]++;
3049  if (ch == 'P') {
3050  pieces[total] = piece_Make (side, PAWN);
3051  } else {
3052  pieces[total] = piece_Make (side, piece_FromChar(ch));
3053  }
3054  total++;
3055  break;
3056  case ' ': case '-': case '.': case ',': case ':':
3057  // Ignore spaces, commas, etc:
3058  break;
3059  default:
3060  return ERROR_Corrupt;
3061  }
3062  material++;
3063  }
3064  if (side != BLACK) { return ERROR_Corrupt; } // Never saw Black king!
3065 
3066  // Generate two non-adjacent king squares:
3067  squareT wk = randomSquare();
3068  squareT bk = randomSquare();
3069  while (wk == bk || square_Adjacent (wk, bk)) { bk = randomSquare(); }
3070 
3071  // Now add all other pieces to empty squares, looping until a legal
3072  // position is found:
3073  while (1) {
3074  Clear();
3075  ToMove = (rand() % 2) ? WHITE : BLACK;
3076  AddPiece (WK, wk);
3077  AddPiece (BK, bk);
3078 
3079  for (uint i=0; i < total; i++) {
3080  squareT sq;
3081  pieceT p = pieces[i];
3082  bool isPawn = (piece_Type(p) == PAWN);
3083  while (1) {
3084  sq = isPawn ? randomPawnSquare() : randomSquare();
3085  if (Board[sq] == EMPTY) { break; }
3086  }
3087  // Add this piece on the random empty square:
3088  AddPiece (p, sq);
3089  }
3090  // Generated a random position with kings not adjacent and
3091  // every piece on its own square. We can stop at this
3092  // attempt if the enemy king is not in check:
3093  squareT enemyKing = (ToMove == WHITE) ? bk : wk;
3094  if (CalcAttacks (ToMove, enemyKing, NULL) == 0) { break; }
3095  }
3096  return OK;
3097 }
3098 
3099 //////////////////////////////////////////////////////////////////////
3100 // EOF: position.cpp
3101 //////////////////////////////////////////////////////////////////////
void GenerateCaptures(MoveList *mlist)
Definition: position.h:239
const pieceT WK
Definition: common.h:241
unsigned char byte
Definition: common.h:89
void DumpHtmlBoard(DString *dstr, uint style, const char *dir, bool flip)
Definition: position.cpp:2879
errorT Random(const char *material)
Definition: position.cpp:3025
fyleT fyle_FromChar(char c)
Definition: common.h:373
void PrintCompactStr(char *cboard)
Definition: position.cpp:2578
const squareT F2
Definition: common.h:349
void SetToMove(colorT c)
Definition: position.h:161
#define HASH(h, p, sq)
Definition: position.cpp:30
const pieceT BB
Definition: common.h:242
piecew sq
Definition: board.tcl:1248
squareT capturedSquare
Definition: movelist.h:45
const colorT WHITE
Definition: common.h:207
pieceT piece_Type(pieceT p)
Definition: common.h:292
byte sanFlagT
Definition: position.h:37
void MakeSANString(simpleMoveT *sm, char *s, sanFlagT flag)
Definition: position.cpp:1888
const squareT C8
Definition: common.h:355
const pieceT BK
Definition: common.h:242
sqsqname
Definition: board.tcl:292
const pieceT BN
Definition: common.h:242
const directionT UP
Definition: common.h:552
iterator end()
Definition: movelist.h:95
const castleDirT KSIDE
Definition: common.h:219
bool square_IsKnightHop(squareT from, squareT to)
Definition: common.h:509
const errorT OK
Definition: error.h:23
bool attack(squareT sqFrom, squareT sqTo, pieceT pieceCol, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Validate an ATTACK move, that is if a piece placed at sqFrom can capture an enemy piece at sqTo...
Definition: movegen.h:132
void CalcPins()
Definition: position.cpp:711
const fyleT D_FYLE
Definition: common.h:365
const squareT F8
Definition: common.h:355
colorT square_Color(squareT sq)
Definition: common.h:410
const squareT H1
Definition: common.h:348
simpleMoveT * Get(size_t index)
Definition: movelist.h:116
const fyleT G_FYLE
Definition: common.h:366
const squareT NULL_SQUARE
Definition: common.h:357
bool IsKingInCheck()
Definition: position.h:255
byte rankT
Definition: common.h:107
const squareT D2
Definition: common.h:349
const directionT LEFT
Definition: common.h:554
promopiece
Definition: calvar.tcl:258
uint FyleCount(pieceT p, fyleT f) const
Definition: position.h:180
const rankT NO_RANK
Definition: common.h:361
static const Position & getStdStart()
Definition: position.cpp:594
void init()
init() - initialize the pool of databases.
Definition: dbasepool.cpp:37
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 directionT dirOpposite[11]
Definition: common.h:561
const squareT C1
Definition: common.h:348
const rankT RANK_8
Definition: common.h:361
const squareT kingAttacks[66][9]
Definition: attacks.h:121
const fyleT B_FYLE
Definition: common.h:365
const directionT UP_LEFT
Definition: common.h:556
const pieceT BQ
Definition: common.h:242
bool pseudo(squareT sqFrom, squareT sqTo, colorT, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Definition: movegen.h:148
void PrintCompactStrFlipped(char *cboard)
Definition: position.cpp:2607
const pieceT WQ
Definition: common.h:241
const pieceT KING
Definition: common.h:226
const rankT RANK_3
Definition: common.h:360
uint RightDiagCount(pieceT p, rightDiagT diag)
Definition: position.h:189
const pieceT BP
Definition: common.h:242
byte capturedNum
Definition: movelist.h:43
const errorT ERROR_CastlingAvailability
Definition: error.h:75
errorT AddPiece(pieceT p, squareT sq)
Definition: position.cpp:670
const colorT BLACK
Definition: common.h:208
errorT ReadFromCompactStr(const byte *str)
Definition: position.cpp:2550
byte castleFlags
Definition: movelist.h:47
errorT RelocatePiece(squareT fromSq, squareT toSq)
Definition: position.cpp:1805
void DoSimpleMove(simpleMoveT *sm)
Definition: position.cpp:1578
const squareT E7
Definition: common.h:354
uint Size()
Definition: movelist.h:96
rankT square_Rank(squareT sq)
Definition: common.h:390
byte fyleT
Definition: common.h:108
const fyleT H_FYLE
Definition: common.h:366
void Add(squareT sq)
Definition: sqmove.h:31
errorT ReadFromFEN(const char *s)
Definition: position.cpp:2638
bool IsLegalMove(simpleMoveT *sm)
Definition: position.cpp:874
const squareT * GetList(colorT c) const
Definition: position.h:169
void MakeUCIString(simpleMoveT *sm, char *s)
Definition: position.cpp:2038
bool IsKingInMate()
Definition: position.cpp:1513
const squareT D7
Definition: common.h:354
const fyleT C_FYLE
Definition: common.h:365
const squareT A8
Definition: common.h:355
colorT color_Flip(colorT c)
Definition: common.h:214
squareT randomPawnSquare(void)
Definition: position.cpp:3022
const fyleT NO_FYLE
Definition: common.h:366
uint CalcAttacks(colorT toMove, squareT kingSq, SquareList *squares)
Definition: position.cpp:1198
bool piece_IsKing(pieceT p)
Definition: common.h:304
const directionT RIGHT
Definition: common.h:555
int32_t sint
Definition: common.h:92
#define POSSIBLE_CAPTURE(d)
iterator begin()
Definition: movelist.h:94
byte PieceCount(pieceT p)
Definition: position.h:157
const pieceT BISHOP
Definition: common.h:229
const errorT ERROR_InvalidFEN
Definition: error.h:62
std::pair< pieceT, squareT > opens_ray(squareT sqFrom, squareT sqTo, squareT sqRay, const TBoard *board, const TBoard EMPTY_SQUARE)
Given a pseudo-legal move, this functions return the type and the location of the piece that can poss...
Definition: movegen.h:179
const squareT A1
Definition: common.h:348
const pieceT KNIGHT
Definition: common.h:230
squareT square_Make(fyleT f, rankT r)
Definition: common.h:377
int find(const char *filename)
find() - search for a database.
Definition: dbasepool.cpp:51
const squareT A7
Definition: common.h:354
uint Size()
Definition: sqmove.h:35
bool valid_king(squareT sqFrom, squareT sqTo)
Definition: movegen.h:46
uint GetSquares(pieceT p, SquareList *sqlist)
Definition: position.cpp:3001
const pieceT PIECE_FLIP[MAX_PIECE_TYPES]
Definition: common.h:256
const directionT UP_RIGHT
Definition: common.h:557
const castleDirT QSIDE
Definition: common.h:219
ushort oldHalfMoveClock
Definition: movelist.h:49
void SetCastling(colorT c, castleDirT dir, bool flag)
Definition: position.h:316
uint CalcNumChecks()
Definition: position.h:244
uint genMovesT
Definition: position.h:54
const pieceT EMPTY
Definition: common.h:239
const pieceT INVALID_PIECE
Definition: common.h:225
const pieceT WB
Definition: common.h:241
const squareT G1
Definition: common.h:348
const squareT F7
Definition: common.h:354
bool Contains(squareT sq)
Definition: sqmove.h:99
void UndoSimpleMove(simpleMoveT *sm)
Definition: position.cpp:1721
void AddChar(char ch)
Definition: dstring.h:32
const fyleT E_FYLE
Definition: common.h:365
const pieceT QUEEN
Definition: common.h:227
void CalcSANStrings(sanListT *sanList, sanFlagT flag)
Definition: position.cpp:2474
uint32_t uint
Definition: common.h:91
void PrintFEN(char *str, uint flags) const
Definition: position.cpp:2804
void GenPieceMoves(MoveList *mlist, squareT sq, SquareSet *sqset, bool capturesOnly)
Definition: position.cpp:752
#define UNHASH(h, p, sq)
Definition: position.cpp:31
void Clear()
Definition: movelist.h:97
const squareT H2
Definition: common.h:349
bool isNullMove() const
Definition: movelist.h:52
int direction_Delta(directionT dir)
Definition: common.h:624
const char * dir
Definition: position.cpp:2871
const squareT B2
Definition: common.h:349
const squareT C2
Definition: common.h:349
uint LeftDiagCount(pieceT p, leftDiagT diag)
Definition: position.h:186
const pieceT ROOK
Definition: common.h:228
rightDiagT square_RightDiag(squareT sq)
Definition: common.h:402
errorT ReadFromLongStr(const char *str)
Definition: position.cpp:2486
rankT rank_FromChar(char c)
Definition: common.h:369
bool IsKingInCheckDir(directionT dir)
Definition: position.cpp:1345
const errorT ERROR_InvalidMove
Definition: error.h:63
const squareT H8
Definition: common.h:355
const rankT RANK_5
Definition: common.h:360
uint MaterialValue(colorT c)
Definition: position.cpp:1860
byte rightDiagT
Definition: common.h:110
const squareT B1
Definition: common.h:348
flipw ?newstate?
Definition: board.tcl:1465
bool attack_slider(squareT sqFrom, squareT sqTo, pieceT pieceType, const TBoard *board, const TBoard EMPTY_SQUARE)
Definition: movegen.h:101
const uint FEN_COMPACT
Definition: position.h:46
const pieceT PAWN
Definition: common.h:231
void DumpLatexBoard(DString *dstr, bool flip)
Definition: position.cpp:2955
errorT ParseMove(simpleMoveT *sm, const char *str)
Definition: position.cpp:2373
const squareT G8
Definition: common.h:355
const squareT G7
Definition: common.h:354
bool IsStdStart() const
Definition: position.cpp:650
errorT ReadCoordMove(simpleMoveT *m, const char *s, int slen, bool reverse)
Definition: position.cpp:2081
bool IsPromoMove(squareT from, squareT to)
Definition: position.cpp:1555
const squareT D1
Definition: common.h:348
const squareT B8
Definition: common.h:355
uint Mobility(pieceT p, colorT color, squareT from)
Definition: position.cpp:1477
void GenerateMoves(MoveList *mlist, pieceT mask, genMovesT genType, bool maybeInCheck)
Definition: position.cpp:784
unsigned short errorT
Definition: error.h:20
const directionT NULL_DIR
Definition: common.h:551
const sanFlagT SAN_NO_CHECKTEST
Definition: position.h:38
pieceT piece_FromChar(int x)
Definition: common.h:328
leftDiagT square_LeftDiag(squareT sq)
Definition: common.h:396
char square_FyleChar(squareT sq)
Definition: common.h:520
const squareT B7
Definition: common.h:354
void Append(uint i)
Definition: dstring.h:46
squareT to
Definition: movelist.h:39
const genMovesT GEN_ALL_MOVES
Definition: position.h:58
byte pieceNum
Definition: movelist.h:42
colorpct ?col?
Definition: ptracker.tcl:77
uint16_t ushort
Definition: common.h:90
squareT from
Definition: movelist.h:38
colorT piece_Color(pieceT p)
Definition: common.h:285
const squareT knightAttacks[66][9]
Definition: attacks.h:43
const pieceT WP
Definition: common.h:241
const squareT E2
Definition: common.h:349
directionT direction_Opposite(directionT d)
Definition: common.h:577
uint RankCount(pieceT p, rankT r) const
Definition: position.h:183
uint SquareColorCount(pieceT p, colorT sqColor)
Definition: position.h:192
void MakeLongStr(char *str)
Definition: position.cpp:2526
pieceT capturedPiece
Definition: movelist.h:44
const directionT DOWN
Definition: common.h:553
struct sqDir_Init sqDir_Init_singleton
materialw
Definition: board.tcl:1506
colorT GetToMove() const
Definition: position.h:162
const squareT A2
Definition: common.h:349
const pieceT END_OF_BOARD
Definition: common.h:240
const squareT E8
Definition: common.h:355
ushort num
Definition: position.h:66
const rankT RANK_6
Definition: common.h:360
const errorT ERROR_Corrupt
Definition: error.h:46
colorT piece_Color_NotEmpty(pieceT p)
Definition: common.h:289
bool direction_IsDiagonal(directionT dir)
Definition: common.h:600
byte colorT
Definition: common.h:104
const char PIECE_CHAR[]
Definition: common.h:252
const pieceT BR
Definition: common.h:242
void Add(squareT sq)
Definition: sqmove.h:74
int Compare(Position *p)
Definition: position.cpp:2982
bool current
Definition: position.h:65
void Clear()
Definition: sqmove.h:30
const pieceT WN
Definition: common.h:241
const genMovesT GEN_NON_CAPS
Definition: position.h:57
constexpr squareT square_Last(squareT sq, directionT dir)
Definition: sqmove.h:286
byte directionT
Definition: common.h:106
const squareT E1
Definition: common.h:348
directionT sqDir[66][66]
Definition: position.cpp:130
bool square_Adjacent(squareT from, squareT to)
Definition: common.h:677
byte leftDiagT
Definition: common.h:109
const directionT DOWN_RIGHT
Definition: common.h:559
const rankT RANK_1
Definition: common.h:360
squareT GetEnemyKingSquare()
Definition: position.h:210
const squareT COLOR_SQUARE
Definition: common.h:356
void Clear()
Definition: position.cpp:563
const errorT ERROR_PieceCount
Definition: error.h:64
const errorT ERROR
Definition: error.h:26
squareT epSquare
Definition: movelist.h:48
const squareT G2
Definition: common.h:349
int TreeCalcAttacks(colorT toMove, squareT target)
Definition: position.cpp:1161
const fyleT A_FYLE
Definition: common.h:365
Implements functions for the validation of chess moves.
const rankT RANK_4
Definition: common.h:360
pieceT movingPiece
Definition: movelist.h:41
const rankT RANK_7
Definition: common.h:361
squareT randomSquare(void)
Definition: position.cpp:3019
uint GetHPSig()
Definition: position.cpp:523
const squareT NS
Definition: common.h:357
const squareT F1
Definition: common.h:348
const squareT C7
Definition: common.h:354
pieceT piece_Make(colorT c, pieceT p)
Definition: common.h:295
char square_RankChar(squareT sq)
Definition: common.h:526
sanStringT list[MAX_LEGAL_MOVES]
Definition: position.h:67
uint GetCount(colorT c) const
Definition: position.h:171
const uint FEN_CASTLING_EP
Definition: position.h:48
const directionT DOWN_LEFT
Definition: common.h:558
const fyleT F_FYLE
Definition: common.h:365
char piece_Char(pieceT p)
Definition: common.h:325
bool IsLegal()
Definition: position.cpp:1533
squareT GetKingSquare()
Definition: position.h:209
bool GetCastling(colorT c, castleDirT dir) const
Definition: position.h:214
pieceT promote
Definition: movelist.h:40
bool transparent
Definition: position.cpp:2874
const uint goodHashValues[12 *64]
Definition: hash.h:28
byte squareT
Definition: common.h:105
void emplace_back(squareT from, squareT to, pieceT promote, pieceT movingPiece, pieceT capturedPiece)
Definition: movelist.h:98
const squareT D8
Definition: common.h:355
const sanFlagT SAN_MATETEST
Definition: position.h:40
byte pieceT
Definition: common.h:103
int isCastle() const
Definition: movelist.h:57
fyleT square_Fyle(squareT sq)
Definition: common.h:384
squareT Get(uint index)
Definition: sqmove.h:37
const pieceT WR
Definition: common.h:241
bool piece_IsSlider(pieceT p)
Definition: common.h:322
const uint FEN_ALL_FIELDS
Definition: position.h:49