Extend legality testing to drop moves
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 16 Sep 2010 16:48:29 +0000 (18:48 +0200)
committerArun Persaud <arun@nubati.net>
Fri, 17 Sep 2010 03:47:08 +0000 (20:47 -0700)
LegalityTest() can nowbe called with (internal-format) drop moves, and
delegates their testing to a new routine LegalDrop(). This routine
performs the 'no-pawn-on-back-rank' test that used to be in
UserMoveTest (which now calls LegalityTest also for drop moves).
The more complex Shogi case is also handled (except for Pawn mate
drops) in LegalDrop().

backend.c
moves.c
parser.c
parser.l

index 65ea20d..12cef35 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -895,7 +895,7 @@ InitBackEnd1()
       case VariantGothic:     /* [HGM] should work */
       case VariantCapablanca: /* [HGM] should work */
       case VariantCourier:    /* [HGM] initial forced moves not implemented */
       case VariantGothic:     /* [HGM] should work */
       case VariantCapablanca: /* [HGM] should work */
       case VariantCourier:    /* [HGM] initial forced moves not implemented */
-      case VariantShogi:      /* [HGM] drops not tested for legality */
+      case VariantShogi:      /* [HGM] could still mate with pawn drop */
       case VariantKnightmate: /* [HGM] should work */
       case VariantCylinder:   /* [HGM] untested */
       case VariantFalcon:     /* [HGM] untested */
       case VariantKnightmate: /* [HGM] should work */
       case VariantCylinder:   /* [HGM] untested */
       case VariantFalcon:     /* [HGM] untested */
@@ -5996,7 +5996,7 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
           fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings
           while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; 
          fromY = DROP_RANK;
           fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings
           while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; 
          fromY = DROP_RANK;
-    } else
+    }
 
     /* [HGM] always test for legality, to get promotion info */
     moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
 
     /* [HGM] always test for legality, to get promotion info */
     moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
@@ -7164,9 +7164,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
         /* to make sure an illegal e.p. capture does not slip through,   */
         /* to cause a forfeit on a justified illegal-move complaint      */
         /* of the opponent.                                              */
         /* to make sure an illegal e.p. capture does not slip through,   */
         /* to cause a forfeit on a justified illegal-move complaint      */
         /* of the opponent.                                              */
-        if( gameMode==TwoMachinesPlay && appData.testLegality
-            && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */
-                                                              ) {
+        if( gameMode==TwoMachinesPlay && appData.testLegality ) {
            ChessMove moveType;
            moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
                              fromY, fromX, toY, toX, promoChar);
            ChessMove moveType;
            moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
                              fromY, fromX, toY, toX, promoChar);
diff --git a/moves.c b/moves.c
index 545a09c..f4f33b2 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -987,7 +987,7 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        }
        board[rt][ft] = board[rf][ff];
        board[rf][ff] = EmptySquare;
        }
        board[rt][ft] = board[rf][ff];
        board[rf][ff] = EmptySquare;
-    }
+    } else board[rt][ft] = ff; // [HGM] drop
 
     /* For compatibility with ICS wild 9, we scan the board in the
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
 
     /* For compatibility with ICS wild 9, we scan the board in the
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
@@ -1022,11 +1022,44 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        } else {
            board[rt][ft] = captured;
        }
        } else {
            board[rt][ft] = captured;
        }
-    }
+    } else board[rt][ft] = EmptySquare; // [HGM] drop
 
     return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
 }
 
 
     return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
 }
 
+ChessMove LegalDrop(board, flags, piece, rt, ft)
+     Board board;
+     int flags;
+     ChessSquare piece;
+     int rt, ft;
+{   // [HGM] put drop legality testing in separate routine for clarity
+    int n;
+if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt);
+    if(board[rt][ft] != EmptySquare) return ImpossibleMove; // must drop to empty square
+    n = PieceToNumber(piece);
+    if(gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece)
+        return ImpossibleMove; // piece not available
+    if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden!
+        if((piece == WhitePawn || piece == WhiteQueen) && rt == BOARD_HEIGHT-1 ||
+           (piece == BlackPawn || piece == BlackQueen) && rt == 0 ||
+            piece == WhiteKnight && rt > BOARD_HEIGHT-3 ||
+            piece == BlackKnight && rt < 2 ) return IllegalMove; // e.g. where dropped piece has no moves
+        if(piece == WhitePawn || piece == BlackPawn) {
+            int r;
+            for(r=1; r<BOARD_HEIGHT-1; r++)
+                if(board[r][ft] == piece) return IllegalMove; // or there already is a Pawn in file
+            // should still test if we mate with this Pawn
+        }
+    } else {
+        if( (piece == WhitePawn || piece == BlackPawn) &&
+            (rt == 0 || rt == BOARD_HEIGHT -1 ) )
+            return IllegalMove; /* no pawn drops on 1st/8th */
+    }
+if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt);
+    if (!(flags & F_IGNORE_CHECK) &&
+       CheckTest(board, flags, DROP_RANK, piece, rt, ft, FALSE) ) return IllegalMove;
+    return flags & F_WHITE_ON_MOVE ? WhiteDrop : BlackDrop;
+}
 
 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
                                    int rf, int ff, int rt, int ft,
 
 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
                                    int rf, int ff, int rt, int ft,
@@ -1055,7 +1088,10 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
      int flags;
      int rf, ff, rt, ft, promoChar;
 {
      int flags;
      int rf, ff, rt, ft, promoChar;
 {
-    LegalityTestClosure cl; ChessSquare piece = board[rf][ff], *castlingRights = board[CASTLING];
+    LegalityTestClosure cl; ChessSquare piece, *castlingRights = board[CASTLING];
+
+    if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft);
+    piece = board[rf][ff];
     
     if (appData.debugMode) {
         int i;
     
     if (appData.debugMode) {
         int i;
index ee1e2b1..ca1681b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2838,7 +2838,7 @@ case 11:
 YY_RULE_SETUP
 #line 826 "parser.l"
 {\r
 YY_RULE_SETUP
 #line 826 "parser.l"
 {\r
-    /* Bughouse piece drop.  No legality checking for now. */\r
+    /* Bughouse piece drop. */\r
     currentMoveString[1] = '@';\r
     currentMoveString[2] = yytext[2];\r
     currentMoveString[3] = yytext[3];\r
     currentMoveString[1] = '@';\r
     currentMoveString[2] = yytext[2];\r
     currentMoveString[3] = yytext[3];\r
@@ -2854,11 +2854,11 @@ YY_RULE_SETUP
 \r
     if (WhiteOnMove(yyboardindex)) {\r
        currentMoveString[0] = ToUpper(yytext[0]);\r
 \r
     if (WhiteOnMove(yyboardindex)) {\r
        currentMoveString[0] = ToUpper(yytext[0]);\r
-       return (int) WhiteDrop;\r
     } else {\r
        currentMoveString[0] = ToLower(yytext[0]);\r
     } else {\r
        currentMoveString[0] = ToLower(yytext[0]);\r
-       return (int) BlackDrop;\r
     }\r
     }\r
+    return LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), DROP_RANK, // [HGM] does drops now too
+                        CharToPiece(currentMoveString[0]), currentMoveString[3] - ONE, currentMoveString[2] - AAA, NULLCHAR);
 }\r
        YY_BREAK
 case 12:
 }\r
        YY_BREAK
 case 12:
index 528b3de..9590fe2 100644 (file)
--- a/parser.l
+++ b/parser.l
@@ -824,7 +824,7 @@ extern void CopyBoard P((Board to, Board from));
 }\r
 \r
 [A-Z][@*][a-l][0-9] {\r
 }\r
 \r
 [A-Z][@*][a-l][0-9] {\r
-    /* Bughouse piece drop.  No legality checking for now. */\r
+    /* Bughouse piece drop. */\r
     currentMoveString[1] = '@';\r
     currentMoveString[2] = yytext[2];\r
     currentMoveString[3] = yytext[3];\r
     currentMoveString[1] = '@';\r
     currentMoveString[2] = yytext[2];\r
     currentMoveString[3] = yytext[3];\r
@@ -840,11 +840,11 @@ extern void CopyBoard P((Board to, Board from));
 \r
     if (WhiteOnMove(yyboardindex)) {\r
        currentMoveString[0] = ToUpper(yytext[0]);\r
 \r
     if (WhiteOnMove(yyboardindex)) {\r
        currentMoveString[0] = ToUpper(yytext[0]);\r
-       return (int) WhiteDrop;\r
     } else {\r
        currentMoveString[0] = ToLower(yytext[0]);\r
     } else {\r
        currentMoveString[0] = ToLower(yytext[0]);\r
-       return (int) BlackDrop;\r
     }\r
     }\r
+    return LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), DROP_RANK, // [HGM] does drops now too
+                        CharToPiece(currentMoveString[0]), currentMoveString[3] - ONE, currentMoveString[2] - AAA, NULLCHAR);
 }\r
 \r
 [Rr]esign(s|ed)?  {\r
 }\r
 \r
 [Rr]esign(s|ed)?  {\r