Updated copyright notice to 2015
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 88bbdee..4158ea5 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -5,7 +5,7 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -114,19 +114,32 @@ SameColor (ChessSquare piece1, ChessSquare piece2)
 #define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn) || piece1 == DarkSquare || piece2 == DarkSquare)
 #endif
 
-char pieceToChar[] = {
+unsigned char pieceToChar[EmptySquare+1] = {
                         'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M',
                         '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' };
-char pieceNickName[EmptySquare];
+unsigned char pieceNickName[EmptySquare];
 
 char
 PieceToChar (ChessSquare p)
 {
+    int c;
     if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */
-    return pieceToChar[(int) p];
+    c = pieceToChar[(int) p];
+    if(c & 128) c = c & 63 | 64;
+    return c;
+}
+
+char
+PieceSuffix (ChessSquare p)
+{
+    int c;
+    if((int)p < 0 || (int)p >= (int)EmptySquare) return 0; /* [HGM] for safety */
+    c = pieceToChar[(int) p];
+    if(c < 128) return 0;
+    return SUFFIXES[c - 128 >> 6];
 }
 
 int
@@ -1816,7 +1829,10 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC
         if(cl.kind != NormalMove || promoChar == NULLCHAR || promoChar == '=') return cl.kind;
         if(promoChar != '+')
             return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove;
-        if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') return ImpossibleMove;
+        if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') {
+           if(PieceToChar(CHUPROMOTED (board[rf][ff] < BlackPawn ? WhitePawn : BlackPawn)) != '.')
+           return ImpossibleMove;
+       }
         return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
     } else
     if(gameInfo.variant == VariantShogi) {
@@ -1973,6 +1989,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
 {
     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
     int wildCard = FALSE; ChessSquare piece = board[rf][ff];
+    extern int kifu; // in parser.c
 
     // [HGM] wild: for wild-card pieces rt and rf are dummies
     if(piece == WhiteFalcon || piece == BlackFalcon ||
@@ -1990,6 +2007,18 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
 
        if(cl->count && rf == cl->rf && ff == cl->ff) return; // duplicate move
 
+       if(cl->count == 1 && kifu & 0x7E && cl->rfIn == -1 && cl->ffIn == -1) { // traditional Shogi disambiguation required
+           int this = 1, other = 1;
+           if(kifu & 2) this &= (flags & 1 ? rt > rf : rt < rf), other &= (flags & 1 ? cl->rt > cl->rf : cl->rt < cl->rf);
+           if(kifu & 4) this &= (flags & 1 ? rt < rf : rt > rf), other &= (flags & 1 ? cl->rt < cl->rf : cl->rt > cl->rf);
+           if(kifu & 8) this &= (rf == rt), other &= (cl->rt == cl->rf);
+           if(kifu & 0x10) this &= (flags & 1 ? ft <= ff : ft >= ff), other &= (flags & 1 ? cl->ft <= cl->ff : cl->ft >= cl->ff);
+           if(kifu & 0x20) this &= (flags & 1 ? ft >= ff : ft <= ff), other &= (flags & 1 ? cl->ft >= cl->ff : cl->ft <= cl->ff);
+           if(kifu & 0x40) this &= (ft == ff), other &= (cl->ft == cl->ff); // should never be used
+           if(!other) cl->count--; // the old move did not satisfy the requested relative position, erase it
+           if(!this) return;       // the current move does not satisfy the requested relative position, ignore it
+       }
+
        cl->count++;
        if(cl->count == 1 || board[rt][ft] != EmptySquare) {
          // [HGM] oneclick: if multiple moves, be sure we remember capture
@@ -2031,7 +2060,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
         GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn);
        if (closure->count == 0) {
            /* No, it's not even that */
-         if(!appData.testLegality && closure->pieceIn != EmptySquare) {
+         if(!appData.testLegality && !pieceDefs && closure->pieceIn != EmptySquare) {
            int f, r; // if there is only a single piece of the requested type on the board, use that
            closure->rt = closure->rtIn, closure->ft = closure->ftIn;
            for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
@@ -2111,8 +2140,10 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
     if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
         if(c == NULLCHAR) { // missing promoChar on mandatory promotion; use default for variant
             if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
-               gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
+               gameInfo.variant == VariantMakruk)
                 c = PieceToChar(BlackFerz);
+            else if(gameInfo.variant == VariantASEAN)
+                c = PieceToChar(BlackRook);
             else if(gameInfo.variant == VariantGreat)
                 c = PieceToChar(BlackMan);
             else if(gameInfo.variant == VariantGrand)
@@ -2326,6 +2357,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p
         }
         if(c=='+') *outp++ = c;
         *outp++ = ToUpper(PieceToChar(piece));
+        if(*outp = PieceSuffix(piece)) outp++;
 
        if (cl.file || (cl.either && !cl.rank)) {
             *outp++ = ff + AAA;