LCOV - code coverage report
Current view: top level - src - position.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1146 1704 67.3 %
Date: 2019-01-29 11:06:41 Functions: 45 70 64.3 %

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

Generated by: LCOV version 1.13