From 211b194243de81ed013566a30ef754018586c4e1 Mon Sep 17 00:00:00 2001
From: H.G.Muller <hgm@hgm-xboard.(none)>
Date: Wed, 24 Sep 2014 17:02:37 +0200
Subject: [PATCH] Improve virginity test for engine-defined pieces

Two squares in the board are now reserved for flags that indicate
whether back-rank pieces have been touched. This allows MovesFromString()
to accurately test virginity of these pieces, rather than having to assume
it when the piece matches that in the opening position. For other ranks
the latter test is still used, as these are normally (irreversible) Pawns,
which cannot return there (and in drop games, when they would, would again
be considered virgin enough for the purpose of double-pushing!).
---
 backend.c |    8 +++++++-
 common.h  |    2 ++
 moves.c   |    4 +++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/backend.c b/backend.c
index 758b71a..749bac9 100644
--- a/backend.c
+++ b/backend.c
@@ -6028,9 +6028,10 @@ InitPosition (int redraw)
     gameInfo.boardHeight   = 8;
     gameInfo.holdingsSize  = 0;
     nrCastlingRights = -1; /* [HGM] Kludge to indicate default should be used */
-    for(i=0; i<BOARD_FILES-2; i++)
+    for(i=0; i<BOARD_FILES-6; i++)
       initialPosition[CASTLING][i] = initialRights[i] = NoRights; /* but no rights yet */
     initialPosition[EP_STATUS] = EP_NONE;
+    initialPosition[TOUCHED_W] = initialPosition[TOUCHED_B] = 0;
     SetCharTable(pieceToChar, "PNBRQ...........Kpnbrq...........k");
     if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant
          SetCharTable(pieceNickName, appData.pieceNickNames);
@@ -9941,6 +9942,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
 	   }
        }
 
+       if(fromY == 0) board[TOUCHED_W] |= 1<<fromX; else // new way to keep track of virginity
+       if(fromY == BOARD_HEIGHT-1) board[TOUCHED_B] |= 1<<fromX;
+       if(toY == 0) board[TOUCHED_W] |= 1<<toX; else
+       if(toY == BOARD_HEIGHT-1) board[TOUCHED_B] |= 1<<toX;
+
        for(i=0; i<nrCastlingRights; i++) {
            if(board[CASTLING][i] == fromX && castlingRank[i] == fromY ||
               board[CASTLING][i] == toX   && castlingRank[i] == toY
diff --git a/common.h b/common.h
index 86a9c5c..cb1278f 100644
--- a/common.h
+++ b/common.h
@@ -180,6 +180,8 @@ typedef char *String;
 #define BOARD_RGHT   (gameInfo.boardWidth + gameInfo.holdingsWidth)
 #define CASTLING     (BOARD_RANKS-1)           /* [HGM] hide in upper rank   */
 #define VIRGIN       (BOARD_RANKS-2)           /* [HGM] pieces not moved     */
+#define TOUCHED_W    CASTLING][(BOARD_FILES-6) /* [HGM] in upper rank        */
+#define TOUCHED_B    CASTLING][(BOARD_FILES-5) /* [HGM] in upper rank        */
 #define EP_RANK      CASTLING][(BOARD_FILES-4) /* [HGM] in upper rank        */
 #define EP_FILE      CASTLING][(BOARD_FILES-3) /* [HGM] in upper rank        */
 #define EP_STATUS    CASTLING][(BOARD_FILES-2) /* [HGM] in upper rank        */
diff --git a/moves.c b/moves.c
index 054ee6b..4831046 100644
--- a/moves.c
+++ b/moves.c
@@ -257,7 +257,9 @@ MovesFromString (Board board, int flags, int f, int r, char *desc, MoveCallback
 	if(isdigit(*++p)) expo = atoi(p++);           // read exponent
 	if(expo > 9) p++;                             // allow double-digit
 	desc = p;                                     // this is start of next move
-	if(initial && board[r][f] != initialPosition[r][f]) continue;
+	if(initial && (board[r][f] != initialPosition[r][f] ||
+		       r == 0              && board[TOUCHED_W] & 1<<f ||
+		       r == BOARD_HEIGHT-1 && board[TOUCHED_B] & 1<<f   ) ) continue;
 	if(expo > 1 && dx == 0 && dy == 0) {          // castling indicated by O + number
 	    mode |= 16; dy = 1;
 	}
-- 
1.7.0.4