Fix piece commands for promoted pieces
[xboard.git] / backend.c
index 0223dfb..83034f4 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -564,8 +564,8 @@ ChessSquare  KnightmateArray[2][BOARD_FILES] = {
 ChessSquare SpartanArray[2][BOARD_FILES] = {
     { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,
         WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },
-    { BlackAlfil, BlackMarshall, BlackKing, BlackDragon,
-        BlackDragon, BlackKing, BlackAngel, BlackAlfil }
+    { BlackAlfil, BlackDragon, BlackKing, BlackTower,
+        BlackTower, BlackKing, BlackAngel, BlackAlfil }
 };
 
 ChessSquare fairyArray[2][BOARD_FILES] = { /* [HGM] Queen side differs from King side */
@@ -691,18 +691,18 @@ ChessSquare CourierArray[2][BOARD_FILES] = {
         BlackFerz, BlackWazir, BlackBishop, BlackAlfil, BlackKnight, BlackRook }
 };
 ChessSquare ChuArray[6][BOARD_FILES] = {
-    { WhiteLance, WhiteUnicorn, WhiteMan, WhiteFerz, WhiteWazir, WhiteKing,
-      WhiteAlfil, WhiteWazir, WhiteFerz, WhiteMan, WhiteUnicorn, WhiteLance },
-    { BlackLance, BlackUnicorn, BlackMan, BlackFerz, BlackWazir, BlackAlfil,
-      BlackKing, BlackWazir, BlackFerz, BlackMan, BlackUnicorn, BlackLance },
-    { WhiteCannon, EmptySquare, WhiteBishop, EmptySquare, WhiteNightrider, WhiteMarshall,
-      WhiteAngel, WhiteNightrider, EmptySquare, WhiteBishop, EmptySquare, WhiteCannon },
-    { BlackCannon, EmptySquare, BlackBishop, EmptySquare, BlackNightrider, BlackAngel,
-      BlackMarshall, BlackNightrider, EmptySquare, BlackBishop, EmptySquare, BlackCannon },
-    { WhiteFalcon, WhiteSilver, WhiteRook, WhiteCardinal, WhiteDragon, WhiteLion,
-      WhiteQueen, WhiteDragon, WhiteCardinal, WhiteRook, WhiteSilver, WhiteFalcon },
-    { BlackFalcon, BlackSilver, BlackRook, BlackCardinal, BlackDragon, BlackQueen,
-      BlackLion, BlackDragon, BlackCardinal, BlackRook, BlackSilver, BlackFalcon }
+    { WhiteLance, WhiteCat, WhiteCopper, WhiteFerz, WhiteWazir, WhiteKing,
+      WhiteAlfil, WhiteWazir, WhiteFerz, WhiteCopper, WhiteCat, WhiteLance },
+    { BlackLance, BlackCat, BlackCopper, BlackFerz, BlackWazir, BlackAlfil,
+      BlackKing, BlackWazir, BlackFerz, BlackCopper, BlackCat, BlackLance },
+    { WhiteAxe, EmptySquare, WhiteBishop, EmptySquare, WhiteClaw, WhiteMarshall,
+      WhiteAngel, WhiteClaw, EmptySquare, WhiteBishop, EmptySquare, WhiteAxe },
+    { BlackAxe, EmptySquare, BlackBishop, EmptySquare, BlackClaw, BlackAngel,
+      BlackMarshall, BlackClaw, EmptySquare, BlackBishop, EmptySquare, BlackAxe },
+    { WhiteDagger, WhiteSword, WhiteRook, WhiteCardinal, WhiteDragon, WhiteLion,
+      WhiteQueen, WhiteDragon, WhiteCardinal, WhiteRook, WhiteSword, WhiteDagger },
+    { BlackDagger, BlackSword, BlackRook, BlackCardinal, BlackDragon, BlackQueen,
+      BlackLion, BlackDragon, BlackCardinal, BlackRook, BlackSword, BlackDagger }
 };
 #else // !(BOARD_FILES>=12)
 #define CourierArray CapablancaArray
@@ -6280,8 +6280,10 @@ InitPosition (int redraw)
       gameInfo.boardWidth  = 12;
       gameInfo.boardHeight = 12;
       nrCastlingRights = 0;
-      SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN.........^T..^L......^A^H/^F^G^M.^E^X^O^I.^P.^B^R..^D^S^C^VK"
-                                   "p.brqsexogcathd.vmlifn.........^t..^l......^a^h/^f^g^m.^e^x^o^i.^p.^b^r..^d^s^c^vk", SUFFIXES);
+//      SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN.........^T..^L......^A^H/^F^G^M.^E^X^O^I.^P.^B^R..^D^S^C^VK"
+  //                                 "p.brqsexogcathd.vmlifn.........^t..^l......^a^h/^f^g^m.^e^x^o^i.^p.^b^r..^d^s^c^vk", SUFFIXES);
+      SetCharTableEsc(pieceToChar, "P.BRQSEXOG...HD..^DLI^HNV........^T..^L.C...A^AFT/^F^G^M.^E^X^O^I.^P.^B^R..M^S^C^VK"
+                                   "p.brqsexog...hd..^dli^hnv........^t..^l.c...a^aft/^f^g^m.^e^x^o^i.^p.^b^r..m^s^c^vk", SUFFIXES);
       break;
     case VariantCourier:
       pieces = CourierArray;
@@ -6295,7 +6297,7 @@ InitPosition (int redraw)
       break;
     case VariantSpartan:
       pieces = SpartanArray;
-      SetCharTable(pieceToChar, "PNBRQ................K......lwg.....c...h..k");
+      SetCharTable(pieceToChar, "PNBRQ.....................K......lw......g...h......ck");
       break;
     case VariantLion:
       pieces = lionArray;
@@ -7112,14 +7114,13 @@ UserMoveEvent (int fromX, int fromY, int toX, int toY, int promoChar)
                ChessSquare p = boards[0][rf][ff];
                if(PieceToChar(p) == '+') gatingPiece = CHUDEMOTED(p); else
                if(PieceToChar(CHUPROMOTED(p)) =='+') gatingPiece = CHUPROMOTED(p); else
-               if(p == WhiteKing || p == BlackKing || p == WhiteRook || p == BlackRook) {
+               if(p == WhiteKing || p == BlackKing || p == WhiteRook || p == BlackRook || p == WhitePawn || p == BlackPawn) {
                    int n = rightsBoard[toY][toX] ^= 1; // toggle virginity of K or R
                    DisplayMessage("", n ? _("rights granted") : _("rights revoked"));
                    gatingPiece = p;
                }
-           }
+           } else  rightsBoard[toY][toX] = 0;  // revoke rights on moving
            boards[0][toY][toX] = boards[0][fromY][fromX];
-           rightsBoard[toY][toX] = 0;  // revoke rights on moving
            if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings
                if(boards[0][fromY][0] != EmptySquare) {
                    if(boards[0][fromY][1]) boards[0][fromY][1]--;
@@ -7914,6 +7915,7 @@ LeftClick (ClickType clickType, int xPix, int yPix)
            DisplayMessage("Click in holdings to choose piece", "");
            return;
        }
+       DrawPosition(FALSE, NULL); // shows piece on from-square during promo popup
        PromotionPopUp(promoChoice);
     } else {
        int oldMove = currentMove;
@@ -9144,10 +9146,10 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
     }
     if(sscanf(message, "piece %s %s", buf2, buf1) == 2) {
       ChessSquare piece = WhitePawn;
-      char *p=message+6, *q, *s = SUFFIXES, ID = *p;
-      if(*p == '+') piece = CHUPROMOTED(WhitePawn), ID = *++p;
+      char *p=message+6, *q, *s = SUFFIXES, ID = *p, promoted = 0;
+      if(*p == '+') promoted++, ID = *++p;
       if(q = strchr(s, p[1])) ID += 64*(q - s + 1), p++;
-      piece += CharToPiece(ID & 255) - WhitePawn;
+      piece = CharToPiece(ID & 255); if(promoted) piece = CHUPROMOTED(piece);
       if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR
       /* always accept definition of  */       && piece != WhiteFalcon && piece != BlackFalcon
       /* wild-card pieces.            */       && piece != WhiteCobra  && piece != BlackCobra
@@ -13924,6 +13926,10 @@ SaveGamePGN2 (FILE *f)
                    snprintf(buf, MSG_SIZ, " %d:%02d%c", seconds/60, seconds%60, 0);
                }
 
+           if(appData.cumulativeTimePGN) {
+               snprintf(buf, MSG_SIZ, " %+ld", timeRemaining[i & 1][i+1]/1000);
+           }
+
             snprintf( move_buffer, sizeof(move_buffer)/sizeof(move_buffer[0]),"{%s%.2f/%d%s}",
                      pvInfoList[i].score >= 0 ? "+" : "",
                      pvInfoList[i].score / 100.0,
@@ -15353,22 +15359,23 @@ EditPositionDone (Boolean fakeRights)
     startedFromSetupPosition = TRUE;
     InitChessProgram(&first, FALSE);
     if(fakeRights) { // [HGM] suppress this if we just pasted a FEN.
+      int r, f;
       boards[0][EP_STATUS] = EP_NONE;
-      boards[0][CASTLING][2] = boards[0][CASTLING][5] = BOARD_WIDTH>>1;
-      if(boards[0][0][BOARD_WIDTH>>1] == king) {
-       boards[0][CASTLING][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? BOARD_LEFT : NoRights;
-       boards[0][CASTLING][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : NoRights;
-      } else boards[0][CASTLING][2] = NoRights;
-      if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) {
-       boards[0][CASTLING][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? BOARD_LEFT : NoRights;
-       boards[0][CASTLING][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : NoRights;
-      } else boards[0][CASTLING][5] = NoRights;
-      if(gameInfo.variant == VariantSChess) {
-       int i;
-       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // pieces in their original position are assumed virgin
-         boards[0][VIRGIN][i] = 0;
-         if(boards[0][0][i]              == FIDEArray[0][i-BOARD_LEFT]) boards[0][VIRGIN][i] |= VIRGIN_W;
-         if(boards[0][BOARD_HEIGHT-1][i] == FIDEArray[1][i-BOARD_LEFT]) boards[0][VIRGIN][i] |= VIRGIN_B;
+      for(f=0; f<=nrCastlingRights; f++) boards[0][CASTLING][f] = NoRights;
+      for(r=BOARD_HEIGHT-1; r>=0; r--) for(f=BOARD_RGHT-1; f>=BOARD_LEFT; f--) { // first pass: Kings & e.p.
+       if(rightsBoard[r][f]) {
+         ChessSquare p = boards[0][r][f];
+         if(p == (blackPlaysFirst ? WhitePawn : BlackPawn)) boards[0][EP_STATUS] = f;
+         else if(p == king) boards[0][CASTLING][2] = f;
+         else if(p == WHITE_TO_BLACK king) boards[0][CASTLING][5] = f;
+         else rightsBoard[r][f] = 2; // mark for second pass
+       }
+      }
+      for(r=BOARD_HEIGHT-1; r>=0; r--) for(f=BOARD_RGHT-1; f>=BOARD_LEFT; f--) { // second pass: Rooks
+       if(rightsBoard[r][f] == 2) {
+         ChessSquare p = boards[0][r][f];
+         if(p == WhiteRook) boards[0][CASTLING][(f < boards[0][CASTLING][2])] = f; else
+         if(p == BlackRook) boards[0][CASTLING][(f < boards[0][CASTLING][5])+3] = f;
        }
       }
     }
@@ -15500,14 +15507,16 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y)
                    }
                }
            }
+           CopyBoard(rightsBoard, nullBoard);
            if(gameMode != IcsExamining) { // [HGM] editpos: cycle trough boards
-               int r;
+               int r, i;
                for(r = 0; r < BOARD_HEIGHT; r++) {
                  for(x = BOARD_LEFT; x < BOARD_RGHT; x++) { // create 'menu board' by removing duplicates 
                    ChessSquare p = menuBoard[r][x];
                    for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[r][y] == p) menuBoard[r][y] = EmptySquare;
                  }
                }
+               menuBoard[CASTLING][0] = menuBoard[CASTLING][3] = NoRights; // h-side Rook was deleted
                DisplayMessage("Clicking clock again restores position", "");
                if(gameInfo.variant != lastVariant) lastVariant = gameInfo.variant, CopyBoard(erasedBoard, boards[0]);
                if(!nonEmpty) { // asked to clear an empty board
@@ -15522,6 +15531,8 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y)
                } else
                    CopyBoard(erasedBoard, currentBoard);
 
+               for(i=0; i<nrCastlingRights; i++) if(boards[0][CASTLING][i] != NoRights)
+                   rightsBoard[castlingRank[i]][boards[0][CASTLING][i]] = 1; // copy remaining rights
            }
        }
        if (gameMode == EditPosition) {
@@ -15588,6 +15599,7 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y)
         baseRank = 0;
       case BlackRook:
         if(y == baseRank && (x == BOARD_LEFT || x == BOARD_RGHT-1 || appData.fischerCastling)) hasRights = 1;
+        if(y == baseRank && (x == BOARD_WIDTH>>1 || appData.fischerCastling)) hasRights = 1;
         goto defaultlabel;
 
       case WhiteKing: