Fix spurious promotions with legality testing off
authorH.G. Muller <h.g.muller@hccnet.nl>
Sun, 31 Oct 2010 12:16:01 +0000 (13:16 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Tue, 9 Nov 2010 13:39:02 +0000 (14:39 +0100)
The recent promotion patch had broken playing without legality testing
completely: without legality testing one always gets the piece that was
asked for, but a NULLCHAR should not be taken as a request for a piece!
But it was, and this resulted in any moved piece turning into a white
Pawn! For true promotions the piece was always black, which was also not
very useful.

Also revert to the use of '+' as internal Shogi promoChar, because
pre-processing turns out not to be possible when reading a game file.
In stead parse any trailing '+' on moves as promoChar. Downside: '++'
can no longer be recognized as checkmate symbol.

backend.c
moves.c
parser.l
winboard/winboard.c
xboard.c

index 5c7ebad..25fe5f5 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -4804,7 +4804,7 @@ CoordsToComputerAlgebraic(rf, ff, rt, ft, promoChar, move)
                     AAA + ff, ONE + rf, AAA + ft, ONE + rt);
        } else {
            sprintf(move, "%c%c%c%c%c\n",
-                    AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar == '^' ? '+' : promoChar);
+                    AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar);
        }
     }
 }
@@ -4884,16 +4884,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
      int *fromX, *fromY, *toX, *toY;
      char *promoChar;
 {
-    char moveCopy[20], *p = moveCopy;
-    strncpy(moveCopy, move, 20); // make a copy of move to preprocess it
-    if(gameInfo.variant == VariantShogi) {
-        while(*p && *p != ' ') p++;
-        if(p[-1] == '+') p[-1] = '^'; // in Shogi '+' is promotion, distinguish from check
-    }
-    if (appData.debugMode) {
-        fprintf(debugFP, "move to parse: %s\n", moveCopy);
-    }
-    *moveType = yylexstr(moveNum, moveCopy, yy_textstr, sizeof yy_textstr);
+    *moveType = yylexstr(moveNum, move, yy_textstr, sizeof yy_textstr);
 
     switch (*moveType) {
       case WhitePromotion:
@@ -5700,14 +5691,14 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
            if(toY == 0 && piece == BlackPawn ||
               toY == 0 && piece == BlackQueen ||
               toY <= 1 && piece == BlackKnight) {
-               *promoChoice = '^';
+               *promoChoice = '+';
                return FALSE;
            }
        } else {
            if(toY == BOARD_HEIGHT-1 && piece == WhitePawn ||
               toY == BOARD_HEIGHT-1 && piece == WhiteQueen ||
               toY >= BOARD_HEIGHT-2 && piece == WhiteKnight) {
-               *promoChoice = '^';
+               *promoChoice = '+';
                return FALSE;
            }
        }
@@ -5744,7 +5735,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
              gameMode == IcsPlayingBlack &&  WhiteOnMove(currentMove);
     if(appData.testLegality && !premove) {
        moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
-                       fromY, fromX, toY, toX, gameInfo.variant == VariantShogi ? '^' : NULLCHAR);
+                       fromY, fromX, toY, toX, gameInfo.variant == VariantShogi ? '+' : NULLCHAR);
        if(moveType != WhitePromotion && moveType  != BlackPromotion)
            return FALSE;
     }
@@ -8650,11 +8641,11 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
        board[toY][toX] = EmptySquare;
       }
     }
-    if(promoChar == '^') {
+    if(promoChar == '+') {
         /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite orinary Pawn promotion) */
         board[toY][toX] = (ChessSquare) (PROMOTED piece);
-    } else if(!appData.testLegality) { // without legality testing, unconditionally believe promoChar
-        board[toY][toX] = CharToPiece(promoChar);
+    } else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar
+        board[toY][toX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar));
     }
     if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
                && promoChar != NULLCHAR && gameInfo.holdingsSize) {
diff --git a/moves.c b/moves.c
index a0f7b7e..89af9a0 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -1037,9 +1037,9 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
             if(promoChar == 'd' && (piece == WhiteRook   || piece == BlackRook)   ||
                promoChar == 'h' && (piece == WhiteBishop || piece == BlackBishop) ||
                promoChar == 'g' && (piece <= WhiteFerz || piece <= BlackFerz && piece >= BlackPawn) )
-                  promoChar = '^'; // allowed ICS notations
+                  promoChar = '+'; // allowed ICS notations
 if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promoChar : '-');
-            if(promoChar != NULLCHAR && promoChar != '^' && promoChar != '=')
+            if(promoChar != NULLCHAR && promoChar != '+' && promoChar != '=')
                 return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove;
             else if(flags & F_WHITE_ON_MOVE) {
                 if( (int) piece < (int) WhiteWazir &&
@@ -1048,16 +1048,16 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo
                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
                        cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion;
                     else /* promotion optional, default is defer */
-                       cl.kind = promoChar == '^' ? WhitePromotion : WhiteNonPromotion;
-                } else cl.kind = promoChar == '^' ? IllegalMove : NormalMove;
+                       cl.kind = promoChar == '+' ? WhitePromotion : WhiteNonPromotion;
+                } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove;
             } else {
                 if( (int) piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) {
                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */
                        cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
                     else /* promotion optional, default is defer */
-                       cl.kind = promoChar == '^' ? BlackPromotion : BlackNonPromotion;
-                } else cl.kind = promoChar == '^' ? IllegalMove : NormalMove;
+                       cl.kind = promoChar == '+' ? BlackPromotion : BlackNonPromotion;
+                } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove;
             }
         }
     } else
@@ -1228,14 +1228,14 @@ void Disambiguate(board, flags, closure)
 
     if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
     if(gameInfo.variant == VariantShogi) {
-        /* [HGM] Shogi promotions. On input, '=' means defer, '^' promote. Afterwards, c is set to '+' for promotions, NULL other */
+        /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */
         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
             ChessSquare piece = closure->piece;
             if (c == 'd' && (piece == WhiteRook   || piece == BlackRook)   ||
                 c == 'h' && (piece == WhiteBishop || piece == BlackBishop) ||
                 c == 'g' && (piece <= WhiteFerz || piece <= BlackFerz && piece >= BlackPawn) )
-                   c = '^'; // allowed ICS notations
-            if(c != NULLCHAR && c != '^' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal
+                   c = '+'; // allowed ICS notations
+            if(c != NULLCHAR && c != '+' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal
             else if(flags & F_WHITE_ON_MOVE) {
                 if( (int) piece < (int) WhiteWazir &&
                      (closure->rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || closure->rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) {
@@ -1243,19 +1243,19 @@ void Disambiguate(board, flags, closure)
                          piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */
                        closure->kind = c == '=' ? IllegalMove : WhitePromotion;
                     else /* promotion optional, default is defer */
-                       closure->kind = c == '^' ? WhitePromotion : WhiteNonPromotion; 
-                } else closure->kind = c == '^' ? IllegalMove : NormalMove;
+                       closure->kind = c == '+' ? WhitePromotion : WhiteNonPromotion; 
+                } else closure->kind = c == '+' ? IllegalMove : NormalMove;
             } else {
                 if( (int) piece < (int) BlackWazir && (closure->rf < BOARD_HEIGHT/3 || closure->rt < BOARD_HEIGHT/3) ) {
                     if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||
                          piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */
                        closure->kind = c == '=' ? IllegalMove : BlackPromotion;
                     else /* promotion optional, default is defer */
-                       closure->kind = c == '^' ? BlackPromotion : BlackNonPromotion;
-                } else closure->kind = c == '^' ? IllegalMove : NormalMove;
+                       closure->kind = c == '+' ? BlackPromotion : BlackNonPromotion;
+                } else closure->kind = c == '+' ? IllegalMove : NormalMove;
             }
         }
-        if(closure->kind == WhitePromotion || closure->kind == BlackPromotion) c = '^'; else
+        if(closure->kind == WhitePromotion || closure->kind == BlackPromotion) c = '+'; else
         if(closure->kind == WhiteNonPromotion || closure->kind == BlackNonPromotion) c = '=';
     } else
     if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
@@ -1270,7 +1270,7 @@ void Disambiguate(board, flags, closure)
     } else if (c != NULLCHAR) closure->kind = IllegalMove;
 
     closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal.
-    if(c != '^' && c != '=' && c != NULLCHAR && CharToPiece(c) == EmptySquare)
+    if(c != '+' && c != '=' && c != NULLCHAR && CharToPiece(c) == EmptySquare)
        closure->kind = ImpossibleMove; // but we cannot handle non-existing piece types!
     if (closure->count > 1) {
        closure->kind = AmbiguousMove;
@@ -1501,7 +1501,6 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
         if (gameInfo.variant == VariantShogi) {
             /* [HGM] in Shogi non-pawns can promote */
-            if(promoChar == '^') promoChar = '+';
             *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
         }
        *outp = NULLCHAR;
index 021047b..17d7915 100644 (file)
--- a/parser.l
+++ b/parser.l
@@ -66,7 +66,7 @@
  * Ranks can be 0-9. The parser returns 0 for off-board files and ranks.
  * For an unknown piece (as mover or promotion piece) it returns
  * IllegalMove, like it does when the piece doesn't match.
- * Promotions can now also be appended Shogi-style, a bare '=' or '^',
+ * Promotions can now also be appended Shogi-style, a bare '=' or '+',
  * and this is then returned as promotion character. The piece indicator
  * can be prefixed by a '+' to indicate it is a promoted piece.
  */
@@ -178,7 +178,7 @@ extern void CopyBoard P((Board to, Board from));
 %}
 %%
 
-"+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=^])? {
+"+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=+])? {
     /*
      * Fully-qualified algebraic move, possibly with promotion
      */
@@ -215,6 +215,7 @@ extern void CopyBoard P((Board to, Board from));
        } else {
             c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
        }
+        if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi
        currentMoveString[5] = NULLCHAR;
     }
 
@@ -256,7 +257,7 @@ extern void CopyBoard P((Board to, Board from));
         else if(gameInfo.variant == VariantGreat)
             currentMoveString[4] = PieceToChar(BlackMan);
         else if(gameInfo.variant == VariantShogi)
-            currentMoveString[4] = '^';
+            currentMoveString[4] = '+';
         else
             currentMoveString[4] = PieceToChar(BlackQueen);
       } else if(result == WhiteNonPromotion  || result == BlackNonPromotion)
@@ -267,7 +268,7 @@ extern void CopyBoard P((Board to, Board from));
     return (int) result;
 }
 
-[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=^])?      {
+[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=+])?      {
     /*
      * Simple algebraic move, possibly with promotion
      * [HGM] Engine moves are received in this format, with lower-case promoChar!
@@ -293,6 +294,7 @@ extern void CopyBoard P((Board to, Board from));
        } else {
             c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
        }
+        if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi
        currentMoveString[5] = NULLCHAR;
     }
 
@@ -322,7 +324,7 @@ extern void CopyBoard P((Board to, Board from));
         else if(gameInfo.variant == VariantGreat)
             currentMoveString[4] = PieceToChar(BlackMan);
         else if(gameInfo.variant == VariantShogi)
-            currentMoveString[4] = '^'; // Queen might not be defined in mini variants!
+            currentMoveString[4] = '+'; // Queen might not be defined in mini variants!
         else
             currentMoveString[4] = PieceToChar(BlackQueen);
       } else if(result == WhiteNonPromotion  || result == BlackNonPromotion)
@@ -377,7 +379,7 @@ extern void CopyBoard P((Board to, Board from));
     return (int) result;
 }
 
-[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=^])?       {
+[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=+])?       {
     /*
      * Pawn move, possibly with promotion
      */
@@ -395,7 +397,8 @@ extern void CopyBoard P((Board to, Board from));
     cl.ffIn = yytext[0] - AAA;
     cl.rtIn = yytext[1] - ONE;
     cl.ftIn = yytext[0] - AAA;
-    c = cl.promoCharIn = ToLower(yytext[2+skip]);
+    cl.promoCharIn = ToLower(yytext[2+skip]);
+    if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi
 
     /* [HGM] do not allow values beyond board size */
     if(cl.rtIn >= BOARD_HEIGHT ||
@@ -446,7 +449,8 @@ extern void CopyBoard P((Board to, Board from));
     cl.ffIn = yytext[0] - AAA;
     cl.rtIn = -1;
     cl.ftIn = yytext[1+skip1] - AAA;
-    c = cl.promoCharIn = yytext[2+skip1+skip2];
+    cl.promoCharIn = yytext[2+skip1+skip2];
+    if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi
 
     /* [HGM] do not allow values beyond board size */
     if(cl.ffIn >= BOARD_RGHT  ||
@@ -467,7 +471,7 @@ extern void CopyBoard P((Board to, Board from));
     return (int) cl.kind;
 }
 
-[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|[=^])? {
+[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|[=+])? {
     /*
      * unambiguously abbreviated Pawn capture, possibly with promotion
      */
@@ -523,8 +527,9 @@ extern void CopyBoard P((Board to, Board from));
        else
           c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
        currentMoveString[5] = NULLCHAR;
-        if(c != '=' && c != '^' && CharToPiece(c) == EmptySquare)
+        if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)
             return ImpossibleMove;
+        if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi
     } else {
        currentMoveString[4] = NULLCHAR;
     }
@@ -546,7 +551,7 @@ extern void CopyBoard P((Board to, Board from));
        if(gameInfo.variant == VariantGreat)
             currentMoveString[4] = PieceToChar(BlackMan);
        if(gameInfo.variant == VariantShogi)
-            currentMoveString[4] = '^';
+            currentMoveString[4] = '+';
       } else if(result == WhiteNonPromotion  || result == BlackNonPromotion)
             currentMoveString[4] = '=';
       currentMoveString[5] = NULLCHAR;
@@ -585,7 +590,7 @@ extern void CopyBoard P((Board to, Board from));
       return (int) IllegalMove;
 }
 
-"+"?[A-Z][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=^])?  {
+"+"?[A-Z][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=+])?  {
     /*
      * piece move, possibly ambiguous
      */
@@ -613,8 +618,9 @@ extern void CopyBoard P((Board to, Board from));
     cl.ftIn = yytext[1+skip] - AAA;
     cl.promoCharIn = NULLCHAR;
 
-    if(yyleng-skip > 3) /* [HGM] can have Shogi-style promotion */
+    if(yyleng-skip > 3 && gameInfo.variant == VariantShogi) /* [HGM] can have Shogi-style promotion */
         cl.promoCharIn = yytext[yyleng-1-(yytext[yyleng-1]==')')];
+    if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi
 
     if (appData.debugMode) {
         fprintf(debugFP, "Parser Qa1: yyleng=%d,  %d(%d,%d)-(%d,%d) = %d (%c)\n",
@@ -641,7 +647,7 @@ extern void CopyBoard P((Board to, Board from));
     return (int) cl.kind;
 }
 
-"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=^])?   {
+"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|[=+])?   {
     /*
      * piece move with rank or file disambiguator
      */
@@ -681,6 +687,7 @@ extern void CopyBoard P((Board to, Board from));
 
     if(yyleng-skip > 4) /* [HGM] can have Shogi-style promotion */
         cl.promoCharIn = yytext[yyleng-1-(yytext[yyleng-1]==')')];
+    if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi
 
     /* [HGM] do not allow values beyond board size */
     if(cl.rtIn >= BOARD_HEIGHT ||
index 2ab9456..f818927 100644 (file)
@@ -4318,7 +4318,7 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = gameInfo.variant == VariantShogi ? '^' : PieceToChar(BlackQueen);\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
       break;\r
     case PB_Rook:\r
       promoChar = PieceToChar(BlackRook);\r
index 59796c7..67992f1 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -5431,7 +5431,7 @@ void PromotionCallback(w, client_data, call_data)
     } else if (strcmp(name, _("Knight")) == 0) {
        promoChar = 'n';
     } else if (strcmp(name, _("Promote")) == 0) {
-       promoChar = '^';
+       promoChar = '+';
     } else if (strcmp(name, _("Defer")) == 0) {
        promoChar = '=';
     } else {