Merge branch 'v4.8.x'
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 68bf107..867a940 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -5,7 +5,8 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free
+ * Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -71,7 +72,6 @@ int BlackPiece P((ChessSquare));
 int SameColor P((ChessSquare, ChessSquare));
 int PosFlags(int index);
 
-extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */
 int quickFlag;
 char *pieceDesc[EmptySquare];
 char *defaultDesc[EmptySquare] = {
@@ -127,7 +127,7 @@ char
 PieceToChar (ChessSquare p)
 {
     int c;
-    if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */
+    if((int)p < 0 || (int)p >= (int)EmptySquare) return('?'); /* [HGM] for safety */
     c = pieceToChar[(int) p];
     if(c & 128) c = c & 63 | 64;
     return c;
@@ -205,7 +205,7 @@ CollectPieceDescriptors ()
     // dump all engine defined pieces, and pieces with non-standard names,
     // but suppress black pieces that are the same as their white counterpart
     ChessSquare p;
-    static char buf[MSG_SIZ];
+    static char buf[MSG_SIZ], s[2];
     char *m, c, d, *pieceName = defaultName;
     int len;
     *buf = NULLCHAR;
@@ -216,21 +216,55 @@ CollectPieceDescriptors ()
     for(p=WhitePawn; p<EmptySquare; p++) {
        if((c = pieceToChar[p]) == '.' || c == '~') continue;  // does not participate
        m = pieceDesc[p]; d = (c == '+' ? pieceToChar[DEMOTED(p)] : c);
-       if(p >= BlackPawn && pieceToChar[BLACK_TO_WHITE p] == toupper(c)
+       if(p >= BlackPawn && pieceToChar[BLACK_TO_WHITE p] == (c & ~32)
              && (c != '+' || pieceToChar[DEMOTED(BLACK_TO_WHITE p)] == d)) {// black member of normal pair
            char *wm = pieceDesc[BLACK_TO_WHITE p];
            if(!m && !wm || m && wm && !strcmp(wm, m)) continue;            // moves as a white piece
        } else                                                              // white or unpaired black
-       if((p < BlackPawn || CharToPiece(toupper(d)) != EmptySquare) &&     // white or lone black
+       if((p < BlackPawn || CharToPiece(d & ~32) != EmptySquare) &&        // white or lone black
           !pieceDesc[p] /*&& pieceName[p] == c*/) continue; // orthodox piece known by its usual name
 // TODO: listing pieces because of unusual name can only be done if we have accurate Betza of all defaults
        if(!m) m = defaultDesc[p];
+       if(!m) continue;
        len = strlen(buf);
-       snprintf(buf+len, MSG_SIZ-len, "%s%s%c:%s", len ? ";" : "", c == '+' ? "+" : "", d, m);
+       *s = (d > 128 ? SUFFIXES[d-128>>6] : 0); d = 64 + (d & 63);
+       snprintf(buf+len, MSG_SIZ-len, "%s%s%c%s:%s", len ? ";" : "", c == '+' ? "+" : "", d, s, m);
     }
     return buf;
 }
 
+int
+LoadPieceDesc (char *s)
+{
+    ChessSquare piece;
+    static char suf[] = SUFFIXES;
+    char *r, *p, *q = s;
+    int ok = TRUE, promoted, c;
+    while(q && *s) {
+       p = s;
+       q = strchr(s, ';');
+       if(q) *q = 0, s = q+1;
+       if(*p == '+') promoted = 1, p++; else promoted = 0;
+       c = *p++;
+       if(!c) { ok = FALSE; continue; } // bad syntax
+       if(*p && (r = strchr(suf, *p))) c += 64*(r - suf + 1), p++;
+       if(*p++ != ':') { ok = FALSE; continue; } // bad syntax
+       if(!strcmp(p, "(null)")) continue; // handle bug in writing of XBoard 4.8.0
+        piece = CharToPiece(c);
+       if(piece >= EmptySquare) { ok = FALSE; continue; } // non-existent piece
+       if(promoted) {
+           piece = promoPartner[piece];
+           if(pieceToChar[piece] != '+') { ok = FALSE; continue; } // promoted form does not exist
+       }
+       ASSIGN(pieceDesc[piece], p);
+       if(piece < BlackPawn && (pieceToChar[WHITE_TO_BLACK piece] == pieceToChar[piece] + 32 || promoted)) {
+           ASSIGN(pieceDesc[WHITE_TO_BLACK piece], p);
+       }
+       pieceDefs = TRUE;
+    }
+    return ok;
+}
+
 // [HGM] gen: configurable move generation from Betza notation sent by engine.
 // Some notes about two-leg moves: GenPseudoLegal() works in two modes, depending on whether a 'kill-
 // square has been set: without one is generates all moves, and a global int legNr flags in bits 0 and 1
@@ -286,7 +320,7 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle
     if(pc == WhitePawn || pc == WhiteLance) promo = WhitePromotion, promoRank = BOARD_HEIGHT-1; else
     if(pc == BlackPawn || pc == BlackLance) promo = BlackPromotion, promoRank = 0;
     while(*p) {                  // more moves to go
-       int expo = 1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0;
+       int expo = -1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0;
        char *cont = NULL;
        while(*p == 'i') initial++, desc = ++p;
        while(islower(*p)) p++;  // skip prefixes
@@ -377,9 +411,10 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle
        if(initial && (board[r][f] != initialPosition[r][f] ||
                       r == 0              && board[TOUCHED_W] & 1<<f ||
                       r == BOARD_HEIGHT-1 && board[TOUCHED_B] & 1<<f   ) ) continue;
-       if(expo > 1 && dx == 0 && dy == 0) {          // castling indicated by O + number
+       if(expo > 0 && dx == 0 && dy == 0) {          // castling indicated by O + number
            mode |= 1024; dy = 1;
        }
+       if(expo < 0) expo = 1;                        // use 1 for default
         if(!cont) {
            if(!(mode & 15)) mode |= his + 4;         // no mode spec, use default = mc
        } else {
@@ -450,7 +485,7 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle
                    if(occup == 4) continue; // skip empty squares
                    if((x == BOARD_LEFT + skip || x > BOARD_LEFT + skip && vx < 0 && board[y][x-1-skip] == DarkSquare)
                                                                    && board[y][x] == initialPosition[y][x]) { // reached initial corner piece
-                     if(pc != WhiteKing && pc != BlackKing) { // non-royal castling (to be entered as two-leg move via 'Rook')
+                     if(pc != WhiteKing && pc != BlackKing || expo == 1) { // non-royal castling (to be entered as two-leg move via 'Rook')
                        if(killX < 0) cb(board, flags, FirstLeg,   r, f, y, x, cl); if(killX < f)
                        legNr <<= 1,  cb(board, flags, NormalMove, r, f, y, f - expo, cl), legNr >>= 1;
                      } else
@@ -458,7 +493,7 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle
                    }
                    if((x == BOARD_RGHT-1-skip || x < BOARD_RGHT-1-skip && vx > 0 && board[y][x+1+skip] == DarkSquare)
                                                                    && board[y][x] == initialPosition[y][x]) {
-                     if(pc != WhiteKing && pc != BlackKing) {
+                     if(pc != WhiteKing && pc != BlackKing || expo == 1) {
                        if(killX < 0) cb(board, flags, FirstLeg,   r, f, y, x, cl); if(killX > f)
                        legNr <<= 1,  cb(board, flags, NormalMove, r, f, y, f + expo, cl), legNr >>= 1;
                      } else
@@ -912,8 +947,8 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                break;
 
 
-            case SHOGI WhiteStag:
-            case SHOGI BlackStag:
+            case SHOGI WhiteGnu:
+            case SHOGI BlackGnu:
                if(gameInfo.variant == VariantShogi) goto BlackGold;
                SlideVertical(board, flags, rf, ff, callback, closure);
                Ferz(board, flags, rf, ff, callback, closure);
@@ -1277,7 +1312,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteHorned:
+            case SHOGI WhiteCat:
                Sting(board, flags, rf, ff, 1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1286,7 +1321,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackHorned:
+            case SHOGI BlackCat:
                Sting(board, flags, rf, ff, -1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1295,7 +1330,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideForward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteEagle:
+            case SHOGI WhiteDagger:
                Sting(board, flags, rf, ff, 1,  1, callback, closure);
                Sting(board, flags, rf, ff, 1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -1304,7 +1339,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideDiagBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackEagle:
+            case SHOGI BlackDagger:
                Sting(board, flags, rf, ff, -1,  1, callback, closure);
                Sting(board, flags, rf, ff, -1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -2414,7 +2449,10 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p
        int r, f;
       for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<=BOARD_RGHT; f++)
                c += (board[r][f] == piece); // count on-board pieces of given type
-       *outp++ = ToUpper(PieceToChar(piece));
+        *outp = PieceToChar(piece);
+        if(*outp == '+') outp++, piece = CHUDEMOTED(piece);
+        *outp++ = ToUpper(PieceToChar(piece));
+        if(*outp = PieceSuffix(piece)) outp++;
     }
   if(c != 1) { // [HGM] but if there is only one piece of the mentioned type, no from-square, thank you!
     *outp++ = ff + AAA;