added book.c to Makefile.am
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index deac69f..58cbfc0 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -117,89 +117,26 @@ ChessSquare PromoPiece(moveType)
        return WhiteKing;\r
       case BlackPromotionKing:\r
        return BlackKing;\r
-#ifdef FAIRY\r
       case WhitePromotionChancellor:\r
         return WhiteMarshall;\r
       case BlackPromotionChancellor:\r
         return BlackMarshall;\r
       case WhitePromotionArchbishop:\r
-        return WhiteCardinal;\r
+        return WhiteAngel;\r
       case BlackPromotionArchbishop:\r
-        return BlackCardinal;\r
-#endif\r
-    }\r
-}\r
-\r
-ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
-     int whiteOnMove;\r
-     int promoChar;\r
-{\r
-    if (whiteOnMove) {\r
-       switch (promoChar) {\r
-         case 'n':\r
-         case 'N':\r
-           return WhitePromotionKnight;\r
-         case 'b':\r
-         case 'B':\r
-           return WhitePromotionBishop;\r
-         case 'r':\r
-         case 'R':\r
-           return WhitePromotionRook;\r
-#ifdef FAIRY\r
-          case 'a':\r
-          case 'A':\r
-            return WhitePromotionArchbishop;\r
-          case 'c':\r
-          case 'C':\r
-            return WhitePromotionChancellor;\r
-#endif\r
-         case 'q':\r
-         case 'Q':\r
-           return WhitePromotionQueen;\r
-         case 'k':\r
-         case 'K':\r
-           return WhitePromotionKing;\r
-         case NULLCHAR:\r
-         default:\r
-           return NormalMove;\r
-       }\r
-    } else {\r
-       switch (promoChar) {\r
-         case 'n':\r
-         case 'N':\r
-           return BlackPromotionKnight;\r
-         case 'b':\r
-         case 'B':\r
-           return BlackPromotionBishop;\r
-         case 'r':\r
-         case 'R':\r
-           return BlackPromotionRook;\r
-#ifdef FAIRY\r
-          case 'a':\r
-          case 'A':\r
-            return BlackPromotionArchbishop;\r
-          case 'c':\r
-          case 'C':\r
-            return BlackPromotionChancellor;\r
-#endif\r
-         case 'q':\r
-         case 'Q':\r
-           return BlackPromotionQueen;\r
-         case 'k':\r
-         case 'K':\r
-           return BlackPromotionKing;\r
-         case NULLCHAR:\r
-         default:\r
-           return NormalMove;\r
-       }\r
+        return BlackAngel;\r
+      case WhitePromotionCentaur:\r
+        return WhiteSilver;\r
+      case BlackPromotionCentaur:\r
+        return BlackSilver;\r
     }\r
 }\r
 \r
 char pieceToChar[] = {\r
                         'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', \r
-                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'S', 'L', 'U', 'K',\r
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',\r
                         'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', \r
-                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 's', 'l', 'u', 'k', \r
+                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', \r
                         'x' };\r
 \r
 char PieceToChar(p)\r
@@ -228,6 +165,52 @@ ChessSquare CharToPiece(c)
      return EmptySquare;\r
 }\r
 \r
+ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
+     int whiteOnMove;\r
+     int promoChar;\r
+{      /* [HGM] made dependent on CharToPiece to alow alternate piece letters */\r
+       ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );
+       if(promoChar == NULLCHAR) return NormalMove;\r
+\r
+       switch(piece) {\r
+               case WhiteQueen:\r
+                       return WhitePromotionQueen;\r
+               case WhiteRook:\r
+                       return WhitePromotionRook;\r
+               case WhiteBishop:\r
+                       return WhitePromotionBishop;\r
+               case WhiteKnight:\r
+                       return WhitePromotionKnight;\r
+               case WhiteKing:\r
+                       return WhitePromotionKing;\r
+               case WhiteAngel:\r
+                       return WhitePromotionArchbishop;\r
+               case WhiteMarshall:\r
+                       return WhitePromotionChancellor;\r
+               case WhiteSilver:\r
+                       return WhitePromotionCentaur;\r
+               case BlackQueen:\r
+                       return BlackPromotionQueen;\r
+               case BlackRook:\r
+                       return BlackPromotionRook;\r
+               case BlackBishop:\r
+                       return BlackPromotionBishop;\r
+               case BlackKnight:\r
+                       return BlackPromotionKnight;\r
+               case BlackKing:\r
+                       return BlackPromotionKing;\r
+               case BlackAngel:\r
+                       return BlackPromotionArchbishop;\r
+               case BlackMarshall:\r
+                       return BlackPromotionChancellor;\r
+               case BlackSilver:\r
+                       return BlackPromotionCentaur;\r
+               default:\r
+                       // not all promotion implemented yet! Take Queen for those we don't know.\r
+                       return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);\r
+       }\r
+}\r
+\r
 void CopyBoard(to, from)\r
      Board to, from;\r
 {\r
@@ -595,7 +578,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      if (board[rt][ft] != EmptySquare) break;\r
                  }\r
                 if(m==1) goto mounted;\r
-                if(m==2) goto walking;\r
+                if(m==2) goto finishGold;\r
              break;\r
 \r
            case WhiteQueen:\r
@@ -650,6 +633,9 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  }\r
                 break;\r
 \r
+           case WhiteSilver:\r
+           case BlackSilver:\r
+               m++; // [HGM] superchess: use for Centaur\r
             case WhiteMan:\r
             case BlackMan:\r
             case SHOGI WhiteKing:\r
@@ -667,6 +653,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                    callback(board, flags, NormalMove,\r
                             rf, ff, rt, ft, closure);\r
                }\r
+               if(m==1) goto mounted;\r
              break;\r
 \r
            case WhiteNightrider:\r
@@ -783,11 +770,12 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             (ignoreCheck ||                             \r
             (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&\r
               !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&\r
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) &&\r
              !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
                      ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
-                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure);\r
+                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
        }\r
        if ((flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_WHITE_QCASTLE_OK) &&\r
@@ -801,7 +789,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
            (ignoreCheck ||\r
             (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&\r
-              !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3,      FALSE) &&\r
+              !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&\r
              !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
@@ -821,11 +809,12 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
            (ignoreCheck ||\r
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&\r
               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&\r
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) &&\r
              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
                     ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,\r
-                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2), closure);\r
+                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
        }\r
        if (!(flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_BLACK_QCASTLE_OK) &&\r
@@ -839,7 +828,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
            (ignoreCheck ||\r
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&\r
-              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3,      FALSE) &&\r
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&\r
               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
@@ -856,7 +845,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
 \r
     if ((flags & F_WHITE_ON_MOVE) != 0) {\r
         ff = castlingRights[2]; /* King file if we have any rights */\r
-        if(ff > 0) {\r
+        if(ff > 0 && board[0][ff] == WhiteKing) {\r
     if (appData.debugMode) {\r
         fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",\r
                 castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);\r
@@ -869,7 +858,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
                 if(k != ft && board[0][k] != EmptySquare) ft = -1;\r
             for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
-            if(ft >= 0)\r
+            if(ft >= 0 && board[0][ft] == WhiteRook)\r
                 callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);\r
 \r
             ft = castlingRights[1]; /* Rook file if we have A-side rights */\r
@@ -881,13 +870,12 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             if(ff > BOARD_LEFT+2) \r
             for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
-\r
-            if(ft >= 0)\r
+            if(ft >= 0 && board[0][ft] == WhiteRook)\r
                 callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);\r
         }\r
     } else {\r
         ff = castlingRights[5]; /* King file if we have any rights */\r
-        if(ff > 0) {\r
+        if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
             ft = castlingRights[3]; /* Rook file if we have H-side rights */\r
             left  = ff+1;\r
             right = BOARD_RGHT-2;\r
@@ -896,7 +884,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
                 if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;\r
             for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
-            if(ft >= 0)\r
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
                 callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
 \r
             ft = castlingRights[4]; /* Rook file if we have A-side rights */\r
@@ -908,8 +896,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             if(ff > BOARD_LEFT+2) \r
             for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
-\r
-            if(ft >= 0)\r
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
                 callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
         }\r
     }\r
@@ -1144,7 +1131,7 @@ int MateTest(board, flags, epfile, castlingRights)
     if (cl.count > 0) {\r
        return inCheck ? MT_CHECK : MT_NONE;\r
     } else {\r
-        return inCheck || gameInfo.variant == VariantXiangqi ?\r
+        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?\r
                          MT_CHECKMATE : MT_STALEMATE;\r
     }\r
 }\r
@@ -1191,6 +1178,11 @@ void Disambiguate(board, flags, epfile, closure)
     closure->count = 0;\r
     closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
     closure->kind = ImpossibleMove;\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+                             closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
+                             closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');\r
+    }\r
     GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
     if (closure->count == 0) {\r
        /* See if it's an illegal move due to check */\r
@@ -1199,15 +1191,17 @@ void Disambiguate(board, flags, epfile, closure)
                 (VOIDSTAR) closure);   \r
        if (closure->count == 0) {\r
            /* No, it's not even that */\r
+    if (appData.debugMode) { int i, j;\r
+       for(i=BOARD_HEIGHT-1; i>=0; i--) {\r
+               for(j=0; j<BOARD_WIDTH; j++)\r
+                       fprintf(debugFP, "%3d", (int) board[i][j]);\r
+               fprintf(debugFP, "\n");\r
+       }\r
+    }\r
            return;\r
        }\r
     }\r
 \r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-                             closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
-                             closure->promoCharIn,closure->promoCharIn);\r
-    }\r
     if(gameInfo.variant == VariantShogi) {\r
         /* [HGM] Shogi promotions. '=' means defer */\r
         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {\r
@@ -1272,7 +1266,7 @@ void Disambiguate(board, flags, epfile, closure)
 #endif\r
     /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */\r
     if(closure->promoCharIn != '=')\r
-        closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+        closure->promoChar = ToLower(closure->promoCharIn);\r
     else closure->promoChar = '=';\r
     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
     if (closure->count > 1) {\r
@@ -1287,10 +1281,11 @@ void Disambiguate(board, flags, epfile, closure)
     }\r
     if(closure->kind == IllegalMove)\r
     /* [HGM] might be a variant we don't understand, pass on promotion info */\r
-        closure->promoChar = closure->promoCharIn;\r
+        closure->promoChar = ToLower(closure->promoCharIn);\r
     if (appData.debugMode) {\r
         fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,closure->promoChar);\r
+        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,\r
+       closure->promoChar >= ' ' ? closure->promoChar:'-');\r
     }\r
 }\r
 \r
@@ -1374,7 +1369,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
     if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);\r
 \r
   if (appData.debugMode)\r
-          fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar );\r
+          fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-');\r
     switch (piece) {\r
       case WhitePawn:\r
       case BlackPawn:\r
@@ -1406,7 +1401,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        /* Use promotion suffix style "=Q" */\r
        *outp = NULLCHAR;\r
   if (appData.debugMode)\r
-          fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar);\r
+          fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-');\r
         if (promoChar != NULLCHAR) {\r
             if(gameInfo.variant == VariantShogi) {\r
                 /* [HGM] ... but not in Shogi! */\r
@@ -1549,8 +1544,6 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
       /* [HGM] Always long notation for fairies we don't know */\r
       case WhiteFalcon:\r
       case BlackFalcon:\r
-      case WhiteSilver:\r
-      case BlackSilver:\r
       case WhiteLance:\r
       case BlackLance:\r
       case WhiteGrasshopper:\r