LCOV - code coverage report
Current view: top level - src - position.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 956 1591 60.1 %
Date: 2017-06-21 14:32:49 Functions: 31 60 51.7 %

          Line data    Source code
       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    16377400 :     HASH (Hash, p, sq);
      38    16377400 :     if (piece_Type(p) == PAWN) {
      39     2119443 :         HASH (PawnHash, p, sq);
      40             :     }
      41             : }
      42             : 
      43             : inline void
      44             : Position::UnHash (pieceT p, squareT sq)
      45             : {
      46    16754311 :     UNHASH (Hash, p, sq);
      47    16754311 :     if (piece_Type(p) == PAWN) {
      48     2326953 :         UNHASH (PawnHash, p, sq);
      49             :     }
      50             : }
      51             : 
      52             : inline void
      53    16377400 : Position::AddToBoard (pieceT p, squareT sq)
      54             : {
      55    16377400 :     ASSERT (Board[sq] == EMPTY);
      56    16377400 :     Board[sq] = p;
      57    32754800 :     NumOnRank[p][square_Rank(sq)]++;
      58    16377400 :     NumOnFyle[p][square_Fyle(sq)]++;
      59    16377400 :     NumOnLeftDiag[p][square_LeftDiag(sq)]++;
      60    16377400 :     NumOnRightDiag[p][square_RightDiag(sq)]++;
      61    16377400 :     NumOnSquareColor[p][square_Color(sq)]++;
      62    32754800 :     AddHash (p, sq);
      63    16377400 : }
      64             : 
      65             : inline void
      66    16754311 : Position::RemoveFromBoard (pieceT p, squareT sq)
      67             : {
      68    16754311 :     ASSERT (Board[sq] == p);
      69    16754311 :     Board[sq] = EMPTY;
      70    33508622 :     NumOnRank[p][square_Rank(sq)]--;
      71    16754311 :     NumOnFyle[p][square_Fyle(sq)]--;
      72    16754311 :     NumOnLeftDiag[p][square_LeftDiag(sq)]--;
      73    16754311 :     NumOnRightDiag[p][square_RightDiag(sq)]--;
      74    16754311 :     NumOnSquareColor[p][square_Color(sq)]--;
      75    33508622 :     UnHash (p, sq);
      76    16754311 : }
      77             : 
      78             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      79             : // initHashValues:
      80             : //    Initialises the table of Zobrist hash values.
      81             : void
      82        4046 : initHashValues (void)
      83             : {
      84             :     // Ensure we set up the hash values only once:
      85             :     static int firstCall = 1;
      86        4046 :     if (! firstCall) { return; }
      87           1 :     firstCall = 0;
      88             : 
      89             : 
      90             :     // First, set all values to 0:
      91             :     uint sq;
      92          17 :     for (uint p = 0; p < 16; p++) {
      93        1040 :         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          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WK][sq] = *hash; hash++; }
     100          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WQ][sq] = *hash; hash++; }
     101          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WR][sq] = *hash; hash++; }
     102          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WB][sq] = *hash; hash++; }
     103          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WN][sq] = *hash; hash++; }
     104          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[WP][sq] = *hash; hash++; }
     105          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BK][sq] = *hash; hash++; }
     106          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BQ][sq] = *hash; hash++; }
     107          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BR][sq] = *hash; hash++; }
     108          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BB][sq] = *hash; hash++; }
     109          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BN][sq] = *hash; hash++; }
     110          65 :     for (sq=A1; sq <= H8; sq++) { hashVal[BP][sq] = *hash; hash++; }
     111             : 
     112             :     // Compute the hash values for the standard starting position:
     113           1 :     uint h = 0;
     114             :     // First the pawns:
     115           1 :     HASH (h,WP,A2);  HASH (h,WP,B2);  HASH (h,WP,C2);  HASH (h,WP,D2);
     116           1 :     HASH (h,WP,E2);  HASH (h,WP,F2);  HASH (h,WP,G2);  HASH (h,WP,H2);
     117           1 :     HASH (h,BP,A7);  HASH (h,BP,B7);  HASH (h,BP,C7);  HASH (h,BP,D7);
     118           1 :     HASH (h,BP,E7);  HASH (h,BP,F7);  HASH (h,BP,G7);  HASH (h,BP,H7);
     119           1 :     stdStartPawnHash = h;
     120             :     // Now the nonpawns:
     121           1 :     HASH (h,WR,A1);  HASH (h,WN,B1);  HASH (h,WB,C1);  HASH (h,WQ,D1);
     122           1 :     HASH (h,WK,E1);  HASH (h,WB,F1);  HASH (h,WN,G1);  HASH (h,WR,H1);
     123           1 :     HASH (h,BR,A8);  HASH (h,BN,B8);  HASH (h,BB,C8);  HASH (h,BQ,D8);
     124           1 :     HASH (h,BK,E8);  HASH (h,BB,F8);  HASH (h,BN,G8);  HASH (h,BR,H8);
     125           1 :     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    15796676 : Position::AssertPos ()
     139             : {
     140    15796676 :     byte mat[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     141    47390028 :     for (colorT c = WHITE; c <= BLACK; c++) {
     142   490198176 :         for (uint i=0; i < Count[c]; i++) {
     143   458604824 :             if (ListPos[List[c][i]] != i
     144   458604824 :                   ||  piece_Color(Board[List[c][i]]) != c) {
     145           0 :                 DumpBoard (stderr);
     146           0 :                 DumpLists (stderr);
     147             :                 return ERROR;
     148             :             }
     149   229302412 :             mat[Board[List[c][i]]]++;
     150             :         }
     151             :     }
     152   426510252 :     for (uint i=WK; i < BP; i++) {
     153   205356788 :         if (mat[i] != Material[i]) {
     154           0 :             DumpBoard (stderr);
     155           0 :             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      394134 : 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      788268 :     squareT king = GetKingSquare (ToMove);
     177      394134 :     squareT friendly = NULL_SQUARE;
     178      394134 :     squareT x = king;
     179      788268 :     squareT last = square_Last (king, dir);
     180      394134 :     int delta = direction_Delta (dir);
     181             : 
     182      971179 :     while (x != last) {
     183      788379 :         x += delta;
     184      788379 :         pieceT p = Board[x];
     185      788379 :         if (p == EMPTY) {
     186             :             // Empty square, so keep searching.
     187      645880 :         } else if (piece_Color_NotEmpty(p) == ToMove) {
     188             :             // Found a friendly piece.
     189      131283 :             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      191657 :             if (friendly != NULL_SQUARE) {
     199             :                 // Potential pin:
     200       66816 :                 pieceT ptype = piece_Type(p);
     201       66816 :                 if (ptype == QUEEN  ||  ptype == attacker) {
     202       41397 :                     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    20001799 : Position::AddLegalMove (MoveList * mlist, squareT from, squareT to, pieceT promo)
     218             : {
     219    20001799 :     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    40003598 :     mlist->emplace_back(from, to, promo, Board[from], Board[to]);
     224    20001799 : }
     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     8973720 : Position::GenSliderMoves (MoveList * mlist, colorT color, squareT fromSq,
     234             :                           directionT dir, SquareSet * sqset, bool capturesOnly)
     235             : {
     236     8973720 :     squareT dest = fromSq;
     237    17947440 :     squareT last = square_Last (fromSq, dir);
     238     8973720 :     int delta = direction_Delta (dir);
     239             : 
     240    18806470 :     while (dest != last) {
     241    13939173 :         dest += delta;
     242    13939173 :         pieceT p = Board[dest];
     243    13939173 :         if (p == EMPTY) {
     244     9832750 :             if (! capturesOnly) {
     245     9832750 :                 if (sqset == NULL  ||  sqset->Contains(dest)) {
     246     8480311 :                     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     8212846 :         if (piece_Color_NotEmpty(p) != color) {
     253     1036915 :             if (sqset == NULL  ||  sqset->Contains(dest)) {
     254      914984 :                 AddLegalMove (mlist, fromSq, dest, EMPTY);
     255             :             }
     256             :         }
     257             :         break;
     258             :     }
     259     8973720 : }
     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      768800 : Position::GenKnightMoves (MoveList * mlist, colorT c, squareT fromSq,
     267             :                           SquareSet * sqset, bool capturesOnly)
     268             : {
     269      768800 :     const squareT * destPtr = knightAttacks[fromSq];
     270             :     while (true) {
     271     4469043 :         squareT dest = *destPtr;
     272     4469043 :         if (dest == NULL_SQUARE) { break; }
     273     3700243 :         destPtr++;
     274     3700243 :         pieceT p = Board[dest];
     275     3700243 :         if (capturesOnly  &&  p == EMPTY) { continue; }
     276     7400486 :         if (piece_Color(p) != c) {
     277     2979794 :             if (sqset == NULL  ||  sqset->Contains(dest)) {
     278     2605728 :                 AddLegalMove (mlist, fromSq, dest, EMPTY);
     279             :             }
     280             :         }
     281             :     }
     282      768800 : }
     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      740813 : Position::GenCastling (MoveList * mlist)
     292             : {
     293      740813 :     ASSERT (! IsKingInCheck());
     294     1481626 :     squareT from = GetKingSquare(ToMove);
     295      740813 :     if (from != (ToMove == WHITE ? E1 : E8))  { return; }
     296      135646 :     squareT enemyKingSq = GetEnemyKingSquare();
     297             :     squareT target, skip, rookSq;
     298             :     pieceT rookPiece;
     299             : 
     300             :     // Try kingside first
     301             : 
     302             :     // Kingside Castling:
     303      271292 :     if (!StrictCastling  ||  GetCastling (ToMove, KSIDE)) {
     304       66780 :         if (ToMove == WHITE) {
     305             :             target = G1; skip = F1; rookSq = H1; rookPiece = WR;
     306             :         } else {
     307       33319 :             target = G8; skip = F8; rookSq = H8; rookPiece = BR;
     308             :         }
     309      158274 :         if (Board[target] == EMPTY  &&  Board[skip] == EMPTY
     310        7230 :                 &&  Board[rookSq] == rookPiece
     311       14460 :                 &&  CalcNumChecks (target) == 0
     312       13926 :                 &&  CalcNumChecks (skip) == 0
     313       73118 :                 &&  ! square_Adjacent (target, enemyKingSq)) {
     314        6338 :             AddLegalMove (mlist, from, target, EMPTY);
     315             :         }
     316             :     }
     317             : 
     318             :     // Queenside Castling:
     319      271292 :     if (!StrictCastling  ||  GetCastling (ToMove, QSIDE)) {
     320       66832 :         if (ToMove == WHITE) {
     321             :             target = C1; skip = D1; rookSq = A1; rookPiece = WR;
     322             :         } else {
     323       34185 :             target = C8; skip = D8; rookSq = A8; rookPiece = BR;
     324             :         }
     325      150282 :         if (Board[target] == EMPTY  &&  Board[skip] == EMPTY
     326        8643 :                 &&  Board[rookSq] == rookPiece
     327        8643 :                 &&  Board[target - 1] == EMPTY // B1 or B8 must be empty too!
     328        7264 :                 &&  CalcNumChecks (target) == 0
     329        6658 :                 &&  CalcNumChecks (skip) == 0
     330       69776 :                 &&  ! square_Adjacent (target, enemyKingSq)) {
     331        2944 :             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      857196 : Position::GenKingMoves (MoveList * mlist, genMovesT genType, bool castling)
     343             : {
     344      857196 :     squareT kingSq = GetKingSquare();
     345      857196 :     squareT enemyKingSq = GetEnemyKingSquare();
     346      857196 :     colorT enemy = color_Flip(ToMove);
     347             :     const squareT * destPtr;
     348      857196 :     pieceT king = piece_Make (ToMove, KING);
     349      857196 :     bool genNonCaptures = (genType & GEN_NON_CAPS);
     350             : 
     351      857196 :     ASSERT (Board[kingSq] == king);
     352             : 
     353      857196 :     destPtr = kingAttacks[kingSq];
     354    11793420 :     while (*destPtr != NULL_SQUARE) {
     355             :         // Try this move and see if it legal:
     356             : 
     357     5468112 :         squareT destSq = *destPtr;
     358     5468112 :         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    10936224 :         if ( (genNonCaptures  &&  Board[destSq] == EMPTY)
     363     7610194 :              ||  piece_Color (Board[destSq]) == enemy) {
     364             : 
     365             :             // Empty or enemy piece there, so try the move:
     366     4562396 :             pieceT captured = Board[destSq];
     367     4562396 :             Board[destSq] = king;
     368     4562396 :             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     4562396 :             if (! square_Adjacent (destSq, enemyKingSq)) {
     373     8875894 :                 if (CalcNumChecks (destSq) == 0) {
     374     3357512 :                     addThisMove = true;
     375             :                 }
     376             :             }
     377     4562396 :             Board[kingSq] = king;
     378     4562396 :             Board[destSq] = captured;
     379             :         }
     380     5468112 :         if (addThisMove) { AddLegalMove (mlist, kingSq, destSq, EMPTY); }
     381     5468112 :         destPtr++;
     382             :     }
     383             :     // Now generate castling moves, if possible:
     384      857196 :     if (genNonCaptures  &&  castling) { GenCastling (mlist); }
     385      857196 : }
     386             : 
     387             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     388             : // Position::AddPromotions():
     389             : //      Add promotion moves.
     390             : //      Called by GenPawnMoves() when a pawn can be promoted.
     391             : //
     392             : inline void
     393       26365 : Position::AddPromotions (MoveList * mlist, squareT from, squareT dest)
     394             : {
     395       52730 :     ASSERT (piece_Type (Board[from]) == PAWN);
     396       52730 :     ASSERT (square_Rank (dest) == RANK_1  ||  square_Rank (dest) == RANK_8);
     397             : 
     398       26365 :     AddLegalMove (mlist, from, dest, QUEEN);
     399       26365 :     AddLegalMove (mlist, from, dest, ROOK);
     400       26365 :     AddLegalMove (mlist, from, dest, BISHOP);
     401       26365 :     AddLegalMove (mlist, from, dest, KNIGHT);
     402       26365 : }
     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        1553 : Position::IsValidEnPassant (squareT from, squareT to)
     413             : {
     414        1553 :     ASSERT (from <= H8  &&  to <= H8);
     415        1553 :     ASSERT (to == EPTarget);
     416             : 
     417             :     // Check that this en passant capture is legal:
     418        3106 :     pieceT ownPawn = piece_Make(ToMove, PAWN);
     419        3106 :     pieceT enemyPawn = piece_Make (color_Flip(ToMove), PAWN);
     420        1553 :     squareT enemyPawnSq = (ToMove == WHITE) ? to - 8 : to + 8;
     421        1553 :     ASSERT (Board[from] == ownPawn);
     422        1553 :     ASSERT (Board[enemyPawnSq] == enemyPawn);
     423        1553 :     Board[from] = EMPTY;
     424             :     
     425             :     // PG
     426        1553 :     Board[to] = ownPawn;
     427             :     
     428        1553 :     Board[enemyPawnSq] = EMPTY;
     429        1553 :     bool isValid = ! IsKingInCheck();
     430             :     
     431             :     //PG
     432        1553 :     Board[to] = EMPTY;
     433             :     
     434        1553 :     Board[from] = ownPawn;
     435        1553 :     Board[enemyPawnSq] = enemyPawn;
     436        1553 :     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     2768749 : Position::GenPawnMoves (MoveList * mlist, squareT from,
     447             :                         directionT dir, SquareSet * sqset, genMovesT genType)
     448             : {
     449     2768749 :     bool genNonCaptures = (genType & GEN_NON_CAPS);
     450     5537498 :     directionT oppdir = direction_Opposite(dir);
     451             :     directionT forward;
     452             :     rankT promoRank;
     453             :     rankT secondRank;
     454     2768749 :     if (ToMove == WHITE) {
     455             :         forward = UP;    promoRank = RANK_8;  secondRank = RANK_2;
     456             :     } else  {
     457     1391826 :         forward = DOWN;  promoRank = RANK_1;  secondRank = RANK_7;
     458             :     }
     459             :     squareT dest;
     460             : 
     461     5537498 :     ASSERT (Board[from] == piece_Make (ToMove, PAWN));
     462             : 
     463     2768749 :     if (genNonCaptures
     464     2768749 :           &&  (dir == NULL_DIR  ||  dir == forward  ||  oppdir == forward)) {
     465     5512066 :         dest = square_Move (from, forward);
     466     2756033 :         if (Board[dest]==EMPTY && (sqset==NULL || sqset->Contains(dest))) {
     467     1626633 :             if (square_Rank(dest) == promoRank) {
     468       22765 :                 AddPromotions (mlist, from, dest);
     469             :             } else {
     470     1603868 :                 AddLegalMove (mlist, from, dest, EMPTY);
     471             :             }
     472             :         }
     473     2756033 :         if (square_Rank(from) == secondRank  &&  Board[dest] == EMPTY) {
     474      633392 :             dest = square_Move (dest, forward);
     475      633392 :             if (Board[dest]==EMPTY  &&  (sqset==NULL || sqset->Contains(dest))) {
     476      500031 :                 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     2768749 :     directionT capdir = forward | LEFT;
     489     2768749 :     if (dir == NULL_DIR  ||  dir == capdir  ||  oppdir == capdir) {
     490     5509138 :         dest = square_Move (from, capdir);
     491     7443925 :         if (POSSIBLE_CAPTURE(dest)  &&  (sqset==NULL || sqset->Contains(dest))) {
     492      458520 :             if (square_Rank(dest) == promoRank) {
     493        1717 :                 AddPromotions (mlist, from, dest);
     494             :             } else {
     495      227543 :                 AddLegalMove (mlist, from, dest, EMPTY);
     496             :             }
     497             :         }
     498             :     }
     499     2768749 :     capdir = forward | RIGHT;
     500     2768749 :     if (dir == NULL_DIR  ||  dir == capdir  ||  oppdir == capdir) {
     501     5504964 :         dest = square_Move (from, capdir);
     502     7426080 :         if (POSSIBLE_CAPTURE(dest)  &&  (sqset==NULL || sqset->Contains(dest))) {
     503      458150 :             if (square_Rank(dest) == promoRank) {
     504        1883 :                 AddPromotions (mlist, from, dest);
     505             :             } else {
     506      227192 :                 AddLegalMove (mlist, from, dest, EMPTY);
     507             :             }
     508             :         }
     509             :     }
     510     2768749 :     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
     523     3511966 : Position::GetHPSig (void)
     524             : {
     525     3511966 :     uint hpSig = 0;
     526     3511966 :     pieceT * b = &(Board[A2]);
     527     3511966 :     if (*b == WP) { hpSig |= 0x8000; }  b++;  /* a2 */
     528     3511966 :     if (*b == WP) { hpSig |= 0x4000; }  b++;  /* b2 */
     529     3511966 :     if (*b == WP) { hpSig |= 0x2000; }  b++;  /* c2 */
     530     3511966 :     if (*b == WP) { hpSig |= 0x1000; }  b++;  /* d2 */
     531     3511966 :     if (*b == WP) { hpSig |= 0x0800; }  b++;  /* e2 */
     532     3511966 :     if (*b == WP) { hpSig |= 0x0400; }  b++;  /* f2 */
     533     3511966 :     if (*b == WP) { hpSig |= 0x0200; }  b++;  /* g2 */
     534     3511966 :     if (*b == WP) { hpSig |= 0x0100; }        /* h2 */
     535     3511966 :     b = &(Board[A7]);
     536     3511966 :     if (*b == BP) { hpSig |= 0x0080; }  b++;  /* a7 */
     537     3511966 :     if (*b == BP) { hpSig |= 0x0040; }  b++;  /* b7 */
     538     3511966 :     if (*b == BP) { hpSig |= 0x0020; }  b++;  /* c7 */
     539     3511966 :     if (*b == BP) { hpSig |= 0x0010; }  b++;  /* d7 */
     540     3511966 :     if (*b == BP) { hpSig |= 0x0008; }  b++;  /* e7 */
     541     3511966 :     if (*b == BP) { hpSig |= 0x0004; }  b++;  /* f7 */
     542     3511966 :     if (*b == BP) { hpSig |= 0x0002; }  b++;  /* g7 */
     543     3511966 :     if (*b == BP) { hpSig |= 0x0001; }        /* h7 */
     544     3511966 :     return hpSig;
     545             : }
     546             : 
     547        4046 : Position::Position() {
     548             :     // Setting up a valid board is left to StdStart() or Clear().
     549        4046 :     Board [COLOR_SQUARE] = EMPTY;
     550        4046 :     Board [NULL_SQUARE] = END_OF_BOARD;
     551        4046 :     StrictCastling = true;
     552             : 
     553             :     // Make sure all tables used for move generation, hashing,
     554             :     // square tests, etc have been computed:
     555        4046 :     initHashValues();
     556        4045 : }
     557             : 
     558             : 
     559             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     560             : // Position::Clear():
     561             : //      Clear the board and associated structures.
     562             : //
     563             : void
     564        4006 : Position::Clear (void)
     565             : {
     566             :     int i;
     567        4006 :     for (i=A1; i <= H8; i++) { Board[i] = EMPTY; }
     568      116174 :     for (i=WK; i <= BP; i++) {
     569       56084 :         Material[i] = 0;
     570      504756 :         for (uint j=0; j < 8; j++) {
     571      448672 :             NumOnRank[i][j] = NumOnFyle[i][j] = 0;
     572             :         }
     573     1738604 :         for (uint d=0; d < 15; d++) {
     574      841260 :             NumOnLeftDiag[i][d] = NumOnRightDiag[i][d] = 0;
     575             :         }
     576       56084 :         NumOnSquareColor[i][WHITE] = NumOnSquareColor[i][BLACK] = 0;
     577             :     }
     578        4006 :     Count[WHITE] = Count[BLACK] = 0;
     579        4006 :     EPTarget = NULL_SQUARE;
     580        4006 :     Castling = 0;
     581        4006 :     Board [NULL_SQUARE] = END_OF_BOARD;
     582        4006 :     PlyCounter = 0;
     583        4006 :     HalfMoveClock = 0;
     584        4006 :     Hash = 0;
     585        4006 :     PawnHash = 0;
     586        4006 :     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             : //
     595       19079 : const Position& Position::getStdStart()
     596             : {
     597       19080 :     static Position startPositionTemplate;
     598             :     static bool init = true;
     599             : 
     600       19079 :     if (init){
     601           1 :         init = false;
     602           1 :         Position* p = &startPositionTemplate;
     603           1 :         p->Clear();
     604           1 :         p->Material[WK] = p->Material[BK] = 1;
     605           1 :         p->Material[WQ] = p->Material[BQ] = 1;
     606           1 :         p->Material[WR] = p->Material[BR] = 2;
     607           1 :         p->Material[WB] = p->Material[BB] = 2;
     608           1 :         p->Material[WN] = p->Material[BN] = 2;
     609           1 :         p->Material[WP] = p->Material[BP] = 8;
     610           1 :         p->Count[WHITE] = p->Count[BLACK] = 16;
     611             : 
     612           1 :         p->AddToBoard(WK, E1);  p->List[WHITE][0] = E1;  p->ListPos[E1] = 0;
     613           1 :         p->AddToBoard(BK, E8);  p->List[BLACK][0] = E8;  p->ListPos[E8] = 0;
     614           1 :         p->AddToBoard(WR, A1);  p->List[WHITE][1] = A1;  p->ListPos[A1] = 1;
     615           1 :         p->AddToBoard(BR, A8);  p->List[BLACK][1] = A8;  p->ListPos[A8] = 1;
     616           1 :         p->AddToBoard(WN, B1);  p->List[WHITE][2] = B1;  p->ListPos[B1] = 2;
     617           1 :         p->AddToBoard(BN, B8);  p->List[BLACK][2] = B8;  p->ListPos[B8] = 2;
     618           1 :         p->AddToBoard(WB, C1);  p->List[WHITE][3] = C1;  p->ListPos[C1] = 3;
     619           1 :         p->AddToBoard(BB, C8);  p->List[BLACK][3] = C8;  p->ListPos[C8] = 3;
     620           1 :         p->AddToBoard(WQ, D1);  p->List[WHITE][4] = D1;  p->ListPos[D1] = 4;
     621           1 :         p->AddToBoard(BQ, D8);  p->List[BLACK][4] = D8;  p->ListPos[D8] = 4;
     622           1 :         p->AddToBoard(WB, F1);  p->List[WHITE][5] = F1;  p->ListPos[F1] = 5;
     623           1 :         p->AddToBoard(BB, F8);  p->List[BLACK][5] = F8;  p->ListPos[F8] = 5;
     624           1 :         p->AddToBoard(WN, G1);  p->List[WHITE][6] = G1;  p->ListPos[G1] = 6;
     625           1 :         p->AddToBoard(BN, G8);  p->List[BLACK][6] = G8;  p->ListPos[G8] = 6;
     626           1 :         p->AddToBoard(WR, H1);  p->List[WHITE][7] = H1;  p->ListPos[H1] = 7;
     627           1 :         p->AddToBoard(BR, H8);  p->List[BLACK][7] = H8;  p->ListPos[H8] = 7;
     628             : 
     629           9 :         for (uint i=0; i < 8; i++) {
     630           8 :             p->AddToBoard(WP, A2+i); p->List[WHITE][i+8] = A2+i; p->ListPos[A2+i] = i+8;
     631           8 :             p->AddToBoard(BP, A7+i); p->List[BLACK][i+8] = A7+i; p->ListPos[A7+i] = i+8;
     632             :         }
     633             : 
     634           1 :         p->Castling = 0;
     635           2 :         p->SetCastling (WHITE, QSIDE, true);  p->SetCastling (WHITE, KSIDE, true);
     636           2 :         p->SetCastling (BLACK, QSIDE, true);  p->SetCastling (BLACK, KSIDE, true);
     637           1 :         p->EPTarget = NULL_SQUARE;
     638           1 :         p->ToMove = WHITE;
     639           1 :         p->PlyCounter = 0;
     640           1 :         p->HalfMoveClock = 0;
     641           1 :         p->Board [NULL_SQUARE] = END_OF_BOARD;
     642           1 :         p->Hash = stdStartHash;
     643           1 :         p->PawnHash = stdStartPawnHash;
     644             :     }
     645       19079 :     return startPositionTemplate;
     646             : }
     647             : 
     648             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     649             : // Position::IsStdStart
     650             : //   Returns true if the position is the standard starting position.
     651             : bool
     652           0 : Position::IsStdStart ()
     653             : {
     654           0 :     if (ToMove != WHITE
     655           0 :           ||  Hash != stdStartHash  ||  PawnHash != stdStartPawnHash
     656           0 :           ||  GetCount(WHITE) != 16  ||  GetCount(BLACK) != 16
     657           0 :           ||  RankCount(WP,RANK_2) != 8  ||  RankCount(BP,RANK_7) != 8
     658           0 :           ||  RankCount(WN,RANK_1) != 2  ||  RankCount(BN,RANK_8) != 2
     659           0 :           ||  !GetCastling(WHITE,KSIDE)  ||  !GetCastling(WHITE,QSIDE)
     660           0 :           ||  !GetCastling(BLACK,KSIDE)  ||  !GetCastling(BLACK,QSIDE)) {
     661             :         return false;
     662             :     }
     663           0 :     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
     673           0 : Position::AddPiece (pieceT p, squareT sq)
     674             : {
     675           0 :     ASSERT (p != EMPTY);
     676           0 :     colorT c = piece_Color(p);
     677           0 :     if ((c != WHITE && c != BLACK) || Count[c] > 15)
     678             :         return ERROR_PieceCount;
     679             : 
     680           0 :     if (piece_Type(p) == KING) {
     681             :         // Check there is not already a King:
     682           0 :         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           0 :         if (Count[c] > 0) {
     687           0 :             squareT oldsq = List[c][0];
     688           0 :             List[c][Count[c]] = oldsq;
     689           0 :             ListPos[oldsq] = Count[c];
     690             :         }
     691           0 :         List[c][0] = sq;
     692           0 :         ListPos[sq] = 0;
     693             :     } else {
     694           0 :         ListPos[sq] = Count[c];
     695           0 :         List[c][Count[c]] = sq;
     696             :     }
     697           0 :     Count[c]++;
     698           0 :     Material[p]++;
     699           0 :     AddToBoard (p, sq);
     700           0 :     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
     714      857196 : Position::CalcPins (void)
     715             : {
     716      857196 :     Pinned[ 0] = Pinned[ 1] = Pinned[ 2] = Pinned[ 3] = Pinned[ 4] =
     717      857196 :     Pinned[ 5] = Pinned[ 6] = Pinned[ 7] = Pinned[ 8] = Pinned[ 9] =
     718      857196 :     Pinned[10] = Pinned[11] = Pinned[12] = Pinned[13] = Pinned[14] =
     719      857196 :     Pinned[15] = NULL_DIR;
     720             : 
     721     1714392 :     squareT kingSq = GetKingSquare (ToMove);
     722      857196 :     colorT enemy = color_Flip (ToMove);
     723     1714392 :     pieceT enemyQueen  = piece_Make (enemy, QUEEN);
     724      857196 :     pieceT enemyRook   = piece_Make (enemy, ROOK);
     725      857196 :     pieceT enemyBishop = piece_Make (enemy, BISHOP);
     726             : 
     727             :     // Pins and checks from Bishops/Queens/Rooks:
     728     1714392 :     fyleT fyle = square_Fyle (kingSq);
     729     2571588 :     if (FyleCount(enemyQueen,fyle) + FyleCount(enemyRook,fyle) > 0) {
     730       86148 :         CalcPinsDir (UP, ROOK);
     731       86148 :         CalcPinsDir (DOWN, ROOK);
     732             :     }
     733      857196 :     rankT rank = square_Rank (kingSq);
     734     2571588 :     if (RankCount(enemyQueen,rank) + RankCount(enemyRook,rank) > 0) {
     735       39621 :         CalcPinsDir (LEFT, ROOK);
     736       39621 :         CalcPinsDir (RIGHT, ROOK);
     737             :     }
     738      857196 :     leftDiagT ld = square_LeftDiag (kingSq);
     739     2571588 :     if (LeftDiagCount(enemyQueen,ld) + LeftDiagCount(enemyBishop,ld) > 0) {
     740       36194 :         CalcPinsDir (UP_LEFT, BISHOP);
     741       36194 :         CalcPinsDir (DOWN_RIGHT, BISHOP);
     742             :     }
     743      857196 :     rightDiagT rd = square_RightDiag (kingSq);
     744     2571588 :     if (RightDiagCount(enemyQueen,rd) + RightDiagCount(enemyBishop,rd) > 0) {
     745       35104 :         CalcPinsDir (UP_RIGHT, BISHOP);
     746       35104 :         CalcPinsDir (DOWN_LEFT, BISHOP);
     747             :     }
     748      857196 : }
     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
     755     2727363 : Position::GenPieceMoves (MoveList * mlist, squareT fromSq,
     756             :                          SquareSet * sqset, bool capturesOnly)
     757             : {
     758     2727363 :     colorT c = ToMove;
     759     2727363 :     pieceT p = Board[fromSq];
     760     2727363 :     pieceT ptype = piece_Type(p);
     761     2727363 :     ASSERT (p != EMPTY  &&  ptype != KING  &&  ptype != PAWN);
     762             : 
     763     2727363 :     if (ptype == KNIGHT) {
     764      768800 :         GenKnightMoves (mlist, c, fromSq, sqset, capturesOnly);
     765      768800 :         return;
     766             :     }
     767     1958563 :     if (ptype != BISHOP) {
     768     1154730 :         GenSliderMoves (mlist, c, fromSq, UP, sqset, capturesOnly);
     769     1154730 :         GenSliderMoves (mlist, c, fromSq, DOWN, sqset, capturesOnly);
     770     1154730 :         GenSliderMoves (mlist, c, fromSq, LEFT, sqset, capturesOnly);
     771     1154730 :         GenSliderMoves (mlist, c, fromSq, RIGHT, sqset, capturesOnly);
     772             :     }
     773     1958563 :     if (ptype != ROOK) {
     774     1085340 :         GenSliderMoves (mlist, c, fromSq, UP_LEFT, sqset, capturesOnly);
     775     1085340 :         GenSliderMoves (mlist, c, fromSq, DOWN_LEFT, sqset, capturesOnly);
     776     1085340 :         GenSliderMoves (mlist, c, fromSq, UP_RIGHT, sqset, capturesOnly);
     777     1085340 :         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
     787      857196 : Position::GenerateMoves (MoveList* mlist, pieceT pieceType,
     788             :                          genMovesT genType, bool maybeInCheck)
     789             : {
     790      857196 :     ASSERT(mlist != NULL);
     791             : 
     792      857196 :     bool genNonCaptures = (genType & GEN_NON_CAPS);
     793      857196 :     bool capturesOnly = !genNonCaptures;
     794             : 
     795      857196 :     uint mask = 0;
     796      857196 :     if (pieceType != EMPTY) {
     797           0 :         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      857196 :     mlist->Clear();
     805             : 
     806             :     // Compute which pieces of the side to move are pinned to the king:
     807      857196 :     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      857196 :     uint numChecks = 0;
     814      857196 :     if (maybeInCheck) {
     815     1598009 :         SquareList checkSquares;
     816     2571588 :         numChecks = CalcNumChecks (GetKingSquare(ToMove), &checkSquares);
     817      857196 :         if (numChecks > 0) {
     818             :             // The side to move IS in check:
     819      116383 :             GenCheckEvasions (mlist, pieceType, genType, &checkSquares);
     820      116383 :             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      740813 :     uint npieces = Count[ToMove];
     828     5582564 :     for (uint x = 1; x < npieces; x++) {
     829     4841751 :         squareT sq = List[ToMove][x];
     830     4841751 :         pieceT p = Board[sq];
     831     4841751 :         pieceT ptype = piece_Type(p);
     832     4841751 :         if (! (mask & (1 << ptype))) { continue; }
     833     4841751 :         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     4841751 :         if (pinned != NULL_DIR) {  // piece x is pinned to king
     839       37488 :             if (ptype == PAWN) {
     840       20600 :                 GenPawnMoves (mlist, sq, pinned, NULL, genType);
     841       16888 :             } 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       11511 :                 if (ptype == QUEEN
     847       13484 :                       || (ptype == ROOK && !direction_IsDiagonal(pinned))
     848       24365 :                       || (ptype == BISHOP && direction_IsDiagonal(pinned))) {
     849        6720 :                     GenSliderMoves (mlist, ToMove, sq, pinned, NULL, capturesOnly);
     850        6720 :                     GenSliderMoves (mlist, ToMove, sq, dirOpposite[pinned],
     851        6720 :                                     NULL, capturesOnly);
     852             :                 }
     853             :             }
     854             :         } else {
     855             :             // This piece is free to move anywhere
     856     4804263 :             if (ptype == PAWN) {
     857     2415768 :                 GenPawnMoves (mlist, sq, NULL_DIR, NULL, genType);
     858             :             } else {
     859             :                 // Knight/Queen/Bishop/Rook:
     860     2388495 :                 GenPieceMoves (mlist, sq, NULL, capturesOnly);
     861             :             }
     862             :         }
     863             :     }
     864             : 
     865             :     // Lastly, king moves...
     866      740813 :     if (mask & (1 << KING)) {
     867      740813 :         bool castling = !numChecks;
     868      740813 :         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
     877           0 : Position::IsLegalMove (simpleMoveT * sm) {
     878           0 :     squareT from = sm->from;
     879           0 :     squareT to = sm->to;
     880           0 :     if (from > H8  ||  to > H8) { return false; }
     881           0 :     if (from == to) { return false; }
     882           0 :     pieceT mover = Board[from];
     883           0 :     pieceT captured = Board[to];
     884           0 :     if (piece_Color(mover) != ToMove) { return false; }
     885           0 :     if (piece_Color(captured) == ToMove) { return false; }
     886           0 :     if (sm->movingPiece != mover) { return false; }
     887           0 :     mover = piece_Type (mover);
     888           0 :     if (sm->promote != EMPTY  &&  mover != PAWN) { return false; }
     889             : 
     890           0 :     if (mover == PAWN) {
     891           0 :         rankT rfrom = square_Rank(from);
     892           0 :         rankT rto = square_Rank(to);
     893           0 :         if (ToMove == BLACK) { rfrom = RANK_8 - rfrom; rto = RANK_8 - rto; }
     894           0 :         int rdiff = (int)rto - (int)rfrom;
     895           0 :         int fdiff = (int)square_Fyle(to) - (int)square_Fyle(from);
     896           0 :         if (rdiff < 1  ||  rdiff > 2) { return false; }
     897           0 :         if (fdiff < -1  ||  fdiff > 1) { return false; }
     898           0 :         if (fdiff == 0) {  // Pawn push:
     899           0 :             if (captured != EMPTY) { return false; }
     900           0 :             if (rdiff == 2) {  // Two-square push:
     901           0 :                 if (rfrom != RANK_2) { return false; }
     902             :                 // Make sure the square in between is empty:
     903           0 :                 squareT midsquare = from + ((to - from) / 2);
     904           0 :                 if (Board[midsquare] != EMPTY) { return false; }
     905             :             }
     906             :         } else {  // Pawn capture:
     907           0 :             if (rdiff != 1) { return false; }
     908           0 :             if (captured == EMPTY) {
     909             :                 // It must be en passant, or illegal
     910           0 :                 if (to != EPTarget) { return false; }
     911             :             }
     912             :         }
     913             :         // Check the promotion piece:
     914           0 :         if (rto == RANK_8) {
     915           0 :             pieceT p = sm->promote;
     916           0 :             if (p != QUEEN  &&  p != ROOK  &&  p != BISHOP  &&  p != KNIGHT) {
     917             :                 return false;
     918             :             }
     919             :         } else {
     920           0 :             if (sm->promote != EMPTY) { return false; }
     921             :         }
     922             : 
     923           0 :     } else if (piece_IsSlider(mover)) {
     924             :         // Make sure the direction is valid:
     925           0 :         directionT dir = sqDir[from][to];
     926           0 :         if (dir == NULL_DIR) { return false; }
     927           0 :         if (mover == ROOK  &&  direction_IsDiagonal(dir)) { return false; }
     928           0 :         if (mover == BISHOP  &&  !direction_IsDiagonal(dir)) { return false; }
     929           0 :         int delta = direction_Delta (dir);
     930             :         // Make sure all the in-between squares are empty:
     931           0 :         squareT dest = from + delta;
     932           0 :         while (dest != to) {
     933           0 :             if (Board[dest] != EMPTY) { return false; }
     934           0 :             dest += delta;
     935             :         }
     936             : 
     937           0 :     } else if (mover == KNIGHT) {
     938           0 :         if (! square_IsKnightHop (from, to)) { return false; }
     939             : 
     940             :     } else /* (mover == KING) */ {
     941           0 :         colorT enemy = color_Flip(ToMove);
     942           0 :         if (square_Adjacent (to, GetKingSquare(enemy))) { return false; }
     943           0 :         if (! square_Adjacent (from, to)) {
     944             :             // The move must be castling, or illegal.
     945           0 :             if (IsKingInCheck()) { return false; }
     946           0 :             MoveList mlist;
     947           0 :             GenCastling (&mlist);
     948           0 :             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           0 :     squareT kingSq = (mover == KING) ? to : GetKingSquare(ToMove);
     954           0 :     colorT enemy = color_Flip(ToMove);
     955           0 :     DoSimpleMove (sm);
     956           0 :     uint nchecks = CalcAttacks (enemy, kingSq, NULL);
     957           0 :     UndoSimpleMove (sm);
     958           0 :     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
     970     1222760 : Position::MatchLegalMove (MoveList * mlist, pieceT mask, squareT target)
     971             : {
     972             :     // This function isn't for Pawn or King moves!
     973     1222760 :     ASSERT (mask != PAWN  &&  mask != KING);
     974     1222760 :     ASSERT(mlist != NULL);
     975             : 
     976     1222760 :     mlist->Clear();
     977             : 
     978     1222760 :     uint count = 0;
     979     2445520 :     uint total = Material[piece_Make(ToMove, mask)];
     980             : 
     981             :     pieceT p, pt, captured;
     982     2445520 :     squareT kingSq = GetKingSquare(ToMove);
     983             :     directionT dir;
     984             : 
     985     1222760 :     uint tryMove = 0;
     986             : 
     987             :     // First, verify that the target square is empty or contains
     988             :     // an enemy piece:
     989             : 
     990     1222760 :     p = Board[target];
     991     1345281 :     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     1222760 :     squareT * sqPtr = &(List[ToMove][1]);
     999     6677855 :     for (uint x=1;  x < Count[ToMove]  &&  count < total;  x++, sqPtr++) {
    1000     5455095 :         p = Board[*sqPtr];
    1001     5455095 :         pt = piece_Type(p);
    1002     5455095 :         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     1982788 :             tryMove = 0;
    1008     1982788 :             count++;
    1009             :             squareT sq;
    1010             : 
    1011     1982788 :             switch (pt) {
    1012             :             case KNIGHT:
    1013      530573 :                 if (square_IsKnightHop (*sqPtr, target)) { tryMove = 1; }
    1014             :                 break;
    1015             : 
    1016             :             case ROOK:
    1017      720714 :                 dir = sqDir[*sqPtr][target];
    1018     1252570 :                 if (dir != NULL_DIR  &&  !direction_IsDiagonal(dir)) {
    1019     1007752 :                     sq = square_Move (*sqPtr, dir);
    1020      503876 :                     tryMove = 1;
    1021     1716564 :                     while (sq != target) {
    1022      664274 :                         if (Board[sq] != EMPTY) { // oops, piece in the way
    1023             :                             tryMove = 0;
    1024             :                             break;
    1025             :                         }
    1026      606344 :                         sq = square_Move (sq, dir);
    1027             :                     }
    1028             :                 }
    1029             :                 break;
    1030             : 
    1031             :             case BISHOP:
    1032      594955 :                 dir = sqDir[*sqPtr][target];
    1033     1189910 :                 if (direction_IsDiagonal(dir)) {
    1034      362759 :                     sq = square_Move (*sqPtr, dir);
    1035      362759 :                     tryMove = 1;
    1036     1065951 :                     while (sq != target) {
    1037      353360 :                         if (Board[sq] != EMPTY) { // oops, piece in the way
    1038             :                             tryMove = 0;
    1039             :                             break;
    1040             :                         }
    1041      351596 :                         sq = square_Move (sq, dir);
    1042             :                     }
    1043             :                 }
    1044             :                 break;
    1045             : 
    1046             :             case QUEEN:
    1047      136546 :                 dir = sqDir[*sqPtr][target];
    1048      136546 :                 if (dir != NULL_DIR) {  // Try the move!
    1049      268564 :                     sq = square_Move (*sqPtr, dir);
    1050      134282 :                     tryMove = 1;
    1051      416748 :                     while (sq != target) {
    1052      141541 :                         if (Board[sq] != EMPTY) { // oops, piece in the way
    1053             :                             tryMove = 0;
    1054             :                             break;
    1055             :                         }
    1056      141233 :                         sq = square_Move (sq, dir);
    1057             :                     }
    1058             :                 }
    1059             :                 break;
    1060             : 
    1061             :             default:  // Should never happen
    1062           0 :                 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     1982788 :             if (tryMove == 1) {
    1069     1263690 :                 captured = Board[target];
    1070     1263690 :                 Board[target] = p;
    1071     1263690 :                 Board[*sqPtr] = EMPTY;
    1072     2527380 :                 if (CalcNumChecks (kingSq) > 0)  { tryMove = 0; }
    1073     1263690 :                 Board[*sqPtr] = p;
    1074     1263690 :                 Board[target] = captured;
    1075     1263690 :                 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      195796 : Position::MatchPawnMove (MoveList * mlist, fyleT fromFyle, squareT to, pieceT promote)
    1090             : {
    1091      195796 :     ASSERT(mlist != NULL);
    1092      195796 :     pieceT promote2 = promote;
    1093             : 
    1094      195796 :     mlist->Clear();
    1095             : 
    1096      391592 :     sint diff = (int)square_Fyle(to) - (int)fromFyle;
    1097      195796 :     if (diff < -1  ||  diff > 1) { return ERROR_InvalidMove; }
    1098             :     pieceT pawn;
    1099      195796 :     rankT toRank = square_Rank(to);
    1100      195796 :     fyleT toFyle = square_Fyle(to);
    1101      195796 :     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      195796 :     squareT from, backup = NS;
    1107             : 
    1108      195796 :     if (ToMove == WHITE) {
    1109       96408 :         pawn = WP;
    1110       96408 :         if (toRank < RANK_3) { return ERROR_InvalidMove; }
    1111      192816 :         from = square_Make(fromFyle, toRank - 1);
    1112       96408 :         if (toRank == RANK_4  &&  fromFyle == toFyle) { backup = to - 16; }
    1113             :     } else {
    1114       99388 :         pawn = BP;
    1115       99388 :         if (toRank > RANK_6) { return ERROR_InvalidMove; }
    1116      198776 :         from = square_Make(fromFyle, toRank + 1);
    1117       99388 :         if (toRank == RANK_5  &&  fromFyle == toFyle) { backup = to + 16; }
    1118             :     }
    1119             : 
    1120             :     // See if the promotion piece is valid:
    1121             : 
    1122      195796 :     if (toRank == promoteRank) {
    1123             :         // if (promote == EMPTY)  { return ERROR_InvalidMove; }
    1124        9864 :         if (promote == EMPTY)  {
    1125             :           // autopromote to queen
    1126           0 :           promote2 = (ToMove == WHITE ? WQ : BQ);
    1127             :         }
    1128             :     } else {
    1129      185932 :         if (promote != EMPTY)  { return ERROR_InvalidMove; }
    1130             :     }
    1131             : 
    1132      195796 :     if (Board[from] != pawn) {
    1133             :         // No match; but it could be a foward-two-squares move:
    1134       34986 :         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      195796 :     uint legal = 0;
    1145      195796 :     if (fromFyle == toFyle) {
    1146             :         // Not a capture:
    1147             : 
    1148      163353 :         if (Board[to] != EMPTY) { return ERROR_InvalidMove; }
    1149      163353 :         Board[to] = pawn;  Board[from] = EMPTY;
    1150      326706 :         if (CalcNumChecks (GetKingSquare()) == 0) {
    1151      163353 :             legal = 1;
    1152             :         }
    1153      163353 :        Board[to] = EMPTY; Board[from] = pawn;
    1154             : 
    1155             :     } else {
    1156             :         // It is a capture -- is it legal?
    1157             : 
    1158       32443 :         pieceT captured = Board[to];
    1159       32443 :         if (captured == EMPTY) {
    1160             :             // Must be an en passant or illegal move.
    1161          72 :             if (to != EPTarget) { return ERROR_InvalidMove; }
    1162         216 :             squareT epSquare = square_Make(toFyle, square_Rank(from));
    1163             : 
    1164         216 :             pieceT enemyPawn = piece_Make (color_Flip(ToMove), PAWN);
    1165             :             // If following assert fails, eptarget was corrupt
    1166          72 :             ASSERT (Board[epSquare] == enemyPawn);
    1167             : 
    1168          72 :             Board[to] = pawn; Board[from] = EMPTY;
    1169          72 :             Board[epSquare] = EMPTY;
    1170          72 :             Material[enemyPawn] --;
    1171         144 :             if (CalcNumChecks (GetKingSquare()) == 0) { legal = 1; }
    1172          72 :             Board[epSquare] = enemyPawn;
    1173          72 :             Board[to] = EMPTY;
    1174          72 :             Board[from] = pawn;
    1175          72 :             Material[enemyPawn]++;
    1176             : 
    1177             :         } else {
    1178       64742 :             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       32371 :                 Board[to] = pawn;  Board[from] = EMPTY;
    1184       32371 :                 Material[captured]--;
    1185       64742 :                 if (CalcNumChecks (GetKingSquare()) == 0) {
    1186       32371 :                     legal = 1;
    1187             :                 }
    1188       32371 :                 Material[captured]++;
    1189       32371 :                 Board[to] = captured; Board[from] = pawn;
    1190             :             }
    1191             :         }
    1192             :     }
    1193             : 
    1194      195796 :     if (legal == 1) {
    1195      195796 :         AddLegalMove (mlist, from, to, promote2);
    1196      195796 :         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
    1208      510806 : Position::MatchKingMove (MoveList * mlist, squareT target)
    1209             : {
    1210      510806 :     ASSERT(mlist != NULL);
    1211             : 
    1212      510806 :     mlist->Clear();
    1213     1021612 :     squareT kingSq = GetKingSquare(ToMove);
    1214      510806 :     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      510806 :     if (diff < -9  ||  diff > 9) { return ERROR_InvalidMove; }
    1219      510806 :     if (diff > -7  &&  diff < -2) { return ERROR_InvalidMove; }
    1220      510806 :     if (diff > 2  &&  diff < 7) { return ERROR_InvalidMove; }
    1221      510806 :     if (diff == 0) { return ERROR_InvalidMove; }
    1222             : 
    1223      510806 :     if (diff == 2) { // KingSide Castling
    1224         367 :         if (kingSq != (ToMove == WHITE ? E1 : E8)) {
    1225             :             return ERROR_InvalidMove;
    1226             :         }
    1227         734 :         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        1101 :         if (Board[kingSq + 1] != EMPTY  ||  Board[kingSq + 2] != EMPTY
    1235         734 :             ||  CalcNumChecks(kingSq) > 0
    1236         734 :             ||  CalcNumChecks(kingSq + 1) > 0
    1237        1101 :             ||  CalcNumChecks(kingSq + 2) > 0) {
    1238             :             return ERROR_InvalidMove;
    1239             :         }
    1240         367 :         AddLegalMove (mlist, kingSq, target, EMPTY);
    1241         367 :         return OK;
    1242             :     }
    1243             : 
    1244      510439 :     if (diff == -2) { // Queenside Castling
    1245         211 :         if (kingSq != (ToMove == WHITE ? E1 : E8)) {
    1246             :             return ERROR_InvalidMove;
    1247             :         }
    1248         422 :         if (StrictCastling  &&  ! GetCastling (ToMove, QSIDE)) {
    1249             :             return ERROR_InvalidMove;
    1250             :         }
    1251         633 :         if (Board[kingSq - 1] != EMPTY  ||  Board[kingSq - 2] != EMPTY
    1252         211 :             ||  Board[kingSq - 3] != EMPTY
    1253         422 :             ||  CalcNumChecks(kingSq) > 0
    1254         422 :             ||  CalcNumChecks(kingSq - 1) > 0
    1255         633 :             ||  CalcNumChecks(kingSq - 2) > 0) {
    1256             :             return ERROR_InvalidMove;
    1257             :         }
    1258         211 :         AddLegalMove (mlist, kingSq, target, EMPTY);
    1259         211 :         return OK;
    1260             :     }
    1261      510228 :     pieceT captured = Board[target];
    1262     1020456 :     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      510228 :     Board[target] = piece_Make(ToMove, KING);
    1272      510228 :     Board[kingSq] = EMPTY;
    1273      510228 :     if (captured != EMPTY) { Material[captured]--; }
    1274      510228 :     uint legal = 0;
    1275     1020456 :     if (CalcNumChecks(target) == 0) { legal = 1; }
    1276      510228 :     if (captured != EMPTY) { Material[captured]++; }
    1277      510228 :     Board[target] = captured;
    1278     1020456 :     Board[kingSq] = piece_Make(ToMove, KING);
    1279      510228 :     if (legal == 1) {
    1280      510228 :         AddLegalMove (mlist, kingSq, target, EMPTY);
    1281      510228 :         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
    1293      116383 : Position::GenCheckEvasions (MoveList * mlist, pieceT mask, genMovesT genType,
    1294             :                             SquareList * checkSquares)
    1295             : {
    1296      116383 :     ASSERT(mlist != NULL);
    1297      116383 :     uint numChecks = checkSquares->Size();
    1298             :     
    1299             :     // Assert that king IS actually in check:    
    1300      116383 :     ASSERT (numChecks > 0);
    1301             : 
    1302      116383 :     bool genNonCaptures = (genType & GEN_NON_CAPS);
    1303      116383 :     bool capturesOnly = !genNonCaptures;
    1304      116383 :     mlist->Clear();
    1305             : 
    1306      232766 :     squareT king = GetKingSquare (ToMove);
    1307             : 
    1308             :     // if it's double check, we can ONLY move the king
    1309      116383 :     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      116000 :         squareT attackSq = checkSquares->Get(0);
    1316      116000 :         directionT dir = sqDir[king][attackSq];
    1317      232000 :         SquareSet targets;  // Set of blocking/capturing squares.
    1318      116000 :         targets.Add(attackSq);
    1319             : 
    1320             :         // Now add squares we can might be able to block on.
    1321      116000 :         if (dir != NULL_DIR) {
    1322      193770 :             squareT sq = square_Move (king, dir);
    1323      341249 :             while (sq != attackSq) {
    1324      122182 :                 if (Board[sq] == EMPTY) { targets.Add(sq); }
    1325      122182 :                 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      116000 :         uint numPieces = Count[ToMove];
    1334      791059 :         for (uint p2 = 1; p2 < numPieces; p2++) {
    1335      675059 :             squareT from = List[ToMove][p2];
    1336      675059 :             pieceT p2piece = Board[from];
    1337      675059 :             if (Pinned[p2] != NULL_DIR) { continue; }
    1338      671158 :             if (mask == EMPTY  ||  mask == piece_Type(p2piece)) {
    1339      671158 :                 if (piece_Type(p2piece) == PAWN) {
    1340      332290 :                     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      332290 :                     if (EPTarget != NULL_SQUARE) {
    1347         105 :                         squareT pawnSq = (ToMove == WHITE ? EPTarget - 8 : EPTarget + 8);
    1348         105 :                         if (pawnSq == attackSq) {
    1349         182 :                             SquareSet epset;
    1350          91 :                             epset.Add(EPTarget);
    1351          91 :                             GenPawnMoves (mlist, from, NULL_DIR, &epset, genType);
    1352             :                         }
    1353             :                     }
    1354             :                 } else {
    1355      338868 :                     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      116383 :     if (mask == EMPTY  ||  mask == KING) { GenKingMoves(mlist, genType, false); }
    1363             : 
    1364      116383 :     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
    1372           0 : Position::TreeCalcAttacks(colorT side, squareT target)
    1373             : {
    1374           0 :   int maxScore = -2;
    1375           0 :   uint moveCount = 0, zeroCount = 0;
    1376           0 :   MoveList moveList;
    1377           0 :   GenerateCaptures(&moveList);
    1378           0 :   for (uint i=0; i < moveList.Size(); i++) {
    1379           0 :     simpleMoveT *smPtr = moveList.Get(i);
    1380           0 :     if (smPtr->to == target) {
    1381           0 :       if (piece_IsKing(Board[target])) return -1;
    1382           0 :       moveCount++;
    1383           0 :       DoSimpleMove(smPtr);
    1384           0 :       int score = TreeCalcAttacks(color_Flip(side), target);
    1385           0 :       UndoSimpleMove(smPtr);
    1386           0 :       if (!score && ++zeroCount > 1) return -2;
    1387           0 :       if (score > maxScore) maxScore = score;
    1388             :     }
    1389             :   }
    1390             : 
    1391           0 :  if (!moveCount) return 0;
    1392           0 :  if (!maxScore) return -1;
    1393           0 :  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     9589353 : 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    19178706 :     SquareList fromSqs;
    1416     9589353 :     if (fromSquares == NULL) { fromSquares = &fromSqs; }
    1417             : 
    1418     9589353 :     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     9589353 :     if (side == WHITE) {
    1424             :         king = WK; queen = WQ; rook = WR; bishop = WB; knight = WN;
    1425             :     } else {
    1426     4805971 :         king = BK; queen = BQ; rook = BR; bishop = BB; knight = BN;
    1427             :     }
    1428             : 
    1429     9589353 :     uint numQueensRooks = Material[queen] + Material[rook];
    1430     9589353 :     uint numQueensBishops = Material[queen] + Material[bishop];
    1431             : 
    1432             :     // We only bother if there are any sliding pieces of each type:
    1433     9589353 :     if (numQueensRooks > 0) {
    1434    12550152 :         fyleT fyle = square_Fyle (target);
    1435     6275076 :         rankT rank = square_Rank (target);
    1436             :         directionT dirs[4];
    1437     6275076 :         uint ndirs = 0;
    1438    18825228 :         if (FyleCount(queen,fyle) + FyleCount(rook,fyle) > 0) {
    1439      966223 :             dirs[ndirs++] = UP;  dirs[ndirs++] = DOWN;
    1440             :         }
    1441    18825228 :         if (RankCount(queen,rank) + RankCount(rook,rank) > 0) {
    1442      429392 :             dirs[ndirs++] = LEFT; dirs[ndirs++] = RIGHT;
    1443             :         }
    1444     9066306 :         for (uint i = 0; i < ndirs; i++) {
    1445     2791230 :             directionT dir = dirs[i];
    1446     5582460 :             int delta = direction_Delta (dir);
    1447     2791230 :             squareT dest = target;
    1448     2791230 :             squareT last = square_Last (target, dir);
    1449             : 
    1450     6154295 :             while (dest != last) {
    1451     5038705 :                 dest += delta;
    1452     5038705 :                 pieceT p = Board[dest];
    1453     5038705 :                 if (p == EMPTY) {
    1454             :                     // empty square: keep searching
    1455     1675640 :                 } else if (p == queen  ||  p == rook) {
    1456             :                     // Found an attacking piece
    1457      492735 :                     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     9589353 :     if (numQueensBishops > 0) {
    1469    12664392 :         leftDiagT left = square_LeftDiag (target);
    1470     6332196 :         rightDiagT right = square_RightDiag (target);
    1471             :         directionT dirs[4];
    1472     6332196 :         uint ndirs = 0;
    1473    18996588 :         if (LeftDiagCount(queen,left) + LeftDiagCount(bishop,left) > 0) {
    1474      448201 :             dirs[ndirs++] = UP_LEFT;  dirs[ndirs++] = DOWN_RIGHT;
    1475             :         }
    1476    18996588 :         if (RightDiagCount(queen,right) + RightDiagCount(bishop,right) > 0) {
    1477      440457 :             dirs[ndirs++] = UP_RIGHT;  dirs[ndirs++] = DOWN_LEFT;
    1478             :         }
    1479     8109512 :         for (uint i = 0; i < ndirs; i++) {
    1480     1777316 :             directionT dir = dirs[i];
    1481     3554632 :             int delta = direction_Delta (dir);
    1482     1777316 :             squareT dest = target;
    1483     1777316 :             squareT last = square_Last (target, dir);
    1484             : 
    1485     3417925 :             while (dest != last) {
    1486     2642726 :                 dest += delta;
    1487     2642726 :                 pieceT p = Board[dest];
    1488     2642726 :                 if (p == EMPTY) {
    1489             :                     // empty square: keep searching
    1490     1002117 :                 } else if (p == queen  ||  p == bishop) {
    1491             :                     // Found an attacking piece
    1492      412286 :                     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    19178706 :     if (Material[knight] > 0
    1505    26369580 :          &&  SquareColorCount(knight, color_Flip(square_Color(target))) > 0) {
    1506     3487840 :         const squareT * destPtr = knightAttacks[target];
    1507             :         while (true) {
    1508    21129380 :             squareT dest = *destPtr;
    1509    21129380 :             if (dest == NULL_SQUARE) { break; }
    1510    17641540 :             if (Board[dest] == knight) {
    1511      235450 :                 fromSquares->Add(dest);
    1512             :             }
    1513    17641540 :             destPtr++;
    1514    17641540 :         }
    1515             :     }
    1516             : 
    1517             :     // Now pawn attacks:
    1518     9589353 :     if (side == WHITE) {
    1519     9566764 :         if (square_Rank(target) != RANK_1) {  //if (Material[WP] > 0) {
    1520     4677708 :             sq = square_Move (target, DOWN_LEFT);
    1521     4677708 :             if (Board[sq] == WP)  {
    1522       74079 :                 fromSquares->Add(sq);
    1523             :             }
    1524     4677708 :             sq = square_Move (target, DOWN_RIGHT);
    1525     4677708 :             if (Board[sq] == WP)  {
    1526       71220 :                 fromSquares->Add(sq);
    1527             :             }
    1528             :         }
    1529             :     } else {
    1530     9611942 :         if (square_Rank(target) != RANK_8) {  //if (Material[BP] > 0) {
    1531     4694172 :             sq = square_Move (target, UP_LEFT);
    1532     4694172 :             if (Board[sq] == BP)  {
    1533       73047 :                 fromSquares->Add(sq);
    1534             :             }
    1535     4694172 :             sq = square_Move (target, UP_RIGHT);
    1536     4694172 :             if (Board[sq] == BP)  {
    1537       75185 :                 fromSquares->Add(sq);
    1538             :             }
    1539             :         }
    1540             :     }
    1541             : 
    1542             :     // King attacks:
    1543     9589353 :     const squareT *destPtr = kingAttacks[target];
    1544   189779487 :     do if (Board[*destPtr] == king) fromSquares->Add(*destPtr);
    1545    63259829 :     while (*++destPtr != NULL_SQUARE);
    1546             : 
    1547    19178706 :     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
    1556           0 : Position::IsKingInCheckDir (directionT dir)
    1557             : {
    1558           0 :     ASSERT (dir != NULL_DIR);
    1559           0 :     squareT kingSq = GetKingSquare(ToMove);
    1560           0 :     colorT enemy = color_Flip(ToMove);
    1561           0 :     bool isDiagonal = direction_IsDiagonal(dir);
    1562           0 :     pieceT queen = piece_Make (enemy, QUEEN);
    1563           0 :     pieceT slider = piece_Make (enemy, (isDiagonal ? BISHOP : ROOK));
    1564             : 
    1565             :     // First, make sure the enemy has sliding pieces that could give check:
    1566           0 :     uint nSliders = PieceCount(queen) + PieceCount(slider);
    1567           0 :     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           0 :     fyleT fyle = square_Fyle (kingSq);
    1572           0 :     rankT rank = square_Rank (kingSq);
    1573           0 :     leftDiagT ldiag = square_LeftDiag (kingSq);
    1574           0 :     rightDiagT rdiag = square_RightDiag (kingSq);
    1575             : 
    1576           0 :     switch (dir) {
    1577             :     case UP:
    1578             :     case DOWN:
    1579           0 :         nSliders = FyleCount(queen,fyle) + FyleCount(slider,fyle);
    1580           0 :         break;
    1581             :     case LEFT:
    1582             :     case RIGHT:
    1583           0 :         nSliders = RankCount(queen,rank) + RankCount(slider,rank);
    1584           0 :         break;
    1585             :     case UP_LEFT:
    1586             :     case DOWN_RIGHT:
    1587           0 :         nSliders = LeftDiagCount(queen,ldiag) + LeftDiagCount(slider,ldiag);
    1588           0 :         break;
    1589             :     case UP_RIGHT:
    1590             :     case DOWN_LEFT:
    1591           0 :         nSliders = RightDiagCount(queen,rdiag) + RightDiagCount(slider,rdiag);
    1592           0 :         break;
    1593             :     }
    1594           0 :     if (nSliders == 0) { return false; }
    1595             : 
    1596             :     // Now move along the specified direction looking for a checking piece:
    1597           0 :     squareT dest = kingSq;
    1598           0 :     squareT last = square_Last (kingSq, dir);
    1599           0 :     int delta = direction_Delta (dir);
    1600             : 
    1601           0 :     while (dest != last) {
    1602           0 :         dest += delta;
    1603           0 :         pieceT p = Board[dest];
    1604           0 :         if (p == EMPTY) {
    1605             :              // empty square: keep searching
    1606           0 :         } 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           0 :     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
    1627           0 : Position::IsKingInCheck (simpleMoveT * sm)
    1628             : {
    1629           0 :     if (sm == NULL) { return IsKingInCheck(); }
    1630             : 
    1631           0 :     squareT kingSq = GetKingSquare(ToMove);
    1632           0 :     pieceT p = piece_Type (sm->movingPiece);
    1633           0 :     if (sm->promote != EMPTY) { p = piece_Type(sm->promote); }
    1634             : 
    1635             :     // No optimization of the last move was castling:
    1636           0 :     if (p == KING  &&  square_Fyle(sm->from) == E_FYLE) {
    1637           0 :         fyleT toFyle = square_Fyle(sm->to);
    1638           0 :         if (toFyle == C_FYLE  ||  toFyle == G_FYLE) {
    1639           0 :             return IsKingInCheck();
    1640             :         }
    1641             :     }
    1642             :     // No optimization for en passant capture:
    1643           0 :     if (p == PAWN  &&  piece_Type(sm->capturedPiece) == PAWN) {
    1644           0 :         rankT fromRank = square_Rank(sm->from);
    1645           0 :         rankT capturedRank = square_Rank(sm->capturedSquare);
    1646           0 :         if (fromRank == capturedRank) { return IsKingInCheck(); }
    1647             :     }
    1648             : 
    1649           0 :     if (p == PAWN) {
    1650           0 :         if (ToMove == WHITE) {
    1651           0 :             if (Material[BP] > 0) {
    1652           0 :                 squareT sq = square_Move (kingSq, UP_LEFT);
    1653           0 :                 if (Board[sq] == BP)  { return true; }
    1654           0 :                 sq = square_Move (kingSq, UP_RIGHT);
    1655           0 :                 if (Board[sq] == BP)  { return true; }
    1656             :             }
    1657             :         } else {
    1658           0 :             if (Material[WP] > 0) {
    1659           0 :                 squareT sq = square_Move (kingSq, DOWN_LEFT);
    1660           0 :                 if (Board[sq] == WP)  { return true; }
    1661           0 :                 sq = square_Move (kingSq, DOWN_RIGHT);
    1662           0 :                 if (Board[sq] == WP)  { return true; }
    1663             :             }
    1664             :         }
    1665           0 :     } else if (p == KNIGHT) {
    1666           0 :         if (square_IsKnightHop (kingSq, sm->to)) { return true; }
    1667           0 :     } else if (p == KING) {
    1668             :         // A king cannot directly check its adversary.
    1669             :     } else {
    1670             :         // A sliding piece:
    1671           0 :         directionT toDir = sqDir[kingSq][sm->to];
    1672           0 :         if (toDir != NULL_DIR  &&  IsKingInCheckDir(toDir)) { return true; }
    1673             :     }
    1674             : 
    1675             :     // Now look for a discovered check from a sliding piece:
    1676           0 :     directionT dir = sqDir[kingSq][sm->from];
    1677           0 :     if (dir != NULL_DIR  &&  IsKingInCheckDir(dir)) { return true; }
    1678             : 
    1679           0 :     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
    1688           0 : Position::Mobility (pieceT p, colorT color, squareT from)
    1689             : {
    1690           0 :     ASSERT (p == ROOK  ||  p == BISHOP);
    1691           0 :     uint mobility = 0;
    1692           0 :     directionT rookDirs[4] = { UP, DOWN, LEFT, RIGHT };
    1693             :     directionT bishopDirs[4]
    1694           0 :         = { UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT };
    1695           0 :     directionT * dirPtr = (p == ROOK ? rookDirs : bishopDirs);
    1696             : 
    1697           0 :     for (uint i=0; i < 4; i++) {
    1698           0 :         directionT dir = dirPtr[i];
    1699           0 :         int delta = direction_Delta (dir);
    1700           0 :         squareT dest = from;
    1701           0 :         squareT last = square_Last (from, dir);
    1702             : 
    1703           0 :         while (dest != last) {
    1704           0 :             dest += delta;
    1705           0 :             pieceT p = Board[dest];
    1706           0 :             if (p == EMPTY) {  // Empty square
    1707           0 :                 mobility++;
    1708           0 :             } else if (piece_Color(p) == color) {  // Friendly piece
    1709             :                 break;  // Finished with this direction.
    1710             :             } else {  // Enemy piece
    1711           0 :                 mobility++;
    1712           0 :                 break;  // Finished with this direction.
    1713             :             }
    1714             :         }
    1715             :     }
    1716           0 :     return mobility;
    1717             : }
    1718             : 
    1719             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1720             : // Position::IsKingInMate():
    1721             : //      Quick check if king is in mate.
    1722             : //
    1723             : bool
    1724           0 : Position::IsKingInMate (void)
    1725             : {
    1726           0 :     SquareList checkSquares;
    1727           0 :     uint numChecks = CalcNumChecks (GetKingSquare(ToMove), &checkSquares);
    1728           0 :     if (numChecks == 0) { return false; }
    1729           0 :     CalcPins ();
    1730           0 :     MoveList mlist;
    1731           0 :     GenCheckEvasions (&mlist, EMPTY, GEN_ALL_MOVES, &checkSquares);
    1732           0 :     if (mlist.Size() == 0) { return true; }
    1733           0 :     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
    1744           0 : Position::IsLegal (void)
    1745             : {
    1746           0 :     squareT stmKing = GetKingSquare();
    1747           0 :     squareT enemyKing = GetEnemyKingSquare();
    1748           0 :     if (square_Adjacent (stmKing, enemyKing)) { return false; }
    1749           0 :     if (RankCount (WP, RANK_1) != 0) { return false; }
    1750           0 :     if (RankCount (WP, RANK_8) != 0) { return false; }
    1751           0 :     if (RankCount (BP, RANK_1) != 0) { return false; }
    1752           0 :     if (RankCount (BP, RANK_8) != 0) { return false; }
    1753           0 :     if (CalcAttacks (ToMove, enemyKing, NULL) > 0) {
    1754             :          return false;
    1755             :     }
    1756           0 :     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
    1766           0 : Position::IsPromoMove (squareT from, squareT to)
    1767             : {
    1768             :     rankT seventh, eighth;
    1769             :     pieceT pawn;
    1770           0 :     if (ToMove == WHITE) { seventh = RANK_7; eighth = RANK_8; pawn = WP; }
    1771           0 :     else { seventh = RANK_2; eighth = RANK_1; pawn = BP; }
    1772             :     rankT fromR, toR;
    1773           0 :     fromR = square_Rank(from);
    1774           0 :     toR = square_Rank(to);
    1775           0 :     if ( (fromR == seventh  &&  toR == eighth  &&  Board[from] == pawn)  ||
    1776           0 :          (toR == seventh  &&  fromR == eighth  &&  Board[to] == pawn) ) {
    1777             :         return 1;
    1778             :     }
    1779           0 :     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
    1789    10353839 : Position::DoSimpleMove (simpleMoveT * sm)
    1790             : {
    1791    10353839 :     ASSERT (sm != NULL);
    1792    10353839 :     squareT from = sm->from;
    1793    10353839 :     squareT to = sm->to;
    1794    10353839 :     pieceT p = Board[from];
    1795    20707678 :     pieceT ptype = piece_Type(p);
    1796    20707678 :     colorT enemy = color_Flip(ToMove);
    1797    10353839 :     ASSERT (p != EMPTY);
    1798             : 
    1799             :     // update move fields that (maybe) have not yet been set:
    1800             : 
    1801    10353839 :     sm->pieceNum = ListPos[from];
    1802    10353839 :     sm->capturedPiece = Board[to];
    1803    10353839 :     sm->capturedSquare = to;
    1804    10353839 :     sm->castleFlags = Castling;
    1805    10353839 :     sm->epSquare = EPTarget;
    1806    10353839 :     sm->oldHalfMoveClock = HalfMoveClock;
    1807             : 
    1808    10353839 :     HalfMoveClock++;
    1809    10353839 :     PlyCounter++;
    1810             : 
    1811             :     // Check for a null (empty) move:
    1812    20707678 :     if (sm->isNullMove()) {
    1813           0 :         ToMove = enemy;
    1814           0 :         EPTarget = NULL_SQUARE;
    1815           0 :         return;
    1816             :     }
    1817             : 
    1818             :     // Handle en passant capture:
    1819             : 
    1820    11614426 :     if (ptype == PAWN  &&  sm->capturedPiece == EMPTY
    1821    12450031 :             && 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         802 :         pieceT enemyPawn = piece_Make(enemy, PAWN);
    1827         401 :         sm->capturedSquare = (ToMove == WHITE ? (to - 8) : (to + 8));
    1828         401 :         ASSERT (Board[sm->capturedSquare] == enemyPawn);
    1829         401 :         sm->capturedPiece = enemyPawn;
    1830             :     }
    1831             : 
    1832             :     // handle captures:
    1833             : 
    1834    10353839 :     if (sm->capturedPiece != EMPTY) {
    1835     1679918 :         ASSERT (piece_Type(sm->capturedPiece) != KING);
    1836      839959 :         sm->capturedNum = ListPos[sm->capturedSquare];
    1837             :         // update opponents List of pieces
    1838      839959 :         Count[enemy]--;
    1839      839959 :         ListPos[List[enemy][Count[enemy]]] = sm->capturedNum;
    1840      839959 :         List[enemy][sm->capturedNum] = List[enemy][Count[enemy]];
    1841      839959 :         Material[sm->capturedPiece]--;
    1842      839959 :         HalfMoveClock = 0;
    1843      839959 :         RemoveFromBoard (sm->capturedPiece, sm->capturedSquare);
    1844             :     }
    1845             : 
    1846             :     // handle promotion:
    1847             : 
    1848    10353839 :     if (sm->promote != EMPTY) {
    1849      147922 :         ASSERT (p == piece_Make(ToMove, PAWN));
    1850       73961 :         Material[p]--;
    1851       73961 :         RemoveFromBoard (p, from);
    1852      147922 :         p = piece_Make(ToMove, sm->promote);
    1853       73961 :         Material[p]++;
    1854       73961 :         AddToBoard (p, from);
    1855             :     }
    1856             : 
    1857             :     // now make the move:
    1858    10353839 :     List[ToMove][sm->pieceNum] = to;
    1859    10353839 :     ListPos[to] = sm->pieceNum;
    1860    10353839 :     RemoveFromBoard (p, from);
    1861    10353839 :     AddToBoard (p, to);
    1862             : 
    1863             :     // handle Castling:
    1864             : 
    1865    24678814 :     if (ptype == KING  &&  square_Fyle(from) == E_FYLE  &&
    1866      983468 :             (square_Fyle(to) == C_FYLE  ||  square_Fyle(to) == G_FYLE)) {
    1867             :         squareT rookfrom, rookto;
    1868       14414 :         pieceT rook = piece_Make (ToMove, ROOK);
    1869        7207 :         if (square_Fyle(to) == C_FYLE) {
    1870        1188 :             rookfrom = to - 2;
    1871        1188 :             rookto = to + 1;
    1872             :         } else {
    1873        6019 :             rookfrom = to + 1;
    1874        6019 :             rookto = to - 1;
    1875             :         }
    1876        7207 :         ListPos[rookto] = ListPos[rookfrom];
    1877        7207 :         List[ToMove][ListPos[rookto]] = rookto;
    1878        7207 :         RemoveFromBoard (rook, rookfrom);
    1879        7207 :         AddToBoard (rook, rookto);
    1880             :     }
    1881             : 
    1882             :     // Handle clearing of castling flags:
    1883             : 
    1884    10353839 :     if (Castling) {
    1885     1480480 :         if (ptype == KING) {   // The king moved.
    1886      188722 :             SetCastling (ToMove, QSIDE, false);
    1887       94361 :             SetCastling (ToMove, KSIDE, false);
    1888             :         }
    1889             :         // See if a rook moved or was captured:
    1890     1480480 :         if (ToMove == WHITE) {
    1891      745076 :             if (from == A1)  { SetCastling (WHITE, QSIDE, false); }
    1892      745076 :             if (from == H1)  { SetCastling (WHITE, KSIDE, false); }
    1893      745076 :             if (to == A8)    { SetCastling (BLACK, QSIDE, false); }
    1894      745076 :             if (to == H8)    { SetCastling (BLACK, KSIDE, false); }
    1895             :         } else {
    1896      735404 :             if (from == A8)  { SetCastling (BLACK, QSIDE, false); }
    1897      735404 :             if (from == H8)  { SetCastling (BLACK, KSIDE, false); }
    1898      735404 :             if (to == A1)    { SetCastling (WHITE, QSIDE, false); }
    1899      735404 :             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    10353839 :     EPTarget = NULL_SQUARE;
    1906    10353839 :     if (ptype == PAWN) {
    1907     1260587 :         rankT fromRank = square_Rank(from);
    1908     1260587 :         rankT toRank = square_Rank(to);
    1909     2521174 :         if (fromRank == RANK_2  &&  toRank == RANK_4
    1910     1382746 :               &&  (Board[square_Move(to,LEFT)] == BP
    1911      118339 :                      ||  Board[square_Move(to,RIGHT)] == BP)) {
    1912        7283 :             EPTarget = square_Move(from, UP);
    1913             :         }
    1914     2521174 :         if (fromRank == RANK_7  &&  toRank == RANK_5
    1915     1359658 :               &&  (Board[square_Move(to,LEFT)] == WP
    1916       94904 :                      ||  Board[square_Move(to,RIGHT)] == WP)) {
    1917        7937 :             EPTarget = square_Move(from, DOWN);
    1918             :         }
    1919     1260587 :         HalfMoveClock = 0; // 50-move clock resets on pawn moves.
    1920             :     }
    1921             : 
    1922    10353839 :     ToMove = enemy;
    1923             : 
    1924             : #ifndef NDEBUG
    1925             :     // Do a SLOW, careful check for corruption:
    1926    10353839 :     if (AssertPos() != OK) {
    1927           0 :         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
    1940     5442837 : Position::UndoSimpleMove (simpleMoveT * m)
    1941             : {
    1942     5442837 :     ASSERT (m != NULL);
    1943     5442837 :     squareT from = m->from;
    1944     5442837 :     squareT to = m->to;
    1945     5442837 :     pieceT p = Board[to];
    1946     5442837 :     EPTarget = m->epSquare;
    1947     5442837 :     Castling = m->castleFlags;
    1948     5442837 :     HalfMoveClock = m->oldHalfMoveClock;
    1949     5442837 :     PlyCounter--;
    1950    10885674 :     ToMove = color_Flip(ToMove);
    1951     5442837 :     m->pieceNum = ListPos[to];
    1952             : 
    1953             :     // Check for a null move:
    1954    10885674 :     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     5442837 :     if (m->capturedPiece != EMPTY) {
    1965      463016 :         colorT c = color_Flip(ToMove);
    1966      463016 :         ListPos[List[c][m->capturedNum]] = Count[c];
    1967      463016 :         ListPos[m->capturedSquare] = m->capturedNum;
    1968      463016 :         List[c][Count[c]] = List[c][m->capturedNum];
    1969      463016 :         List[c][m->capturedNum] = m->capturedSquare;
    1970      463016 :         Material[m->capturedPiece]++;
    1971      463016 :         Count[c]++;
    1972             :     }
    1973             : 
    1974             :     // handle promotion:
    1975             : 
    1976     5442837 :     if (m->promote != EMPTY) {
    1977       34476 :         Material[p]--;
    1978       34476 :         RemoveFromBoard (p, to);
    1979       68952 :         p = piece_Make(ToMove, PAWN);
    1980       34476 :         Material[p]++;
    1981       34476 :         AddToBoard (p, to);
    1982             :     }
    1983             : 
    1984             :     // now make the move:
    1985             : 
    1986     5442837 :     List[ToMove][m->pieceNum] = from;
    1987     5442837 :     ListPos[from] = m->pieceNum;
    1988     5442837 :     RemoveFromBoard (p, to);
    1989     5442837 :     AddToBoard (p, from);
    1990     5442837 :     if (m->capturedPiece != EMPTY) {
    1991      463016 :         AddToBoard (m->capturedPiece, m->capturedSquare);
    1992             :     }
    1993             : 
    1994             :     // handle Castling:
    1995             : 
    1996    12672858 :     if ((piece_Type(p) == KING) && square_Fyle(from) == E_FYLE
    1997     5747690 :             && (square_Fyle(to) == C_FYLE || square_Fyle(to) == G_FYLE)) {
    1998             :         squareT rookfrom, rookto;
    1999        2032 :         pieceT rook = (ToMove == WHITE? WR : BR);
    2000        2032 :         if (square_Fyle(to) == C_FYLE) {
    2001         776 :             rookfrom = to - 2;   rookto = to + 1;
    2002             :         } else {
    2003        1256 :             rookfrom = to + 1;   rookto = to - 1;
    2004             :         }
    2005        2032 :         ListPos[rookfrom] = ListPos[rookto];
    2006        2032 :         List[ToMove][ListPos[rookto]] = rookfrom;
    2007        2032 :         RemoveFromBoard (rook, rookto);
    2008        2032 :         AddToBoard (rook, rookfrom);
    2009             :     }
    2010             : 
    2011             : #ifndef NDEBUG
    2012     5442837 :     if (AssertPos() != OK) {
    2013           0 :         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
    2031           0 : Position::RelocatePiece (squareT fromSq, squareT toSq)
    2032             : {
    2033             :     // Must have on-board squares:
    2034           0 :     if (fromSq == NS ||  toSq == NS) { return ERROR; }
    2035             : 
    2036             :     // If squares are identical, just return success:
    2037           0 :     if (fromSq == toSq) { return OK; }
    2038             : 
    2039           0 :     pieceT piece = Board[fromSq];
    2040           0 :     pieceT ptype = piece_Type(piece);
    2041           0 :     colorT pcolor = piece_Color(piece);
    2042             : 
    2043             :     // Must be relocating a nonempty piece to an empty square:
    2044           0 :     if (piece == EMPTY  ||  Board[toSq] != EMPTY) { return ERROR; }
    2045             : 
    2046             :     // Pawns cannot relocate to the first or last rank:
    2047           0 :     if (ptype == PAWN) {
    2048           0 :         rankT toRank = square_Rank(toSq);
    2049           0 :         if (toRank == RANK_1  ||  toRank == RANK_8) { return ERROR; }
    2050             :     }
    2051             : 
    2052             :     // Locate the piece index in the appropriate list of pieces:
    2053           0 :     uint index = ListPos[fromSq];
    2054           0 :     ASSERT(List[pcolor][index] == fromSq);
    2055             : 
    2056             :     // Relocate the piece:
    2057           0 :     List[pcolor][index] = toSq;
    2058           0 :     ListPos[toSq] = index;
    2059           0 :     RemoveFromBoard (piece, fromSq);
    2060           0 :     AddToBoard (piece, toSq);
    2061             : 
    2062             :     // Check for adjacent kings or side to move giving check:
    2063           0 :     if (! IsLegal()) {
    2064             :         // Undo the relocation and return error:
    2065           0 :         List[pcolor][index] = fromSq;
    2066           0 :         RemoveFromBoard (piece, toSq);
    2067           0 :         AddToBoard (piece, fromSq);
    2068           0 :         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
    2086           0 : Position::MaterialValue (colorT c)
    2087             : {
    2088           0 :     ASSERT (c == WHITE  ||  c == BLACK);
    2089           0 :     uint value = 0;
    2090           0 :     if (c == WHITE) {
    2091           0 :         value += 9 * PieceCount(WQ);
    2092           0 :         value += 5 * PieceCount(WR);
    2093           0 :         value += 3 * PieceCount(WB);
    2094           0 :         value += 3 * PieceCount(WN);
    2095           0 :         value += 1 * PieceCount(WP);
    2096             :     } else {
    2097           0 :         value += 9 * PieceCount(BQ);
    2098           0 :         value += 5 * PieceCount(BR);
    2099           0 :         value += 3 * PieceCount(BB);
    2100           0 :         value += 3 * PieceCount(BN);
    2101           0 :         value += 1 * PieceCount(BP);
    2102             :     }
    2103           0 :     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
    2114     1559242 : Position::MakeSANString (simpleMoveT * m, char * s, sanFlagT flag)
    2115             : {
    2116     1559242 :     ASSERT (m != NULL  &&  s != NULL);
    2117             : 
    2118             :     // Make sure m->pieceNum is updated:
    2119     1559242 :     m->pieceNum = ListPos[m->from];
    2120     3118484 :     pieceT  p    = piece_Type (Board[List[ToMove][m->pieceNum]]);
    2121     1559242 :     squareT from = List[ToMove][m->pieceNum];
    2122     1559242 :     squareT to   = m->to;
    2123     1559242 :     char * c     = s;
    2124             : 
    2125     1559242 :     if (p == PAWN) {
    2126      391842 :         if (square_Fyle(from) != square_Fyle(to)) {  // pawn capture
    2127       65006 :             *c++ = square_FyleChar(from);
    2128       32503 :             *c++ = 'x';
    2129             :         }
    2130      391842 :         *c++ = square_FyleChar(to);
    2131      391842 :         *c++ = square_RankChar(to);
    2132      195921 :         if ((square_Rank(to)==RANK_1) || (square_Rank(to)==RANK_8)) {
    2133        9864 :             *c++ = '=';
    2134       19728 :             *c++ = piece_Char(m->promote);
    2135             :         }
    2136             : 
    2137     1363321 :     } else if (p == KING) {
    2138     1021724 :         if (m->isNullMove()) {
    2139             :             //*c++ = 'n'; *c++ = 'u'; *c++ = 'l'; *c++ = 'l';
    2140           0 :             *c++ = '-'; *c++ = '-';
    2141             :         } else
    2142      597941 :         if ((square_Fyle(from)==E_FYLE) && (square_Fyle(to)==G_FYLE)) {
    2143         371 :             *c++ = 'O'; *c++ = '-'; *c++ = 'O';
    2144             :         } else
    2145      597199 :         if ((square_Fyle(from)==E_FYLE) && (square_Fyle(to)==C_FYLE)) {
    2146         223 :             *c++ = 'O'; *c++ = '-'; *c++ = 'O'; *c++ = '-'; *c++ = 'O';
    2147             :         } else {  // regular King move
    2148      510268 :             *c++ = 'K';
    2149      510268 :             if (Board[to] != EMPTY)  *c++ = 'x';
    2150     1020536 :             *c++ = square_FyleChar(to);
    2151     1020536 :             *c++ = square_RankChar(to);
    2152             :         }
    2153             : 
    2154             :     } else {    // Queen/Rook/Bishop/Knight
    2155     1704918 :         *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      852459 :         if (Material[Board[m->from]] < 2) {
    2161      481724 :             if (Board[to] != EMPTY)  { *c++ = 'x'; }
    2162      963448 :             *c++ = square_FyleChar(to);
    2163      963448 :             *c++ = square_RankChar(to);
    2164             : 
    2165             :         } else {
    2166             :             // disambiguate moves here:
    2167             :             // SHOULD handle 3-way ambiguity!  Looks like it does ok.
    2168      370735 :             bool unique_fyle = true;
    2169      370735 :             bool unique_rank = true;
    2170      370735 :             bool ambiguity = false;
    2171      370735 :             char f = square_FyleChar(from);
    2172      370735 :             char r = square_RankChar(from);
    2173      370735 :             MoveList mlist;
    2174      370735 :             MatchLegalMove (&mlist, p, to);
    2175             : 
    2176      761739 :             for (uint i=0; i < mlist.Size(); i++) {
    2177      391004 :                 simpleMoveT * m2 = mlist.Get(i);
    2178      391004 :                 squareT from2 = m2->from;
    2179      782008 :                 pieceT p2 = piece_Type(Board[from2]);
    2180      391004 :                 if ((to == m2->to) && (from != from2) && (p2 == p)) {
    2181       20269 :                     ambiguity = true;
    2182       20269 :                     if (f == square_FyleChar(from2)) {
    2183        2082 :                         unique_fyle = false;
    2184             :                     }
    2185       20269 :                     if (r == square_RankChar(from2)) {
    2186        4796 :                         unique_rank = false;
    2187             :                     }
    2188             :                 }
    2189             :             }
    2190      370735 :             if (ambiguity) {
    2191       20209 :                 if (!unique_rank || unique_fyle)
    2192       18129 :                     { *c++ = f; }  // print from-fyle
    2193       20209 :                 if (!unique_fyle)
    2194        2082 :                     { *c++ = r; }  // print from-rank
    2195             :             }
    2196      370735 :             if (Board[to] != EMPTY) { *c++ = 'x'; }
    2197      741470 :             *c++ = square_FyleChar (to);
    2198      741470 :             *c++ = square_RankChar (to);
    2199             :         }
    2200             :     }
    2201             : 
    2202             :     // Now do the check or mate symbol:
    2203     1559242 :     if (flag != SAN_NO_CHECKTEST) {
    2204             :         // Now we make the move to test for check:
    2205     1559242 :         DoSimpleMove (m);
    2206     3118484 :         if (CalcNumChecks (GetKingSquare()) > 0) {
    2207       77857 :             char ch = '+';
    2208       77857 :             if (flag == SAN_MATETEST) {
    2209       77857 :                 MoveList mlist;
    2210       77857 :                 GenerateMoves (&mlist);
    2211       77857 :                 if (mlist.Size() == 0) { ch = '#'; }
    2212             :             }
    2213       77857 :             *c++ = ch;
    2214             :         }
    2215     1559242 :         UndoSimpleMove (m);
    2216             :     }
    2217     1559242 :     *c = 0;
    2218     1559242 : }
    2219             : 
    2220             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2221             : // Position::MakeUCIString():
    2222             : //      Make the UCI string for a simpleMove.
    2223             : //
    2224             : void
    2225           0 : Position::MakeUCIString (simpleMoveT * m, char * s)
    2226             : {
    2227           0 :     ASSERT (m != NULL  &&  s != NULL);
    2228             : 
    2229             :     // Make sure m->pieceNum is updated:
    2230           0 :     m->pieceNum = ListPos[m->from];
    2231           0 :     pieceT  p    = piece_Type (Board[List[ToMove][m->pieceNum]]);
    2232           0 :     squareT from = List[ToMove][m->pieceNum];
    2233           0 :     squareT to   = m->to;
    2234             : 
    2235           0 :     char * c     = s;
    2236             : 
    2237           0 :     if (from == to && to != NULL_SQUARE) {
    2238             :       // UCI standard for null move
    2239           0 :         c[0] = '0';
    2240           0 :         c[1] = '0';
    2241           0 :         c[2] = '0';
    2242           0 :         c[3] = '0';
    2243           0 :         c[4] = 0;
    2244           0 :         return;
    2245             :     }
    2246             : 
    2247           0 :     *c++ = square_FyleChar(from);
    2248           0 :     *c++ = square_RankChar(from);
    2249           0 :     *c++ = square_FyleChar(to);
    2250           0 :     *c++ = square_RankChar(to);
    2251           0 :     if (p == PAWN) {
    2252           0 :         if ((square_Rank(to)==RANK_1) || (square_Rank(to)==RANK_8)) {
    2253           0 :             *c++ = piece_Char(m->promote);
    2254             :         }
    2255             :     }
    2256             : 
    2257           0 :     *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           0 : Position::ReadCoordMove (simpleMoveT * m, const char * str, bool reverse)
    2270             : {
    2271           0 :     ASSERT (m != NULL  &&  str != NULL);
    2272             :     fyleT fromFyle, toFyle;
    2273             :     rankT fromRank, toRank;
    2274             :     squareT from, to;
    2275           0 :     pieceT promo = EMPTY;
    2276             : 
    2277           0 :     uint slen = strLength(str);
    2278           0 :     if (slen == 5) {
    2279           0 :         promo = piece_FromChar(toupper(str[4]));
    2280           0 :     } else if (slen != 4) { return ERROR_InvalidMove; }
    2281             : 
    2282           0 :     fromFyle = fyle_FromChar (str[0]);
    2283           0 :     fromRank = rank_FromChar (str[1]);
    2284           0 :     from = square_Make (fromFyle, fromRank);
    2285           0 :     if (from == NS) { return ERROR_InvalidMove; }
    2286             : 
    2287           0 :     toFyle = fyle_FromChar (str[2]);
    2288           0 :     toRank = rank_FromChar (str[3]);
    2289           0 :     to = square_Make (toFyle, toRank);
    2290           0 :     if (to == NS) { return ERROR_InvalidMove; }
    2291             : 
    2292           0 :     MoveList mlist;
    2293           0 :     GenerateMoves(&mlist);
    2294           0 :     for (size_t i = 0, n = mlist.Size(); i < n; i++) {
    2295           0 :         simpleMoveT* sm = mlist.Get(i);
    2296           0 :         if (sm->promote == promo) {
    2297           0 :             if (sm->from == from  &&  sm->to == to) {
    2298           0 :                 *m = *sm;
    2299           0 :                 return OK;
    2300             :             }
    2301           0 :             if (reverse  &&  sm->to == from  &&  sm->from == to) {
    2302           0 :                 *m = *sm;
    2303           0 :                 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     1558627 : Position::ReadMove (simpleMoveT * m, const char * str, tokenT token)
    2318             : {
    2319     1558627 :     ASSERT (m != NULL  &&  str != NULL);
    2320     1558627 :     const char * s = str;
    2321             :     char mStr [255];
    2322             :     pieceT p;
    2323     1558627 :     squareT from = NS;
    2324     1558627 :     squareT to = NS;
    2325             :     rankT frRank, toRank;
    2326             :     fyleT frFyle, toFyle;
    2327             : 
    2328     1558627 :     MoveList mlist;
    2329     1558627 :     mlist.Clear();
    2330             : 
    2331             :     // Check for a null move:
    2332     1558627 :     if (token == TOKEN_Move_Null) {
    2333           0 :         m->pieceNum = 0;
    2334           0 :         m->from = GetKingSquare (ToMove);
    2335           0 :         m->to = m->from;
    2336           0 :         m->movingPiece = Board[m->from];
    2337           0 :         m->promote = EMPTY;
    2338           0 :         return OK;
    2339             :     }
    2340             : 
    2341             :     // Strip out 'x', '-', etc leaving just pieces, files and ranks:
    2342             :     char * s2 = mStr;
    2343             :     uint slen = 0;
    2344    10664381 :     while (!isspace(*s)  &&  *s != '\0') {
    2345     4552877 :         if ((isalpha(*s)  && (*s != 'x'))  ||  isdigit(*s)  ||  *s == '=') {
    2346     4552088 :             *s2 = *s;  s2++;  slen++;
    2347             :         }
    2348     4552877 :         s++;
    2349             :     }
    2350             : 
    2351     1558627 :     if (slen < 2) return ERROR_InvalidMove;
    2352             :     
    2353     1558627 :     *s2 = '\0';
    2354     1558627 :     s = mStr;
    2355             : 
    2356             :     // Pawn moves:
    2357     1558627 :     if (token == TOKEN_Move_Pawn  ||  token == TOKEN_Move_Promote) {
    2358             : 
    2359      195796 :         pieceT promo = EMPTY;
    2360      195796 :         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       19728 :             promo = piece_FromChar(toupper(s[slen-1]));
    2365        9864 :             if (promo != QUEEN  &&  promo != ROOK  &&  promo != KNIGHT
    2366        2532 :                 && promo != BISHOP) {
    2367             :                 return ERROR_InvalidMove;
    2368             :             }
    2369        9864 :             slen--;
    2370        9864 :             if (s[slen-1] == '=') { slen--; }
    2371             : 
    2372             :             // in case of malformed moves
    2373        9864 :             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      185932 :             if (slen >= 4  &&
    2378           0 :                 islower(s[0])  &&  isdigit(s[1])  &&
    2379           0 :                 islower(s[slen-2])  &&  isdigit(s[slen-1])) {
    2380           0 :                 return ReadCoordMove (m, str, false);
    2381             :             }
    2382             :         }
    2383             :         // First char MUST be a fyle:
    2384      195796 :         if (*s < 'a'  ||  *s > 'h')  {  return ERROR_InvalidMove; }
    2385      195796 :         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      195796 :         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           0 :             for (rankT r = RANK_1; r <= RANK_8; r++) {
    2393           0 :                 to = square_Make (toFyle, r);
    2394           0 :                 if (MatchPawnMove (&mlist, frFyle, to, promo) == OK) {
    2395           0 :                     *m = *(mlist.Get(0));
    2396           0 :                     return OK;
    2397             :                 }
    2398             :             }
    2399             :             // It is NOT a valid capture with no rank:
    2400             :             return ERROR_InvalidMove;
    2401             :         }
    2402             : 
    2403      391592 :         toFyle = fyle_FromChar (s[slen-2]);
    2404      391592 :         toRank = rank_FromChar (s[slen-1]);
    2405      391592 :         to = square_Make (toFyle, toRank);
    2406      195796 :         if (to == NS) { return ERROR_InvalidMove; }
    2407             : 
    2408      195796 :         if (MatchPawnMove (&mlist, frFyle, to, promo) != OK) {
    2409             :             return ERROR_InvalidMove;
    2410             :         } else {
    2411      195796 :             *m = *(mlist.Get(0));
    2412      195796 :             return OK;
    2413             :         }
    2414             :     }
    2415             : 
    2416             :     // Here we handle piece moves, including castling
    2417     1362831 :     if (token != TOKEN_Move_Piece) {  // Must be castling move
    2418         578 :         ASSERT (token == TOKEN_Move_Castle_King  ||  token == TOKEN_Move_Castle_Queen);
    2419         578 :         from = (ToMove == WHITE ? E1 : E8);
    2420        1156 :         if (GetKingSquare(ToMove) != from) { return ERROR_InvalidMove; }
    2421         578 :         to = (token == TOKEN_Move_Castle_King ? (from + 2) : (from - 2));
    2422         578 :         if (MatchKingMove (&mlist, to) != OK) {
    2423             :             return ERROR_InvalidMove;
    2424             :         } else {
    2425         578 :             *m = *(mlist.Get(0));
    2426         578 :             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     2724506 :     p = piece_FromChar(*s);
    2434     1362253 :     if (p == EMPTY) { return ERROR_InvalidMove; }
    2435     1362253 :     if (slen < 3  ||  slen > 5) { return ERROR_InvalidMove; }
    2436     2724506 :     toRank = rank_FromChar(s[slen-1]);
    2437     2724506 :     toFyle = fyle_FromChar(s[slen-2]);
    2438     2724506 :     to = square_Make(toFyle, toRank);
    2439     1362253 :     if (to == NS) { return ERROR_InvalidMove; }
    2440     1362253 :     frRank = NO_RANK;
    2441     1362253 :     frFyle = NO_FYLE;
    2442     1362253 :     if (slen > 3) {
    2443             :         // There is some ambiguity information in the input string.
    2444             : 
    2445       60595 :         for (uint i=1; i < slen-2; i++) {  // For each extra char:
    2446       20199 :             if (isdigit(s[i])) {
    2447             :                 frRank = rank_FromChar(s[i]);
    2448       18117 :             } else if (s[i] >= 'a'  &&  s[i] <= 'h') {
    2449       18117 :                 frFyle = fyle_FromChar(s[i]);
    2450             :             }
    2451             :         }
    2452             :     }
    2453             : 
    2454             :     // Calculate the matching legal move(s):
    2455     1362253 :     if (p == KING) {
    2456      510228 :         if (MatchKingMove(&mlist, to) != OK) {
    2457             :             return ERROR_InvalidMove;
    2458             :         } else {
    2459      510228 :             *m = *(mlist.Get(0));
    2460      510228 :             return OK;
    2461             :         }
    2462             :     } else {  // A Queen/Rook/Bishop/Knight move
    2463      852025 :         MatchLegalMove (&mlist, p, to);
    2464             :     }
    2465             : 
    2466             :     uint i;
    2467      852025 :     uint matchCount = 0;
    2468     1724307 :     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      872282 :         simpleMoveT * thisMove = mlist.Get(i);
    2473     1744564 :         if (to == thisMove->to
    2474      908562 :               && (frFyle==NO_FYLE || frFyle == square_Fyle(thisMove->from))
    2475     1730581 :               && (frRank==NO_RANK || frRank == square_Rank(thisMove->from))) {
    2476             :             // We have a match!!
    2477      852025 :             *m = *thisMove;
    2478      852025 :             matchCount++;
    2479             :         }
    2480             :     }
    2481      852025 :     if (matchCount == 1) { return OK; }
    2482             :     // No match, or too many (ambiguous) moves match:
    2483           0 :     return ERROR_InvalidMove;
    2484             : }
    2485             : 
    2486             : 
    2487             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2488             : // Position::ParseMove():
    2489             : //      Parse a single move from SAN-style notation.
    2490             : //
    2491             : errorT
    2492           0 : Position::ParseMove (simpleMoveT * sm, const char * line)
    2493             : {
    2494             :     const char * s;
    2495             :     char * s2;
    2496             :     char mStr [255];
    2497           0 :     uint length = 0;
    2498           0 :     tokenT token = TOKEN_Invalid;
    2499           0 :     errorT err = OK;
    2500             : 
    2501           0 :     s = line;
    2502           0 :     ASSERT (line != NULL);
    2503             : 
    2504             :     // First, strip the move string down to its raw form with no
    2505             :     // 'x' (capture symbols), etc:
    2506             : 
    2507           0 :     while (*s != 0  &&  !isalpha(*s)) { s++; }
    2508           0 :     if (*s == '\0') { return ERROR_InvalidMove; }
    2509             :     s2 = mStr; length = 0;
    2510           0 :     while (!isspace(*s)  &&  *s != '\0') {
    2511           0 :         if ((isalpha(*s)  && (*s != 'x'))  ||  isdigit(*s)  ||  *s == '=') {
    2512           0 :             *s2 = *s;  s2++;  length++;
    2513           0 :             if (length >= 10) { return ERROR_InvalidMove; }
    2514             :         }
    2515           0 :         s++;
    2516             :     }
    2517           0 :     if (length == 0 ||  length > 10) { return ERROR_InvalidMove; }
    2518           0 :     *s2 = '\0';
    2519           0 :     if (mStr[0] == 'O') {
    2520           0 :         if (mStr[1] == 'O'  &&  mStr[2] == 'O' && mStr[3] == 0) {
    2521             :             token = TOKEN_Move_Castle_Queen;
    2522           0 :         } else if (mStr[1] == 'O'  &&  mStr[2] == 0) {
    2523             :             token = TOKEN_Move_Castle_King;
    2524             :         } else { return ERROR_InvalidMove; }
    2525           0 :     } else if (mStr[0] == 'K'  ||  mStr[0] == 'Q'  ||  mStr[0] == 'R'  ||
    2526           0 :                mStr[0] == 'B'  ||  mStr[0] == 'N'  ||  mStr[0] == 'r'  ||
    2527           0 :                mStr[0] == 'k'  ||  mStr[0] == 'q'  ||  mStr[0] == 'n') {
    2528           0 :         mStr[0] = toupper(mStr[0]);
    2529           0 :         token = TOKEN_Move_Piece;
    2530           0 :     } else if (mStr[0] >= 'a'  &&  mStr[0] <= 'h') {
    2531           0 :         token = TOKEN_Move_Pawn;
    2532           0 :         if (!isdigit (mStr[length - 1])) {
    2533           0 :             token = TOKEN_Move_Promote;
    2534             :         }
    2535             :     } else { return ERROR_InvalidMove; }
    2536           0 :     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           0 :     if (err != OK  &&  token == TOKEN_Move_Pawn) {
    2541           0 :         mStr[0] = toupper(mStr[0]);
    2542           0 :         token = TOKEN_Move_Piece;
    2543           0 :          err = ReadMove (sm, mStr, token);
    2544             :     }
    2545           0 :     if (err != OK) { return ERROR_InvalidMove; }
    2546           0 :     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           0 : Position::ReadLine (const char * line)
    2557             : {
    2558           0 :     const char * s = line;
    2559             :     char mStr[255];
    2560             :     char * s2;
    2561           0 :     uint length = 0;
    2562             :     simpleMoveT sm;
    2563           0 :     tokenT token = TOKEN_Invalid;
    2564             :     errorT err;
    2565             : 
    2566             :     while (1) {
    2567           0 :         while (*s != 0  &&  !isalpha(*s)) { s++; }
    2568           0 :         if (*s == '\0') { return OK; }
    2569             :         s2 = mStr; length = 0;
    2570           0 :         while (!isspace(*s)  &&  *s != '\0') {
    2571           0 :             if (isalpha(*s)  ||  isdigit(*s)  ||  *s == '=') {
    2572           0 :                 *s2 = *s;  s2++;  length++;
    2573             :             }
    2574           0 :             s++;
    2575             :         }
    2576           0 :         *s2 = '\0';
    2577           0 :         if (*mStr == 'O') {
    2578           0 :             if (mStr[1] == 'O'  &&  mStr[2] == 'O' && mStr[3] == 0) {
    2579             :                 token = TOKEN_Move_Castle_Queen;
    2580           0 :             } else if (mStr[1] == 'O'  &&  mStr[2] == 0) {
    2581           0 :                 token = TOKEN_Move_Castle_King;
    2582             :             }
    2583           0 :         } else if (*mStr == 'K'  ||  *mStr == 'Q'  ||  *mStr == 'R'  ||
    2584           0 :                    *mStr == 'B'  ||  *mStr == 'N'  ||  *mStr == 'r'  ||
    2585           0 :                    *mStr == 'k'  ||  *mStr == 'q'  ||  *mStr == 'n') {
    2586           0 :             *mStr = toupper(*mStr);
    2587           0 :             token = TOKEN_Move_Piece;
    2588           0 :         } else if (*mStr >= 'a'  &&  *mStr <= 'h') {
    2589           0 :             token = TOKEN_Move_Pawn;
    2590           0 :             if (!isdigit (mStr[length - 1])) {
    2591           0 :                 token = TOKEN_Move_Promote;
    2592             :             }
    2593             :         } else { return ERROR_InvalidMove; }
    2594           0 :         err = ReadMove (&sm, mStr, token);
    2595           0 :         if (err != OK) { return err; }
    2596           0 :         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
    2606           0 : Position::CalcSANStrings (sanListT *sanList, sanFlagT flag)
    2607             : {
    2608           0 :     MoveList mlist;
    2609           0 :     GenerateMoves(&mlist);
    2610           0 :     for (size_t i = 0, n = mlist.Size(); i < n; i++) {
    2611           0 :         MakeSANString(mlist.Get(i), sanList->list[i], flag);
    2612             :     }
    2613           0 :     sanList->num = mlist.Size();
    2614           0 :     sanList->current = true;
    2615           0 : }
    2616             : 
    2617             : errorT
    2618           0 : Position::ReadFromLongStr (const char * str)
    2619             : {
    2620           0 :     pieceT pieceFromByte [256] = {EMPTY};
    2621           0 :     pieceFromByte [(int) 'K'] = WK;  pieceFromByte [(int) 'k'] = BK;
    2622           0 :     pieceFromByte [(int) 'Q'] = WQ;  pieceFromByte [(int) 'q'] = BQ;
    2623           0 :     pieceFromByte [(int) 'R'] = WR;  pieceFromByte [(int) 'r'] = BR;
    2624           0 :     pieceFromByte [(int) 'B'] = WB;  pieceFromByte [(int) 'b'] = BB;
    2625           0 :     pieceFromByte [(int) 'N'] = WN;  pieceFromByte [(int) 'n'] = BN;
    2626           0 :     pieceFromByte [(int) 'P'] = WP;  pieceFromByte [(int) 'p'] = BP;
    2627             : 
    2628           0 :     Clear();
    2629           0 :     for (squareT sq=A1; sq <= H8; sq++) {
    2630           0 :         if (str[sq] == '.') { continue; }
    2631           0 :         pieceT p = pieceFromByte [(byte) str[sq]];
    2632           0 :         if (p == EMPTY) { return ERROR_Corrupt; }
    2633           0 :         if (AddPiece (p,sq) != OK) { return ERROR_Corrupt; }
    2634             :     }
    2635           0 :     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
    2658           0 : Position::MakeLongStr (char * str)
    2659             : {
    2660           0 :     ASSERT (str != NULL);
    2661             :     char * s = str;
    2662           0 :     for (squareT sq = A1; sq <= H8; sq++) {
    2663           0 :         *s++ = PIECE_CHAR[Board[sq]];
    2664             :     }
    2665           0 :     *s++ = ' ';
    2666           0 :     *s++ = (ToMove == WHITE ? 'w' : 'b');
    2667           0 :     *s = 0;
    2668           0 : }
    2669             : 
    2670             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2671             : // Position::DumpBoard():
    2672             : //      Dump the board to an open file.
    2673             : //
    2674             : void
    2675           0 : Position::DumpBoard (FILE * fp)
    2676             : {
    2677           0 :     ASSERT (fp != NULL);
    2678             :     squareT s;
    2679           0 :     for (int i=7; i>=0; i--) {
    2680           0 :         fputs ("   ", fp);
    2681           0 :         for (int j=0; j<8; j++) {
    2682           0 :             s = (i*8) + j;
    2683           0 :             putc (PIECE_CHAR[Board[s]], fp);
    2684           0 :             putc (' ', fp);
    2685             :         }
    2686           0 :         putc ('\n', fp);
    2687             :     }
    2688           0 : }
    2689             : 
    2690             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2691             : // Position::DumpLists():
    2692             : //      Dump the piece lists to an open file.
    2693             : //
    2694             : void
    2695           0 : Position::DumpLists (FILE * fp)
    2696             : {
    2697           0 :     ASSERT (fp != NULL);
    2698             :     uint i;
    2699           0 :     for (colorT c = WHITE; c <= BLACK; c++) {
    2700           0 :         for (i=0; i < Count[c]; i++) {
    2701           0 :             pieceT p = Board[List[c][i]];
    2702           0 :             fprintf (fp, "%2d:", ListPos[List[c][i]]);
    2703           0 :             putc (PIECE_CHAR[p], fp);
    2704           0 :             putc (square_FyleChar (List[c][i]), fp);
    2705           0 :             putc (square_RankChar (List[c][i]), fp);
    2706           0 :             putc (' ', fp);
    2707             :         }
    2708           0 :         putc ('\n', fp);
    2709             :     }
    2710           0 : }
    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
    2724           0 : Position::ReadFromCompactStr (const byte * str)
    2725             : {
    2726           0 :     Clear();
    2727           0 :     for (uint i=0; i < 32; i++) {
    2728           0 :         pieceT p = str[i] >> 4;
    2729           0 :         if (p != EMPTY) {
    2730           0 :             if (AddPiece (p, i * 2) != OK) {
    2731             :                 return ERROR_Corrupt;
    2732             :             }
    2733             :         }
    2734           0 :         p = str[i] & 15;
    2735           0 :         if (p != EMPTY) {
    2736           0 :             if (AddPiece (p, i * 2 + 1) != OK) {
    2737             :                 return ERROR_Corrupt;
    2738             :             }
    2739             :         }
    2740             :     }
    2741           0 :     colorT toMove = str[32] - 1;
    2742           0 :     if (toMove != WHITE  &&  toMove != BLACK) {
    2743             :         return ERROR_Corrupt;
    2744             :     }
    2745           0 :     ToMove = toMove;
    2746           0 :     Castling = str[33] - 1;
    2747           0 :     EPTarget = str[34] - 1;
    2748           0 :     return OK;
    2749             : }
    2750             : 
    2751             : void
    2752           0 : Position::PrintCompactStr (char * cboard)
    2753             : {
    2754           0 :     for (uint i=0; i < 32; i++) {
    2755           0 :         uint i2 = i << 1;
    2756           0 :         cboard[i] = (byte)(Board[i2] << 4) | Board[i2+1];
    2757             :     }
    2758           0 :     cboard[32] = 1 + ToMove;
    2759           0 :     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           0 :     squareT ep = EPTarget;
    2767           0 :     if (ToMove == WHITE) {
    2768           0 :         if (Board[square_Move (ep, DOWN_LEFT)] != WP  &&
    2769           0 :             Board[square_Move (ep, DOWN_RIGHT)] != WP) { ep = NULL_SQUARE; }
    2770             : 
    2771             :     } else {
    2772           0 :         if (Board[square_Move (ep, UP_LEFT)] != BP  &&
    2773           0 :             Board[square_Move (ep, UP_RIGHT)] != BP) { ep = NULL_SQUARE; }
    2774             : 
    2775             :     }
    2776           0 :     cboard[34] = 1 + ep;
    2777           0 :     cboard[35] = 0;
    2778           0 : }
    2779             : 
    2780             : void
    2781           0 : Position::PrintCompactStrFlipped (char * cboard)
    2782             : {
    2783           0 :     for (uint i=0; i < 32; i++) {
    2784           0 :         uint i2 = i << 1;
    2785             :         // Flip 1st rank to 8th, etc:
    2786           0 :         i2 = ((7 - (i2)/8) * 8 + ((i2) % 8));
    2787           0 :         cboard[i] = (byte)(PIECE_FLIP[Board[i2]] << 4) |
    2788           0 :             (byte)(PIECE_FLIP[Board[i2+1]]);
    2789             :     }
    2790           0 :     cboard[32] = 1 + color_Flip(ToMove);
    2791           0 :     cboard[33] = 1 + Castling;
    2792           0 :     cboard[34] = 1 + EPTarget;
    2793           0 :     cboard[35] = 0;
    2794           0 : }
    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        4005 : 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        4005 :     ASSERT (str != NULL);
    2825        4005 :     const char * s = str;
    2826        4005 :     int count = 0;
    2827             : 
    2828        4005 :     if (firstCall) {
    2829           1 :         firstCall = 0;
    2830             : 
    2831             :         // Set up pieceFromByte[]:
    2832           1 :         for (int i=0; i < 256; i++) { pieceFromByte[i] = EMPTY; }
    2833           1 :         pieceFromByte [(int) 'K'] = WK;  pieceFromByte [(int) 'k'] = BK;
    2834           1 :         pieceFromByte [(int) 'Q'] = WQ;  pieceFromByte [(int) 'q'] = BQ;
    2835           1 :         pieceFromByte [(int) 'R'] = WR;  pieceFromByte [(int) 'r'] = BR;
    2836           1 :         pieceFromByte [(int) 'B'] = WB;  pieceFromByte [(int) 'b'] = BB;
    2837           1 :         pieceFromByte [(int) 'N'] = WN;  pieceFromByte [(int) 'n'] = BN;
    2838           1 :         pieceFromByte [(int) 'P'] = WP;  pieceFromByte [(int) 'p'] = BP;
    2839             : 
    2840             :         // Set up fenSqToRealSq[]:
    2841          65 :         for (int sq=0; sq < 64; sq++) {
    2842          64 :             fenSqToRealSquare [sq] = (squareT)((7 - (sq)/8) * 8 + ((sq) % 8));
    2843             :         }
    2844             :     }
    2845             : 
    2846        4005 :     Clear ();
    2847        4005 :     while (count < 64) {
    2848        4005 :         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           0 :             if (count % 8) { return ERROR_InvalidFEN; }
    2853             : 
    2854        4005 :         } else if (*s > '0'  &&  *s < '9') {
    2855           0 :             count += (*s - '0');
    2856             : 
    2857             :         } else {
    2858        4005 :             pieceT p = pieceFromByte [(byte) *s];
    2859        4005 :             if (p == EMPTY) { return ERROR_InvalidFEN; }
    2860           0 :             if (AddPiece (p, fenSqToRealSquare[count]) != OK) {
    2861             :                 return ERROR_InvalidFEN;
    2862             :             }
    2863           0 :             count++;
    2864             :         }
    2865           0 :         s++;
    2866             :     }
    2867           0 :     if (Material[WK] != 1  ||  Material[BK] != 1) { return ERROR_InvalidFEN; }
    2868             : 
    2869             :     // Now the side to move:
    2870           0 :     while (isspace(*s)) { s++; }
    2871           0 :     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           0 :     s++;
    2882             : 
    2883           0 :     if (! IsLegal()) { return ERROR_InvalidFEN; }
    2884             : 
    2885             :     // Now the castling flags:
    2886           0 :     while (isspace(*s)) { s++; }
    2887           0 :     if (*s == '-') {
    2888           0 :         s++;  // do nothing
    2889           0 :     } 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           0 :         if (Board[E1] == WK) {
    2894           0 :             if (Board[A1] == WR) { SetCastling (WHITE, QSIDE, true); }
    2895           0 :             if (Board[H1] == WR) { SetCastling (WHITE, KSIDE, true); }
    2896             :         }
    2897           0 :         if (Board[E8] == BK) {
    2898           0 :             if (Board[A8] == BR) { SetCastling (BLACK, QSIDE, true); }
    2899           0 :             if (Board[H8] == BR) { SetCastling (BLACK, KSIDE, true); }
    2900             :         }
    2901             :     } else {
    2902           0 :         while (!isspace(*s)  &&  *s != 0) {
    2903           0 :             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           0 :             s++;
    2920             :         }
    2921             :     }
    2922             : 
    2923             :     // Now the EP target:
    2924           0 :     while (isspace(*s)) { s++; }
    2925           0 :     if (*s == 0) {
    2926             :         // do nothing
    2927           0 :     } else if (*s == '-') {
    2928           0 :         EPTarget = NULL_SQUARE;
    2929           0 :         s++;  // No EP target
    2930             :     } else {
    2931           0 :         char fylec = *s; s++;
    2932           0 :         if (fylec < 'a'  ||  fylec > 'h') {
    2933             :             return ERROR_InvalidFEN;
    2934             :         }
    2935           0 :         char rankc = *s; s++;
    2936           0 :         if (rankc != '3'  &&  rankc != '6') {
    2937             :             return ERROR_InvalidFEN;
    2938             :         }
    2939           0 :         EPTarget = square_Make(fyle_FromChar(fylec), rank_FromChar(rankc));
    2940             :     }
    2941             : 
    2942             :     // Now the capture/pawn halfmove clock:
    2943           0 :     while (isspace(*s)) { s++; }
    2944           0 :     if (*s) {
    2945           0 :         HalfMoveClock = (ushort) atoi(s);
    2946             :     }
    2947           0 :     while (!isspace(*s)  && *s != 0) { s++; }
    2948             : 
    2949             :     // Finally, the fullmove counter:
    2950           0 :     while (isspace(*s)) { s++; }
    2951           0 :     if (*s) {
    2952           0 :         int i = atoi(s);
    2953           0 :         if (i >= 1) {
    2954           0 :             PlyCounter = (i - 1) * 2;
    2955             :         }
    2956             :     }
    2957           0 :     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        1124 : Position::PrintFEN (char * str, uint flags)
    2976             : {
    2977        1124 :     ASSERT (str != NULL);
    2978             :     uint emptyRun, iRank, iFyle;
    2979       19108 :     for (iRank = 0; iRank < 8; iRank++) {
    2980        8992 :         const pieceT* pBoard = &(Board[(7 - iRank) * 8]);
    2981        8992 :         emptyRun = 0;
    2982        8992 :         if (iRank > 0  &&  flags > FEN_COMPACT) { *str++ = '/'; }
    2983      152864 :         for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
    2984       71936 :             if (*pBoard != EMPTY) {
    2985       26420 :                 if (emptyRun) { *str++ = (byte) emptyRun + '0'; }
    2986       26420 :                 emptyRun = 0;
    2987       26420 :                 *str++ = PIECE_CHAR[*pBoard];
    2988             :             } else {
    2989       45516 :                 emptyRun++;
    2990             :             }
    2991             :         }
    2992        8992 :         if (emptyRun) { *str++ = (byte) emptyRun + '0'; }
    2993             :     }
    2994             : 
    2995        1124 :     if (flags > FEN_COMPACT) { *str++ = ' '; }
    2996        1124 :     *str++ = (ToMove == WHITE ? 'w' : 'b');
    2997        1124 :     *str = 0;
    2998             : 
    2999        1124 :     if (flags >= FEN_CASTLING_EP) {
    3000             :         // Add the castling flags and EP flag as well:
    3001        1124 :         *str++ = ' ';
    3002        1124 :         if (Castling == 0)  {
    3003         154 :             *str++ = '-';
    3004             :         } else {
    3005         970 :             if (GetCastling (WHITE, KSIDE))  { *str++ = 'K'; }
    3006         970 :             if (GetCastling (WHITE, QSIDE))  { *str++ = 'Q'; }
    3007         970 :             if (GetCastling (BLACK, KSIDE))  { *str++ = 'k'; }
    3008         970 :             if (GetCastling (BLACK, QSIDE))  { *str++ = 'q'; }
    3009             :         }
    3010        1124 :         *str++ = ' ';
    3011             : 
    3012             :         // Now the EP target square:
    3013        1124 :         if (EPTarget == NULL_SQUARE) {
    3014        1124 :             *str++ = '-';
    3015             :         } else {
    3016           0 :             *str++ = square_FyleChar (EPTarget);
    3017           0 :             *str++ = square_RankChar (EPTarget);
    3018             :         }
    3019        1124 :         *str = 0;
    3020             : 
    3021        1124 :         if (flags >= FEN_ALL_FIELDS) {
    3022             :             // Also print the Halfmove and ply counters:
    3023        1124 :             *str++ = ' ';
    3024        1124 :             sprintf (str, "%d %d", HalfMoveClock, (PlyCounter / 2) + 1);
    3025             :         }
    3026             :     }
    3027        1124 :     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           0 : Position::DumpHtmlBoard (DString * dstr, uint style, const char * dir, bool flip)
    3052             : {
    3053           0 :     const uint HTML_DIAG_STYLES = 2;
    3054             :     htmlStyleT hs [HTML_DIAG_STYLES];
    3055           0 :     hs[0].dir = "bitmaps"; hs[0].width = 40; hs[0].height = 40;
    3056           0 :     hs[1].dir = "bitmaps2"; hs[1].width = 36; hs[1].height = 35;
    3057           0 :     if (style >= HTML_DIAG_STYLES) { style = 0; }
    3058             : 
    3059           0 :     uint width = hs[style].width;
    3060           0 :     uint height = hs[style].height;
    3061             :     uint iRank, iFyle;
    3062             :     pieceT * pBoard;
    3063           0 :     if (dir == NULL) { dir = hs[style].dir; }
    3064             : 
    3065           0 :     dstr->Append ("<br><br><center>\n");
    3066             :     dstr->Append ("<table Border=1 CellSpacing=0 CellPadding=0>\n");
    3067           0 :     for (iRank = 0; iRank < 8; iRank++) {
    3068           0 :         dstr->Append ("<tr>\n");
    3069           0 :         pBoard = &(Board[(7 - iRank) * 8]);
    3070           0 :         for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
    3071           0 :             pieceT piece = *pBoard;
    3072           0 :             if (flip) { piece = Board[iRank * 8 + (7 - iFyle)]; }
    3073           0 :             dstr->Append ("  <td><img border=0 ");
    3074           0 :             if (width > 0) {
    3075             :                 char temp[40];
    3076           0 :                 sprintf (temp, "width=%u ", width);
    3077           0 :                 dstr->Append (temp);
    3078             :             }
    3079           0 :             if (height > 0) {
    3080             :                 char temp[40];
    3081           0 :                 sprintf (temp, "height=%u ", height);
    3082           0 :                 dstr->Append (temp);
    3083             :             }
    3084           0 :             dstr->Append ("src=\"");
    3085           0 :             dstr->Append (dir);
    3086           0 :             dstr->AddChar ('/');
    3087           0 :             bool lightSq = ((iRank % 2) == (iFyle % 2));
    3088           0 :             if (lightSq) {
    3089             :                 dstr->AddChar ('w');
    3090             :             } else {
    3091             :                 dstr->AddChar ('b');
    3092             :             }
    3093           0 :             if (piece == EMPTY) {
    3094             :                 dstr->Append ("sq.gif");
    3095             :             } else {
    3096           0 :                 colorT c = piece_Color(piece);
    3097           0 :                 dstr->AddChar (c == WHITE ? 'w' : 'b');
    3098           0 :                 dstr->AddChar (tolower (PIECE_CHAR[piece]));
    3099             :                 dstr->Append (".gif");
    3100             :             }
    3101           0 :             dstr->Append ("\" alt=\"");
    3102           0 :             if (piece == EMPTY) {
    3103           0 :                 if (! lightSq) { dstr->Append ("::"); }
    3104             :             } else {
    3105           0 :                 colorT c = piece_Color(piece);
    3106           0 :                 dstr->AddChar (c == WHITE ? 'W' : 'B');
    3107           0 :                 dstr->AddChar (toupper (PIECE_CHAR[piece]));
    3108             :             }
    3109           0 :             dstr->Append ("\"></td>\n");
    3110             :         }
    3111           0 :         dstr->Append ("</tr>\n");
    3112             :     }
    3113           0 :     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           0 :     dstr->Append("</center><br>");
    3120           0 : }
    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
    3127           0 : Position::DumpLatexBoard (DString * dstr, bool flip)
    3128             : {
    3129             :     uint iRank, iFyle;
    3130             :     pieceT * pBoard;
    3131           0 :     dstr->Append ("\\board{");
    3132           0 :     for (iRank = 0; iRank < 8; iRank++) {
    3133           0 :         pBoard = &(Board[(7 - iRank) * 8]);
    3134           0 :         for (iFyle = 0; iFyle < 8; iFyle++, pBoard++) {
    3135           0 :             pieceT piece = *pBoard;
    3136           0 :             if (flip) { piece = Board[iRank * 8 + (7 - iFyle)]; }
    3137           0 :             if (piece != EMPTY) {
    3138           0 :                 dstr->AddChar (PIECE_CHAR[piece]);
    3139             :             } else { // put a space or a '*':
    3140           0 :                 dstr->AddChar (((iRank % 2) == (iFyle % 2)) ? ' ' : '*');
    3141             :             }
    3142             :         }
    3143           0 :         if (iRank < 7) {
    3144             :             dstr->Append ("}\n {");
    3145             :         } else { dstr->AddChar ('}'); }
    3146             :     }
    3147           0 : }
    3148             : 
    3149             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    3150             : // Position::Compare():
    3151             : //      Compare another position with this one.
    3152             : //
    3153             : sint
    3154           0 : Position::Compare (Position * p)
    3155             : {
    3156           0 :     int i = 32;
    3157             :     byte *p1, *p2;
    3158           0 :     p1 = Board;
    3159           0 :     p2 = p->Board;
    3160           0 :     while (i   &&  *p1 == *p2) {
    3161           0 :         i--;  p1++;  p2++;
    3162             :     }
    3163           0 :     if (p1 < p2) { return -1; }
    3164           0 :     if (p1 > p2) { return 1; }
    3165           0 :     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
    3173           0 : Position::GetSquares (pieceT piece, SquareList * sqlist)
    3174             : {
    3175           0 :     colorT color = piece_Color(piece);
    3176           0 :     squareT * squares = GetList(color);
    3177           0 :     uint npieces = GetCount(color);
    3178           0 :     for (uint i=0; i < npieces; i++) {
    3179           0 :         squareT sq = squares[i];
    3180           0 :         pieceT p = Board[sq];
    3181           0 :         if (p == piece) { sqlist->Add (sq); }
    3182             :     }
    3183           0 :     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           0 : randomSquare (void) { return rand() % 64; }
    3192             : 
    3193             : inline squareT
    3194           0 : randomPawnSquare (void) { return (rand() % 48) + A2; }
    3195             : 
    3196             : errorT
    3197           0 : Position::Random (const char * material)
    3198             : {
    3199             :     pieceT pieces [32];         // List of pieces excluding kings
    3200           0 :     uint nPieces[2] = {0, 0};   // Number of pieces per side excluding kings.
    3201           0 :     uint total = 0;             // Total number of pieces excluding kings.
    3202             : 
    3203           0 :     colorT side = WHITE;
    3204             : 
    3205             :     // The material string must start with a king:
    3206           0 :     if (toupper(*material) != 'K') { return ERROR_Corrupt; }
    3207           0 :     material++;
    3208             : 
    3209             :     // Read the material string:
    3210             :     while (1) {
    3211           0 :         char ch = toupper(*material);
    3212           0 :         if (ch == 0) { break; }
    3213             :         switch (ch) {
    3214             :         case 'K':
    3215           0 :             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           0 :             if (nPieces[side] >= 15) { return ERROR_Corrupt; }
    3220           0 :             nPieces[side]++;
    3221           0 :             if (ch == 'P') {
    3222           0 :                 pieces[total] = piece_Make (side, PAWN);
    3223             :             } else {
    3224           0 :                 pieces[total] = piece_Make (side, piece_FromChar(ch));
    3225             :             }
    3226           0 :             total++;
    3227           0 :             break;
    3228             :         case ' ':  case '-':  case '.':  case ',':  case ':':
    3229             :             // Ignore spaces, commas, etc:
    3230             :             break;
    3231             :         default:
    3232             :             return ERROR_Corrupt;
    3233             :         }
    3234           0 :         material++;
    3235           0 :     }
    3236           0 :     if (side != BLACK) { return ERROR_Corrupt; }  // Never saw Black king!
    3237             : 
    3238             :     // Generate two non-adjacent king squares:
    3239           0 :     squareT wk = randomSquare();
    3240           0 :     squareT bk = randomSquare();
    3241           0 :     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           0 :         Clear();
    3247           0 :         ToMove = (rand() % 2) ? WHITE : BLACK;
    3248           0 :         AddPiece (WK, wk);
    3249           0 :         AddPiece (BK, bk);
    3250             : 
    3251           0 :         for (uint i=0; i < total; i++) {
    3252             :             squareT sq;
    3253           0 :             pieceT p = pieces[i];
    3254           0 :             bool isPawn = (piece_Type(p) == PAWN);
    3255             :             while (1) {
    3256           0 :                 sq = isPawn ? randomPawnSquare() : randomSquare();
    3257           0 :                 if (Board[sq] == EMPTY) { break; }
    3258             :             }
    3259             :             // Add this piece on the random empty square:
    3260           0 :             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           0 :         squareT enemyKing = (ToMove == WHITE) ? bk : wk;
    3266           0 :         if (CalcAttacks (ToMove, enemyKing, NULL) == 0) { break; }
    3267             :     }
    3268             :     return OK;
    3269             : }
    3270             : 
    3271             : //////////////////////////////////////////////////////////////////////
    3272             : //  EOF: position.cpp
    3273             : //////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.12