Fix multi-leg promotions
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index e6e316a..6a747a2 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -261,6 +261,7 @@ LoadPieceDesc (char *s)
            ASSIGN(pieceDesc[WHITE_TO_BLACK piece], p);
        }
        pieceDefs = TRUE;
+       if(q) *q = ';';
     }
     return ok;
 }
@@ -618,12 +619,12 @@ Bishop (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR
 
 void
 Sting (Board board, int flags, int rf, int ff, int dy, int dx, MoveCallback callback, VOIDSTAR closure)
-{ // Lion-like move of Horned Falcon and Souring Eagle
+{ // Lion-like move of Horned Falcon and Soaring Eagle
   int ft = ff + dx, rt = rf + dy;
   if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
   legNr += 2;
   if (!SameColor(board[rf][ff], board[rt][ft]))
-    callback(board, flags, board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure);
+    callback(board, flags, killX < 0 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure);
   legNr -= 2;
   ft += dx; rt += dy;
   if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
@@ -933,11 +934,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
             case SHOGI (PROMO BlackPawn):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI WhiteAxe:
+            case SHOGI BlackAxe:
                SlideVertical(board, flags, rf, ff, callback, closure);
                break;
 
             case SHOGI (PROMO WhiteKnight):
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
+            case SHOGI WhiteClaw:
             case SHOGI BlackDrunk:
             case SHOGI BlackAlfil:
                Ferz(board, flags, rf, ff, callback, closure);
@@ -947,6 +951,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
 
             case SHOGI (PROMO BlackKnight):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI BlackClaw:
             case SHOGI WhiteDrunk:
             case SHOGI WhiteAlfil:
                Ferz(board, flags, rf, ff, callback, closure);
@@ -1100,19 +1105,16 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
             /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */
            case WhiteDragon:
            case BlackDragon:
-              if(gameInfo.variant == VariantChuChess) goto DragonKing;
+              if(gameInfo.variant == VariantChuChess || gameInfo.variant == VariantSpartan) goto DragonKing;
               for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
                 for (s = -2; s <= 2; s += 4) {
                      rt = rf + s * d;
                      ft = ff + s * (1 - d);
                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
-                      if (board[rf+rt>>1][ff+ft>>1] == EmptySquare && gameInfo.variant != VariantSpartan) continue;
+                      if (board[rf+rt>>1][ff+ft>>1] == EmptySquare) continue;
                      if (SameColor(board[rf][ff], board[rt][ft])) continue;
                      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
                  }
-              if(gameInfo.variant == VariantSpartan) // in Spartan Chess restrict range to modern Dababba
-               Wazir(board, flags, rf, ff, callback, closure);
-             else
                Rook(board, flags, rf, ff, callback, closure);
               break;
 
@@ -1137,6 +1139,19 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                    Knight(board, flags, rf, ff, callback, closure);
                break;
 
+            case WhiteTower:
+            case BlackTower:
+                for (d = 0; d <= 1; d++) // Dababba moves
+                  for (s = -2; s <= 2; s += 4) {
+                     rt = rf + s * d;
+                     ft = ff + s * (1 - d);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+                     if (SameColor(board[rf][ff], board[rt][ft])) continue;
+                     callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+                 }
+               Wazir(board, flags, rf, ff, callback, closure);
+               break;
+
             /* Shogi Rooks are ordinary Rooks */
             case SHOGI WhiteRook:
             case SHOGI BlackRook:
@@ -1178,6 +1193,12 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
 
             case WhiteFerz:
             case BlackFerz:
+               if(gameInfo.variant == VariantXiangqi && ff != BOARD_WIDTH>>1) {
+                   int rt = (piece == BlackFerz ? BOARD_HEIGHT-2 : 1);
+                   int ft = BOARD_WIDTH>>1;
+                   if(!SameColor(board[rf][ff], board[rt][ft]))
+                       callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+               } else
                 /* [HGM] support Shatranj pieces */
                Ferz(board, flags, rf, ff, callback, closure);
                break;
@@ -1263,14 +1284,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                 if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
                 if (!(ff == ft && rf == rt) && SameColor(board[rf][ff], board[rt][ft])) continue;
                 i = (killX >= 0 && (rt-killY)*(rt-killY) + (killX-ft)*(killX-ft) < 3); legNr += 2*i;
-                callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove,
+                callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare && !i ? FirstLeg : NormalMove,
                          rf, ff, rt, ft, closure);
                 legNr -= 2*i;
               }
               break;
 
-            case SHOGI WhiteFalcon:
-            case SHOGI BlackFalcon:
+            case SHOGI WhiteDagger:
+            case SHOGI BlackDagger:
             case SHOGI WhitePDagger:
             case SHOGI BlackPDagger:
                SlideSideways(board, flags, rf, ff, callback, closure);
@@ -1286,24 +1307,26 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
             case SHOGI (PROMO BlackFerz):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI WhiteSword:
+            case SHOGI BlackSword:
             case SHOGI WhitePSword:
             case SHOGI BlackPSword:
                SlideVertical(board, flags, rf, ff, callback, closure);
                StepSideways(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteUnicorn:
-            case SHOGI BlackUnicorn:
+            case SHOGI WhiteCat:
+            case SHOGI BlackCat:
                Ferz(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteMan:
+            case SHOGI WhiteCopper:
                StepDiagForward(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackMan:
+            case SHOGI BlackCopper:
                StepDiagBackward(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
@@ -1320,7 +1343,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteCat:
+            case SHOGI WhiteUnicorn:
                Sting(board, flags, rf, ff, 1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1329,7 +1352,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackCat:
+            case SHOGI BlackUnicorn:
                Sting(board, flags, rf, ff, -1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1338,7 +1361,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideForward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteDagger:
+            case SHOGI WhiteFalcon:
                Sting(board, flags, rf, ff, 1,  1, callback, closure);
                Sting(board, flags, rf, ff, 1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -1347,7 +1370,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideDiagBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackDagger:
+            case SHOGI BlackFalcon:
                Sting(board, flags, rf, ff, -1,  1, callback, closure);
                Sting(board, flags, rf, ff, -1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -1407,7 +1430,7 @@ GenLegalCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt
 
     if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square
 
-    if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion
+    if ((int)board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion
 
     if (!(flags & F_IGNORE_CHECK) ) {
       int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion);
@@ -1663,11 +1686,11 @@ CheckTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int r
     register CheckTestClosure *cl = (CheckTestClosure *) closure;
 
     if (rt == cl->rking && ft == cl->fking) {
-       if(xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power
+       if((int)xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power
        cl->check++;
        xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1)
     }
-    if( board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)
+    if( (int)board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)
        && (gameInfo.variant != VariantLion || board[rf][ff] != WhiteKing && board[rf][ff] != BlackKing) )
        cl->check++; // [HGM] lion: forbidden counterstrike against Lion equated to putting yourself in check
 }
@@ -2046,7 +2069,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
     // [HGM] wild: for wild-card pieces rt and rf are dummies
     if(piece == WhiteFalcon || piece == BlackFalcon ||
        piece == WhiteCobra  || piece == BlackCobra)
-        wildCard = TRUE;
+        wildCard = !pieceDefs; // no wildcards when engine defined pieces
 
     if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
          || PieceToChar(board[rf][ff]) == '~'
@@ -2057,7 +2080,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
        (cl->rtIn == -1 || cl->rtIn == rt || wildCard) &&
        (cl->ftIn == -1 || cl->ftIn == ft || wildCard)) {
 
-       if(cl->count && rf == cl->rf && ff == cl->ff) return; // duplicate move
+       if(cl->count && rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft) return; // duplicate move
 
        if(cl->count == 1 && kifu & 0x7E && cl->rfIn == -1 && cl->ffIn == -1) { // traditional Shogi disambiguation required
            int this = 1, other = 1;
@@ -2130,7 +2153,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
            return;
          }
        }
-    } else if(pieceDefs && closure->count > 1) { // [HGM] gen: move is ambiguous under engine-defined rules
+    } else if(pieceDefs && closure->count > 1 && closure->rtIn >=0) { // [HGM] gen: move is ambiguous under engine-defined rules (and not one-click)
        DisambiguateClosure spare = *closure;
        pieceDefs = FALSE; spare.count = 0;     // See if the (erroneous) built-in rules would resolve that
         GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) &spare, closure->pieceIn);