worked on premove bug
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 67c98ed..b4572fe 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -1,11 +1,13 @@
 /*
  * moves.c - Move generation and checking
- * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
  *
  * Copyright 1991 by Digital Equipment Corporation, Maynard,
- * Massachusetts.  Enhancements Copyright
- * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
- * Foundation, Inc.
+ * Massachusetts.
+ *
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007, 2008, 2009 Free Software Foundation, Inc.
+ *
+ * Enhancements Copyright 2005 Alessandro Scotti
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
@@ -65,8 +67,9 @@
 int WhitePiece P((ChessSquare));
 int BlackPiece P((ChessSquare));
 int SameColor P((ChessSquare, ChessSquare));
+int PosFlags(int index);
 
-extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
+extern signed char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
 
 
 int WhitePiece(piece)
@@ -137,7 +140,7 @@ ChessSquare PromoPiece(moveType)
 
 char pieceToChar[] = {
                         'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', 
-                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 'S', 'U', 'K',
                         'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', 
                         'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', 
                         'x' };
@@ -583,7 +586,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      if (board[rt][ft] != EmptySquare) break;
                  }
                 if(m==1) goto mounted;
-                if(m==2) goto finishGold;
+                if(m==2) goto finishSilver;
              break;
 
            case WhiteQueen:
@@ -647,7 +650,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
             case SHOGI BlackKing:
            case WhiteKing:
            case BlackKing:
-            walking:
+//            walking:
              for (i = -1; i <= 1; i++)
                for (j = -1; j <= 1; j++) {
                    if (i == 0 && j == 0) continue;
@@ -726,6 +729,7 @@ void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
 typedef struct {
     int rf, ff, rt, ft;
     ChessMove kind;
+    int captures; // [HGM] losers
 } LegalityTestClosure;
 
 
@@ -1005,7 +1009,7 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        }
     }
 
-    return cl.check;
+    return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
 }
 
 
@@ -1025,6 +1029,8 @@ void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
 //    if (appData.debugMode) {
 //        fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
 //    }
+    if(board[rt][ft] != EmptySquare || kind==WhiteCapturesEnPassant || kind==BlackCapturesEnPassant)
+       cl->captures++; // [HGM] losers: count legal captures
     if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
       cl->kind = kind;
 }
@@ -1054,7 +1060,11 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
     cl.rt = rt;
     cl.ft = ft;
     cl.kind = IllegalMove;
+    cl.captures = 0; // [HGM] losers: prepare to count legal captures.
     GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);
+    if((flags & F_MANDATORY_CAPTURE) && cl.captures && board[rt][ft] == EmptySquare
+               && cl.kind != WhiteCapturesEnPassant && cl.kind != BlackCapturesEnPassant)
+       return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
 
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. '=' means defer */
@@ -1130,15 +1140,45 @@ int MateTest(board, flags, epfile, castlingRights)
      char castlingRights[];
 {
     MateTestClosure cl;
-    int inCheck;
+    int inCheck, r, f, myPieces=0, hisPieces=0, nrKing=0;
+    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
 
+    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) { 
+        // [HGM] losers: Count pieces and kings, to detect other unorthodox winning conditions
+       nrKing += (board[r][f] == king);   // stm has king
+        if( board[r][f] != EmptySquare ) {
+           if((int)board[r][f] <= (int)king && (int)board[r][f] >= (int)king - (int)WhiteKing + (int)WhitePawn)
+                myPieces++;
+           else hisPieces++;
+       }
+    }
+    if(appData.debugMode) fprintf(debugFP, "MateTest: K=%d, my=%d, his=%d\n", nrKing, myPieces, hisPieces);
+    switch(gameInfo.variant) { // [HGM] losers: extinction wins
+       case VariantShatranj:
+               if(hisPieces == 1) return myPieces > 1 ? MT_BARE : MT_DRAW;
+       default:
+               break;
+       case VariantAtomic:
+               if(nrKing == 0) return MT_NOKING;
+               break;
+       case VariantLosers:
+               if(myPieces == 1) return MT_BARE;
+    }
     cl.count = 0;
     inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);
+    // [HGM] 3check: yet to do!
     if (cl.count > 0) {
        return inCheck ? MT_CHECK : MT_NONE;
     } else {
-        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?
-                         MT_CHECKMATE : MT_STALEMATE;
+       if(gameInfo.variant == VariantSuicide) // [HGM] losers: always stalemate, since no check, but result varies
+               return myPieces == hisPieces ? MT_STALEMATE :
+                                       myPieces > hisPieces ? MT_STAINMATE : MT_STEALMATE;
+       else if(gameInfo.variant == VariantLosers) return inCheck ? MT_TRICKMATE : MT_STEALMATE;
+       else if(gameInfo.variant == VariantGiveaway) return MT_STEALMATE; // no check exists, stalemated = win
+                                           
+        return inCheck ? MT_CHECKMATE 
+                      : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj) ? 
+                         MT_STAINMATE : MT_STALEMATE;
     }
 }
 
@@ -1680,11 +1720,11 @@ void ProtectedCallback(board, flags, kind, rf, ff, rt, ft, closure)
      int rf, ff, rt, ft;
      VOIDSTAR closure;
 {   // for determining if a piece (given through the closure) is protected
-  register ChaseClosure *cl = (ChaseClosure *) closure; // closure tells us where to recapture
-  
-  if(rt == cl->rt && ft == cl->ft) cl->recaptures++;    // count legal recaptures to this square
-  if(appData.debugMode && board[rt][ft] != EmptySquare)
-    fprintf(debugFP, "try %c%c%c%c=%d\n", ff+AAA, rf+ONE,ft+AAA, rt+ONE, cl->recaptures);
+    register ChaseClosure *cl = (ChaseClosure *) closure; // closure tells us where to recapture
+
+    if(rt == cl->rt && ft == cl->ft) cl->recaptures++;    // count legal recaptures to this square
+    if(appData.debugMode && board[rt][ft] != EmptySquare)
+       fprintf(debugFP, "try %c%c%c%c=%d\n", ff+AAA, rf+ONE,ft+AAA, rt+ONE, cl->recaptures);
 }
 
 extern char moveList[MAX_MOVES][MOVE_LEN];
@@ -1749,7 +1789,7 @@ int PerpetualChase(int first, int last)
            cl.recaptures = 0;         // prepare closure to pass recapture square and count moves to it
            cl.rt = chaseStack[j].rt;
            cl.ft = chaseStack[j].ft;
-           if(appData.debugMode) { int n; 
+           if(appData.debugMode) {
                fprintf(debugFP, "test if we can recapture %c%c\n", cl.ft+AAA, cl.rt+ONE);
            }
             GenLegal(boards[i+1], PosFlags(i+1), EP_NONE, initialRights, ProtectedCallback, &cl); // try all moves