Fix takeback of S-Chess gatings
[capablanca.git] / lasker-2.2.3 / src / movecheck.c
index a2cb8c9..d575915 100644 (file)
@@ -1665,6 +1665,28 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom
     // non-promotion can still be an option for deeper promotion zones
     mt->piecePromotionTo = promote ? (promote | stm) : NOPIECE;
     if(promote && gs->promoType == 2 && !gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified
+    if(promote == KNIGHT && gs->royalKnight) return MOVE_ILLEGAL; // Knight not allowed in Knightmate
+    if(gs->promoType != 2 && promote > QUEEN) { // for promoType != 2 we must check explicitly if the requested pieceis compatible with the variant
+       switch(promote) {
+         case HAWK:
+         case SELEPHANT:
+           if(gs->drops != 2) return MOVE_ILLEGAL; // allowed only in S-Chess
+           break;
+         case MARSHALL:
+         case CARDINAL:
+           if(!gs->capablancaPieces) return MOVE_ILLEGAL; // allowed when flagged so
+           break;
+         case FERZ:
+         case FERZ2:
+           if(!gs->pawnDblStep) return MOVE_ILLEGAL; // allowed in Shatranj and Courier
+           break;
+         case MAN2:
+           if(!gs->royalKnight) return MOVE_ILLEGAL; // allowed only in Knightmate
+           break;
+         default:
+           return MOVE_ILLEGAL;
+       }
+    }
   } else
   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) && 
       ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) {
@@ -2267,7 +2289,7 @@ int backup_move(int g, int mode)
 {
   struct game_state_t *gs;
   struct move_t *m, *m1;
-  int now, i;
+  int now, i, piece;
 
   if (game_globals.garray[g].link >= 0)        /*IanO: not implemented for bughouse yet */
     return MOVE_ILLEGAL;
@@ -2308,12 +2330,11 @@ int backup_move(int g, int mode)
     gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
     goto cleanupMove;
   }
+  piece = gs->board[m->toFile][m->toRank];
   if(gs->board[m->fromFile][m->fromRank] != NOPIECE) { // [HGM] from-square occupied; move must have been Seirawan-style gating
     gs->holding[gs->onMove==WHITE ? 1 : 0][piecetype(gs->board[m->fromFile][m->fromRank])-1]++; // put back in holdings (onMove not flipped yet!)
-  }
-  gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
-  if (m->piecePromotionTo != NOPIECE) {
-    int piece;
+  } else
+  if (m->piecePromotionTo != NOPIECE) { // it is a real promotion
     switch(piecetype(m->piecePromotionTo)) { // Spartan pieces came from Hoplite, Shogi is problematic
       case KING:
       case CAPTAIN:
@@ -2325,9 +2346,9 @@ int backup_move(int g, int mode)
       case GOLD: // TODO: figure out what original was
       default: piece = PAWN;
     }
-    gs->board[m->fromFile][m->fromRank] = piece |
-      colorval(gs->board[m->fromFile][m->fromRank]);
+    piece |= colorval(gs->board[m->toFile][m->toRank]);
   }
+  gs->board[m->fromFile][m->fromRank] = piece;
   /******************
      When takeback a _first_ move of rook, the ??rmoved variable
      must be cleared . To check, if the move is first, we should