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