Keep track of virginity of back-rank pieces in variant seirawan
authorH.G. Muller <h.g.muller@hccnet.nl>
Mon, 23 Apr 2012 12:12:10 +0000 (14:12 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Mon, 23 Apr 2012 12:12:10 +0000 (14:12 +0200)
The forelast rank of the Board array is now used in VariantSChess to
contain flags that indicate virginity of the back-rank pieces, one bit
for white, the other for black. Legality checking of gatings now makes
use of this info. FENs mention all virgin pieces not implied by castling
rights in the castling field, by printing the corresponding file IDs,
as long as holdings are non-empty. The FEN reader now also understands
this format. EditPositionDone fakes virginity for all pieces that are
on their starting square.

backend.c
common.h
moves.c

index 20e5efc..c346231 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -5866,6 +5866,7 @@ InitPosition (int redraw)
     case VariantSChess:
       SetCharTable(pieceToChar, "PNBRQ..HEKpnbrq..hek");
       gameInfo.holdingsSize = 7;
+      for(i=0; i<BOARD_FILES; i++) initialPosition[VIRGIN][i] = VIRGIN_W | VIRGIN_B;
       break;
     case VariantJanus:
       pieces = JanusArray;
@@ -9314,6 +9315,13 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
              ) board[CASTLING][i] = NoRights; // revoke for moved or captured piece
        }
 
+       if(gameInfo.variant == VariantSChess) { // update virginity
+          if(fromY == 0)              board[VIRGIN][fromX] &= ~VIRGIN_W; // loss by moving
+          if(fromY == BOARD_HEIGHT-1) board[VIRGIN][fromX] &= ~VIRGIN_B;
+          if(toY == 0)                board[VIRGIN][toX]   &= ~VIRGIN_W; // loss by capture
+          if(toY == BOARD_HEIGHT-1)   board[VIRGIN][toX]   &= ~VIRGIN_B;
+       }
+
      if (fromX == toX && fromY == toY) return;
 
      piece = board[fromY][fromX]; /* [HGM] remember, for Shogi promotion */
@@ -13931,14 +13939,22 @@ EditPositionDone (Boolean fakeRights)
     if(fakeRights) { // [HGM] suppress this if we just pasted a FEN.
       boards[0][EP_STATUS] = EP_NONE;
       boards[0][CASTLING][2] = boards[0][CASTLING][5] = BOARD_WIDTH>>1;
-    if(boards[0][0][BOARD_WIDTH>>1] == king) {
+      if(boards[0][0][BOARD_WIDTH>>1] == king) {
        boards[0][CASTLING][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? BOARD_LEFT : NoRights;
        boards[0][CASTLING][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : NoRights;
       } else boards[0][CASTLING][2] = NoRights;
-    if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) {
+      if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) {
        boards[0][CASTLING][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? BOARD_LEFT : NoRights;
        boards[0][CASTLING][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : NoRights;
       } else boards[0][CASTLING][5] = NoRights;
+      if(gameInfo.variant = VariantSChess) {
+       int i;
+       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // pieces in their original position are assumed virgin
+         boards[0][VIRGIN][i] = 0;
+         if(boards[0][0][i]              == FIDEArray[0][i-BOARD_LEFT]) boards[0][VIRGIN][i] |= VIRGIN_W;
+         if(boards[0][BOARD_HEIGHT-1][i] == FIDEArray[1][i-BOARD_LEFT]) boards[0][VIRGIN][i] |= VIRGIN_B;
+       }
+      }
     }
     SendToProgram("force\n", &first);
     if (blackPlaysFirst) {
@@ -16659,14 +16675,30 @@ PositionToFEN (int move, char *overrideCastling)
 
         /* [HGM] write true castling rights */
         if( nrCastlingRights == 6 ) {
+            int q, k=0;
             if(boards[move][CASTLING][0] == BOARD_RGHT-1 &&
-               boards[move][CASTLING][2] != NoRights  ) *p++ = 'K';
-            if(boards[move][CASTLING][1] == BOARD_LEFT &&
-               boards[move][CASTLING][2] != NoRights  ) *p++ = 'Q';
+               boards[move][CASTLING][2] != NoRights  ) k = 1, *p++ = 'K';
+            q = (boards[move][CASTLING][1] == BOARD_LEFT &&
+                 boards[move][CASTLING][2] != NoRights  );
+            if(gameInfo.variant = VariantSChess) { // for S-Chess, indicate all vrgin backrank pieces
+               for(i=j=0; i<BOARD_HEIGHT; i++) j += boards[move][i][BOARD_RGHT]; // count white held pieces
+                for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--)
+                    if((boards[move][0][i] != WhiteKing || k+q == 0) &&
+                        boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a';
+            }
+           if(q) *p++ = 'Q';
+            k = 0;
             if(boards[move][CASTLING][3] == BOARD_RGHT-1 &&
-               boards[move][CASTLING][5] != NoRights  ) *p++ = 'k';
-            if(boards[move][CASTLING][4] == BOARD_LEFT &&
-               boards[move][CASTLING][5] != NoRights  ) *p++ = 'q';
+               boards[move][CASTLING][5] != NoRights  ) k = 1, *p++ = 'k';
+            q = (boards[move][CASTLING][4] == BOARD_LEFT &&
+                 boards[move][CASTLING][5] != NoRights  );
+            if(gameInfo.variant = VariantSChess) {
+               for(i=j=0; i<BOARD_HEIGHT; i++) j += boards[move][i][BOARD_LEFT-1]; // count black held pieces
+                for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--)
+                    if((boards[move][BOARD_HEIGHT-1][i] != BlackKing || k+q == 0) &&
+                        boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA;
+            }
+            if(q) *p++ = 'q';
         }
      }
      if (q == p) *p++ = '-'; /* No castling rights */
@@ -16732,7 +16764,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
 {
     int i, j;
     char *p, c;
-    int emptycount;
+    int emptycount, virgin[BOARD_FILES];
     ChessSquare piece;
 
     p = fen;
@@ -16861,14 +16893,15 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
 
     while(*p==' ') p++;
     if(nrCastlingRights) {
-      if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {
+      if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) virgin[i] = 0;
+      if(*p >= 'A' && *p <= 'Z' || *p >= 'a' && *p <= 'z' || *p=='-') {
           /* castling indicator present, so default becomes no castlings */
           for(i=0; i<nrCastlingRights; i++ ) {
                  board[CASTLING][i] = NoRights;
           }
       }
       while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-' ||
-             (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&
+             (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess) &&
              ( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||
              ( *p >= 'A' && *p < 'A' + gameInfo.boardWidth)   ) {
         int c = *p++, whiteKingFile=NoRights, blackKingFile=NoRights;
@@ -16888,25 +16921,34 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
               for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--);
               board[CASTLING][0] = i != whiteKingFile ? i : NoRights;
               board[CASTLING][2] = whiteKingFile;
+             if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W;
+             if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
               break;
           case'Q':
               for(i=BOARD_LEFT;  i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
               board[CASTLING][1] = i != whiteKingFile ? i : NoRights;
               board[CASTLING][2] = whiteKingFile;
+             if(board[CASTLING][1] != NoRights) virgin[board[CASTLING][1]] |= VIRGIN_W;
+             if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
               break;
           case'k':
               for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--);
               board[CASTLING][3] = i != blackKingFile ? i : NoRights;
               board[CASTLING][5] = blackKingFile;
+             if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B;
+             if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
               break;
           case'q':
               for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
               board[CASTLING][4] = i != blackKingFile ? i : NoRights;
               board[CASTLING][5] = blackKingFile;
+             if(board[CASTLING][4] != NoRights) virgin[board[CASTLING][4]] |= VIRGIN_B;
+             if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
           case '-':
               break;
           default: /* FRC castlings */
               if(c >= 'a') { /* black rights */
+                 if(gameInfo.variant == VariantSChess) { virgin[c-AAA] |= VIRGIN_B; break; } // in S-Chess castlings are always kq, so just virginity
                   for(i=BOARD_LEFT; i<BOARD_RGHT; i++)
                     if(board[BOARD_HEIGHT-1][i] == BlackKing) break;
                   if(i == BOARD_RGHT) break;
@@ -16919,6 +16961,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
                   else
                       board[CASTLING][4] = c;
               } else { /* white rights */
+                 if(gameInfo.variant == VariantSChess) { virgin[c-AAA-'A'+'a'] |= VIRGIN_W; break; } // in S-Chess castlings are always KQ
                   for(i=BOARD_LEFT; i<BOARD_RGHT; i++)
                     if(board[0][i] == WhiteKing) break;
                   if(i == BOARD_RGHT) break;
@@ -16934,6 +16977,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
       }
       for(i=0; i<nrCastlingRights; i++)
         if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
+      if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = virgin[i];
     if (appData.debugMode) {
         fprintf(debugFP, "FEN castling rights:");
         for(i=0; i<nrCastlingRights; i++)
index 09be05a..c657ef7 100644 (file)
--- a/common.h
+++ b/common.h
@@ -132,10 +132,13 @@ int pclose(FILE *);
 #define BOARD_LEFT   (gameInfo.holdingsWidth)  /* [HGM] play-board edges     */
 #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 EP_STATUS    CASTLING][(BOARD_FILES-2) /* [HGM] in upper rank        */
 #define HOLDINGS_SET CASTLING][(BOARD_FILES-1) /* [HGM] in upper-right corner*/
 #define ONE          ('1'-(BOARD_HEIGHT>9))    /* [HGM] foremost board rank  */
 #define AAA          ('a'-BOARD_LEFT)          /* [HGM] leftmost board file  */
+#define VIRGIN_W                 1             /* [HGM] flags in Board[VIRGIN][X] */
+#define VIRGIN_B                 2
 #define DROP_RANK               -3
 #define MAX_MOVES              1000
 #define MSG_SIZ                        512
diff --git a/moves.c b/moves.c
index a458a84..5f4b3f9 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -146,7 +146,8 @@ CopyBoard (Board to, Board from)
     for (i = 0; i < BOARD_HEIGHT; i++)
       for (j = 0; j < BOARD_WIDTH; j++)
        to[i][j] = from[i][j];
-    for (j = 0; j < BOARD_FILES-1; j++) // [HGM] gamestate: copy castling rights and ep status
+    for (j = 0; j < BOARD_FILES; j++) // [HGM] gamestate: copy castling rights and ep status
+       to[VIRGIN][j] = from[VIRGIN][j],
        to[CASTLING][j] = from[CASTLING][j];
     to[HOLDINGS_SET] = 0; // flag used in ICS play
 }
@@ -1127,9 +1128,11 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC
     if(gameInfo.variant == VariantSChess && promoChar && promoChar != '=' && board[rf][ff] != WhitePawn && board[rf][ff] != BlackPawn) {
         if(board[rf][ff] < BlackPawn) { // white
             if(rf != 0) return IllegalMove; // must be on back rank
+            if(!(board[VIRGIN][ff] & VIRGIN_W)) return IllegalMove; // non-virgin
             if(board[PieceToNumber(CharToPiece(ToUpper(promoChar)))][BOARD_WIDTH-2] == 0) return ImpossibleMove;// must be in stock
         } else {
             if(rf != BOARD_HEIGHT-1) return IllegalMove;
+            if(!(board[VIRGIN][ff] & VIRGIN_B)) return IllegalMove; // non-virgin
             if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
         }
     } else
@@ -1356,9 +1359,11 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
     if(gameInfo.variant == VariantSChess && c && c != '=' && closure->piece != WhitePawn && closure->piece != BlackPawn) {
         if(closure->piece < BlackPawn) { // white
             if(closure->rf != 0) closure->kind = IllegalMove; // must be on back rank
+            if(!(board[VIRGIN][closure->ff] & VIRGIN_W)) closure->kind = IllegalMove; // non-virgin
             if(board[PieceToNumber(CharToPiece(ToUpper(c)))][BOARD_WIDTH-2] == 0) closure->kind = ImpossibleMove;// must be in stock
         } else {
             if(closure->rf != BOARD_HEIGHT-1) closure->kind = IllegalMove;
+            if(!(board[VIRGIN][closure->ff] & VIRGIN_B)) closure->kind = IllegalMove; // non-virgin
             if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
         }
     } else