Implement S-Chess
[capablanca.git] / lasker-2.2.3 / src / movecheck.c
index 8f0dd9c..6996d09 100644 (file)
@@ -1296,7 +1296,7 @@ int legal_move(struct game_state_t * gs,
 
   if (fFile == ALG_DROP) {
     move_piece = fRank;
-    if(!gs->drops) return 0; // [HGM] variants: no drops in this variant
+    if(gs->drops != 1) return 0; // [HGM] variants: no drops in this variant
     if (move_piece == KING)
       return 0;
     if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
@@ -1387,10 +1387,12 @@ int legal_move(struct game_state_t * gs,
   case ROOK:
     legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
     break;
+  case HAWK:
   case CARDINAL:
   case PRINCESS:
     legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank);
     break;
+  case SELEPHANT:
   case MARSHALL:
   case EMPRESS:
     legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank);
@@ -1484,6 +1486,7 @@ int legal_move(struct game_state_t * gs,
 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
 {
   struct game_state_t fakeMove;
+  int gating = 0;
 
   mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];
   mt->enPassant = 0;           /* Don't know yet, let execute move take care
@@ -1536,15 +1539,23 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom
     int stm = colorval(gs->board[mt->fromFile][mt->fromRank]);
     if(!promote && (mt->toRank == 0 || mt->toRank == gs->ranks-1)) { // promotion obligatory, but not specified
        if(gs->promoType != 2) promote = QUEEN; else { // choose a default
-           for(promote=KING-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break;
+           for(promote=PIECES-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break;
            if(promote == PAWN) return MOVE_ILLEGAL; // nothing available
        }
-    } // if not obligatory, we defer unless promoton was explicitly specified!
+    } // if not obligatory, we defer unless promotion was explicitly specified!
     if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2;
     if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj
     // 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
+  } else if(gs->drops == 2 && promote && mt->fromRank == (stm == WHITE ? 0 : gs->ranks-1)) { // [HGM] Seirawan-style gating
+    int i; struct game *g = &game_globals.garray[gs->gameNum];
+    if(!gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified
+    // now we must test virginity of the moved piece. Yegh!
+    for (i = g->numHalfMoves-2; i > 0; i -= 2) {
+      if (g->moveList[i].toFile == mt->fromFile && g->moveList[i].toRank == mt->fromRank) return MOVE_ILLEGAL;
+    }
+    gating = 1; // gating OK; remember we did it for check test
   } else {
     mt->piecePromotionTo = NOPIECE;
   }
@@ -1579,6 +1590,7 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom
   fakeMove = *gs;
   /* Calculates enPassant also */
   execute_move(&fakeMove, mt, 0);
+  if(gating) fakeMove.board[mt-fromFile][mt->fromRank] = NOPIECE; // [HGM] gating is only legal if non-gating move was (weird, but true)
 
   /* Does making this move leave ME in check? */
   if (in_check(&fakeMove))
@@ -1667,10 +1679,12 @@ int has_legal_move(struct game_state_t * gs)
     case ROOK:
       possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
       break;
+    case HAWK:
     case CARDINAL:
     case PRINCESS:
       possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible);
       break;
+    case SELEPHANT:
     case MARSHALL:
     case EMPRESS:
       possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible);
@@ -1922,13 +1936,19 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
   } else {
   movedPiece = gs->board[mt->fromFile][mt->fromRank];
   tookPiece = gs->board[mt->toFile][mt->toRank];
-  if (mt->piecePromotionTo == NOPIECE) {
+  if(gs->drops == 2 && mt->piecePromotionTo != NOPIECE && pieceType(movedPiece) != PAWN) { // [HGM] Seirawan-style gating
     gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
+    gs->board[mt->fromFile][mt->fromRank] = mt->piecePromotionTo | gs->onMove;;
+    gs->holding[gs->onMove==WHITE ? 0 : 1][mt->piecePromotionTo-1]--; // remove gated piece from holdings
   } else {
-    gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
-    if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
+    if (mt->piecePromotionTo == NOPIECE) {
+      gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
+    } else {
+      gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
+      if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
+    }
+    gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
   }
-  gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
   /* Check if irreversable */
   if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible!
                        || (tookPiece != NOPIECE)) {
@@ -2243,6 +2263,9 @@ int backup_move(int g, int mode)
     goto cleanupMove;
   }
   gs->board[m->toFile][m->toRank] = m->pieceCaptured;
+  if(gs->board[m->fromFile][m->fromRank] != NOPIECE) { // [HGM] from-square occupied, 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!)
+  }
 cleanupMove:
   if (game_globals.garray[g].status != GAME_EXAMINE) {
     game_update_time(g);