Implement variant seirawan
authorH.G. Muller <h.g.muller@hccnet.nl>
Sat, 13 Nov 2010 17:56:15 +0000 (18:56 +0100)
committerArun Persaud <arun@nubati.net>
Sun, 14 Nov 2010 05:09:04 +0000 (21:09 -0800)
Set upthe position, including Hawk and Elephant in holdings, in
InitPostion(). Suppress putting captured pieces in holding. Let
promoChar indicate gating in ApplyMove(). Remove gated pieces from
the holdings there. Let GenLegal() generate RxK-type castlings to act as
base for gating on Rook square. Gatings are tested for legality
based on the holdings content and whether they occur on the back
rank. Disambiguate() also tests this. Make sure the gated pieces are
printed as move suffixes in CoordsToAlgebraic().

backend.c
moves.c

index ba658ea..05f7dfc 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -5349,12 +5349,12 @@ InitPosition(redraw)
     if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant
          SetCharTable(pieceNickName, appData.pieceNickNames);
     else SetCharTable(pieceNickName, "............");
     if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant
          SetCharTable(pieceNickName, appData.pieceNickNames);
     else SetCharTable(pieceNickName, "............");
+    pieces = FIDEArray;
 
     switch (gameInfo.variant) {
     case VariantFischeRandom:
       shuffleOpenings = TRUE;
     default:
 
     switch (gameInfo.variant) {
     case VariantFischeRandom:
       shuffleOpenings = TRUE;
     default:
-      pieces = FIDEArray;
       break;
     case VariantShatranj:
       pieces = ShatranjArray;
       break;
     case VariantShatranj:
       pieces = ShatranjArray;
@@ -5382,6 +5382,10 @@ InitPosition(redraw)
       gameInfo.boardWidth = 10;
       SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
       break;
       gameInfo.boardWidth = 10;
       SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
       break;
+    case VariantSChess:
+      SetCharTable(pieceToChar, "PNBRQ..HEKpnbrq..hek");
+      gameInfo.holdingsSize = 7;
+      break;
     case VariantJanus:
       pieces = JanusArray;
       gameInfo.boardWidth = 10;
     case VariantJanus:
       pieces = JanusArray;
       gameInfo.boardWidth = 10;
@@ -5538,6 +5542,14 @@ InitPosition(redraw)
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan;
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9;
      }
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan;
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9;
      }
+     if( gameInfo.variant == VariantSChess ) {
+      initialPosition[1][0] = BlackMarshall;
+      initialPosition[2][0] = BlackAngel;
+      initialPosition[6][BOARD_WIDTH-1] = WhiteMarshall;
+      initialPosition[5][BOARD_WIDTH-1] = WhiteAngel;
+      initialPosition[1][1] = initialPosition[2][1] = 
+      initialPosition[6][BOARD_WIDTH-2] = initialPosition[5][BOARD_WIDTH-2] = 1;
+     }
   if (appData.debugMode) {
     fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);
   }
   if (appData.debugMode) {
     fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);
   }
@@ -8433,21 +8445,21 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
          king += (int) WhiteUnicorn - (int) WhiteKing;
 
     /* Code added by Tord: */
          king += (int) WhiteUnicorn - (int) WhiteKing;
 
     /* Code added by Tord: */
-    /* FRC castling assumed when king captures friendly rook. */
-    if (board[fromY][fromX] == WhiteKing &&
-            board[toY][toX] == WhiteRook) {
+    /* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */
+    if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook ||
+        board[fromY][fromX] == WhiteRook && board[toY][toX] == WhiteKing) {
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
-      if(toX > fromX) {
+      if((toX > fromX) != (piece == WhiteRook)) {
         board[0][BOARD_RGHT-2] = WhiteKing; board[0][BOARD_RGHT-3] = WhiteRook;
       } else {
         board[0][BOARD_LEFT+2] = WhiteKing; board[0][BOARD_LEFT+3] = WhiteRook;
       }
         board[0][BOARD_RGHT-2] = WhiteKing; board[0][BOARD_RGHT-3] = WhiteRook;
       } else {
         board[0][BOARD_LEFT+2] = WhiteKing; board[0][BOARD_LEFT+3] = WhiteRook;
       }
-    } else if (board[fromY][fromX] == BlackKing &&
-              board[toY][toX] == BlackRook) {
+    } else if (board[fromY][fromX] == BlackKing && board[toY][toX] == BlackRook ||
+               board[fromY][fromX] == BlackRook && board[toY][toX] == BlackKing) {
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
-      if(toX > fromX) {
+      if((toX > fromX) != (piece == BlackRook)) {
         board[BOARD_HEIGHT-1][BOARD_RGHT-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_RGHT-3] = BlackRook;
       } else {
         board[BOARD_HEIGHT-1][BOARD_LEFT+2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_LEFT+3] = BlackRook;
         board[BOARD_HEIGHT-1][BOARD_RGHT-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_RGHT-3] = BlackRook;
       } else {
         board[BOARD_HEIGHT-1][BOARD_LEFT+2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_LEFT+3] = BlackRook;
@@ -8580,10 +8592,11 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
       /* [HGM] OK, so I have written it. Holdings are stored in the */
       /* penultimate board files, so they are automaticlly stored   */
       /* in the game history.                                       */
       /* [HGM] OK, so I have written it. Holdings are stored in the */
       /* penultimate board files, so they are automaticlly stored   */
       /* in the game history.                                       */
-      if (fromY == DROP_RANK) {
+      if (fromY == DROP_RANK || gameInfo.variant == VariantSChess
+                                && promoChar && piece != WhitePawn && piece != BlackPawn) {
         /* Delete from holdings, by decreasing count */
         /* and erasing image if necessary            */
         /* Delete from holdings, by decreasing count */
         /* and erasing image if necessary            */
-        p = (int) fromX;
+        p = fromY == DROP_RANK ? (int) fromX : CharToPiece(piece > BlackPawn ? ToLower(promoChar) : ToUpper(promoChar));
         if(p < (int) BlackPawn) { /* white drop */
              p -= (int)WhitePawn;
                 p = PieceToNumber((ChessSquare)p);
         if(p < (int) BlackPawn) { /* white drop */
              p -= (int)WhitePawn;
                 p = PieceToNumber((ChessSquare)p);
@@ -8603,7 +8616,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
         }
       }
       if (captured != EmptySquare && gameInfo.holdingsSize > 0
         }
       }
       if (captured != EmptySquare && gameInfo.holdingsSize > 0
-          && gameInfo.variant != VariantBughouse        ) {
+          && gameInfo.variant != VariantBughouse && gameInfo.variant != VariantSChess        ) {
         /* [HGM] holdings: Add to holdings, if holdings exist */
        if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
                // [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip
         /* [HGM] holdings: Add to holdings, if holdings exist */
        if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
                // [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip
@@ -8647,6 +8660,9 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
        board[toY][toX] = EmptySquare;
       }
     }
        board[toY][toX] = EmptySquare;
       }
     }
+    if(gameInfo.variant == VariantSChess && promoChar != NULLCHAR && promoChar != '=' && piece != WhitePawn && piece != BlackPawn) {
+        board[fromY][fromX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); // S-Chess gating
+    } else
     if(promoChar == '+') {
         /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite orinary Pawn promotion) */
         board[toY][toX] = (ChessSquare) (PROMOTED piece);
     if(promoChar == '+') {
         /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite orinary Pawn promotion) */
         board[toY][toX] = (ChessSquare) (PROMOTED piece);
diff --git a/moves.c b/moves.c
index 0b0bba5..331840e 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -727,7 +727,7 @@ int GenLegal(board, flags, callback, closure)
      VOIDSTAR closure;
 {
     GenLegalClosure cl;
      VOIDSTAR closure;
 {
     GenLegalClosure cl;
-    int ff, ft, k, left, right;
+    int ff, ft, k, left, right, swap;
     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
     ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING];
 
     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
     ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING];
 
@@ -824,10 +824,11 @@ int GenLegal(board, flags, callback, closure)
        }
     }
 
        }
     }
 
-  if(flags & F_FRC_TYPE_CASTLING) {
+  if((swap = gameInfo.variant == VariantSChess) || flags & F_FRC_TYPE_CASTLING) {
 
     /* generate all potential FRC castling moves (KxR), ignoring flags */
     /* [HGM] test if the Rooks we find have castling rights */
 
     /* generate all potential FRC castling moves (KxR), ignoring flags */
     /* [HGM] test if the Rooks we find have castling rights */
+    /* In S-Chess we generate RxK for allowed castlings, for gating at Rook square */
 
 
     if ((flags & F_WHITE_ON_MOVE) != 0) {
 
 
     if ((flags & F_WHITE_ON_MOVE) != 0) {
@@ -846,7 +847,7 @@ int GenLegal(board, flags, callback, closure)
             for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[0][ft] == WhiteRook)
             for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[0][ft] == WhiteRook)
-                callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
+                callback(board, flags, WhiteHSideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
 
             ft = castlingRights[1]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
 
             ft = castlingRights[1]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
@@ -858,7 +859,7 @@ int GenLegal(board, flags, callback, closure)
             for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[0][ft] == WhiteRook)
             for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[0][ft] == WhiteRook)
-                callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
+                callback(board, flags, WhiteASideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
         }
     } else {
         ff = castlingRights[5]; /* King file if we have any rights */
         }
     } else {
         ff = castlingRights[5]; /* King file if we have any rights */
@@ -872,7 +873,7 @@ int GenLegal(board, flags, callback, closure)
             for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
             for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
-                callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+                callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : ft, closure);
 
             ft = castlingRights[4]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
 
             ft = castlingRights[4]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
@@ -884,7 +885,7 @@ int GenLegal(board, flags, callback, closure)
             for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
             for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
             if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
-                callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+                callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : ft, closure);
         }
     }
 
         }
     }
 
@@ -1078,6 +1079,15 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
        return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
 
     if(promoChar == 'x') promoChar = NULLCHAR; // [HGM] is this ever the case?
        return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
 
     if(promoChar == 'x') promoChar = NULLCHAR; // [HGM] is this ever the case?
+    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[PieceToNumber(CharToPiece(ToUpper(promoChar)))][BOARD_WIDTH-2] == 0) return ImpossibleMove;// must be in stock
+        } else {
+            if(rf != BOARD_HEIGHT-1) return IllegalMove;
+            if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
+        }
+    } else
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. '=' means defer */
         if(rf != DROP_RANK && cl.kind == NormalMove) {
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. '=' means defer */
         if(rf != DROP_RANK && cl.kind == NormalMove) {
@@ -1277,6 +1287,15 @@ void Disambiguate(board, flags, closure)
     }
 
     if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
     }
 
     if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
+    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[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[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
+        }
+    } else
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */
         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */
         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
@@ -1484,9 +1503,9 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
             ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
              (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
             if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
             ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
              (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
             if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
-             safeStrCpy(out, "O-O", MOVE_LEN);
+             snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
             else
             else
-             safeStrCpy(out, "O-O-O", MOVE_LEN);
+             snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
 
            /* This notation is always unambiguous, unless there are
               kings on both the d and e files, with "wild castling"
 
            /* This notation is always unambiguous, unless there are
               kings on both the d and e files, with "wild castling"
@@ -1553,6 +1572,10 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
             /* [HGM] in Shogi non-pawns can promote */
             *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
         }
             /* [HGM] in Shogi non-pawns can promote */
             *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
         }
+        else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating
+            *outp++ = '/';
+            *outp++ = ToUpper(promoChar);
+        }
        *outp = NULLCHAR;
         return cl.kind;
        
        *outp = NULLCHAR;
         return cl.kind;