Oops! Remove duplicate setboard feature
[gnushogi.git] / gnushogi / commondsp.c
index 603143c..b8e1ca8 100644 (file)
 #include "gnushogi.h"
 
 char mvstr[4][6];
-char *InPtr;
 int mycnt1, mycnt2;
+static char *InPtr;
 struct display *dsp = &raw_display;
 
+short xboard = false;
 
 #if defined(BOOKTEST)
 
@@ -94,20 +95,20 @@ movealgbr(short m, char *s)
         s++;
         *s = '*';
         s++;
-        *s = cxx[column(t)];
+        *s = COL_NAME(column(t));
         s++;
-        *s = rxx[row(t)];
+        *s = ROW_NAME(row(t));
         s++;
     }
     else
     {
-        *s = cxx[column(f)];
+        *s = COL_NAME(column(f));
         s++;
-        *s = rxx[row(f)];
+        *s = ROW_NAME(row(f));
         s++;
-        *s = cxx[column(t)];
+        *s = COL_NAME(column(t));
         s++;
-        *s = rxx[row(t)];
+        *s = ROW_NAME(row(t));
         s++;
 
         if (flag & promote)
@@ -138,7 +139,10 @@ movealgbr(short m, char *s)
  *   - NO_SQUARES <= f NO_SQUARES + 2*NO_PIECES                dropped piece modulo NO_PIECES
  * - t & 0x7f                          target square
  * - t & 0x80                          promotion flag
- * - flag                              FIXME: must be zero ?
+ * - flag
+ *   - if flag & dropmask, piece type encoded in flag & pmask
+ *
+ * FIXME: that makes 2 ways to specify drops and promotions, why ?
  *
  * OUTPUT:
  * - GLOBAL mvstr
@@ -178,9 +182,9 @@ algbr(short f, short t, short flag)
         short piece = flag & pmask;
 
         mvstr[0][0] = pxx[piece];
-        mvstr[0][1] = '*';
-        mvstr[0][2] = cxx[column(t)];
-        mvstr[0][3] = rxx[row(t)];
+        mvstr[0][1] = xboard ? '@' : '*';
+        mvstr[0][2] = COL_NAME(column(t));
+        mvstr[0][3] = ROW_NAME(row(t));
         mvstr[0][4] = '\0';
         strcpy(mvstr[1], mvstr[0]);
         strcpy(mvstr[2], mvstr[0]);
@@ -188,20 +192,27 @@ algbr(short f, short t, short flag)
     }
     else if ((f != 0) || (t != 0))
     {
-        /* algebraic notation */
-        mvstr[0][0] = cxx[column(f)];
-        mvstr[0][1] = rxx[row(f)];
-        mvstr[0][2] = cxx[column(t)];
-        mvstr[0][3] = rxx[row(t)];
-        mvstr[0][4] = mvstr[3][0] = '\0';
+        /* pure coordinates notation */
+        mvstr[0][0] = COL_NAME(column(f));
+        mvstr[0][1] = ROW_NAME(row(f));
+        mvstr[0][2] = COL_NAME(column(t));
+        mvstr[0][3] = ROW_NAME(row(t));
+        mvstr[0][4] = '\0';
+
+        /* algebraic notation without disambiguation */
         mvstr[1][0] = pxx[board[f]];
+        mvstr[1][1] = mvstr[0][2];    /* to column */
+        mvstr[1][2] = mvstr[0][3];    /* to row */
+        mvstr[1][3] = '\0';
 
+        /* algebraic notation with row disambiguation */
         mvstr[2][0] = mvstr[1][0];
         mvstr[2][1] = mvstr[0][1];
+        mvstr[2][2] = mvstr[0][2];    /* to column */
+        mvstr[2][3] = mvstr[0][3];    /* to row */
+        mvstr[2][4] = '\0';
 
-        mvstr[2][2] = mvstr[1][1] = mvstr[0][2];    /* to column */
-        mvstr[2][3] = mvstr[1][2] = mvstr[0][3];    /* to row */
-        mvstr[2][4] = mvstr[1][3] = '\0';
+        /* algebraic notation with column disambiguation */
         strcpy(mvstr[3], mvstr[2]);
         mvstr[3][1] = mvstr[0][0];
 
@@ -274,6 +285,7 @@ VerifyMove(char *s, VerifyMove_mode iop, unsigned short *mv)
     MoveList(opponent, 2, -1, true);
     generate_move_flags = false;
     pnt = TrPnt[2];
+    if(s[4] == '=') s[4] = '\0'; /* deferral is implied */
 
     while (pnt < TrPnt[3])
     {
@@ -300,7 +312,7 @@ VerifyMove(char *s, VerifyMove_mode iop, unsigned short *mv)
         if (SqAttacked(PieceList[opponent][0], computer, &blocked))
         {
             UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
-            dsp->AlwaysShowMessage("Illegal move (in check) %s", s);
+            dsp->AlwaysShowMessage("Illegal move (in check): %s", s);
             return false;
         }
         else
@@ -342,7 +354,7 @@ VerifyMove(char *s, VerifyMove_mode iop, unsigned short *mv)
         }
     }
 
-    dsp->AlwaysShowMessage("Illegal move (no match) %s", s);
+    dsp->AlwaysShowMessage("Illegal move (no match): %s", s);
 
     if (!XSHOGI && (cnt > 1))
     {
@@ -374,17 +386,17 @@ parser(char *f, short *fpiece)
 
     if (f[1] == '*' || f[1] == '\'')
     {
-        c2 = COL_NAME(f[2]);
-        r2 = ROW_NAME(f[3]);
+        c2 = COL_NUM(f[2]);
+        r2 = ROW_NUM(f[3]);
 
         return ((NO_SQUARES + *fpiece) << 8) | locn(r2, c2);
     }
     else
     {
-        c1 = COL_NAME(f[1]);
-        r1 = ROW_NAME(f[2]);
-        c2 = COL_NAME(f[3]);
-        r2 = ROW_NAME(f[4]);
+        c1 = COL_NUM(f[1]);
+        r1 = ROW_NUM(f[2]);
+        c2 = COL_NUM(f[3]);
+        r2 = ROW_NUM(f[4]);
         p = (f[5] == '+') ? 0x80 : 0;
 
         return (locn(r1, c1) << 8) | locn(r2, c2) | p;
@@ -1028,8 +1040,10 @@ BookSave(void)
         RequestInputString(fname, sizeof(fname)-1);
     }
 
-    if (fname[0] == '\0')
+    if (fname[0] == '\0') {
+        dsp->AlwaysShowMessage("aborting book save");
         return;
+    }
 
     if ((fd = fopen(fname, "a")) != NULL)
     {
@@ -1409,16 +1423,15 @@ TestPSpeed(short(*f) (short side), unsigned j)
 static void
 SetOppTime(char *time)
 {
-    int m, t, sec;
+    int m, t;
 
-    sec = 0;
     t = (int)strtol(time, &time, 10);
 
     if (*time == ':')
     {
         time++;
        /* FIXME: sec is parsed but ignored */
-        sec = (int)strtol(time, &time, 10);
+        (void)strtol(time, &time, 10);
     }
 
     m = (int)strtol(time, &time, 10);
@@ -1442,16 +1455,15 @@ SetOppTime(char *time)
 static void
 SetMachineTime(char *time)
 {
-    int m, t, sec;
+    int m, t;
 
-    sec = 0;
     t = (int)strtol(time, &time, 10);
 
     if (*time == ':')
     {
         time++;
        /* FIXME: sec is parsed but ignored */
-        sec = (int)strtol(time, &time, 10);
+        (void)strtol(time, &time, 10);
     }
 
     m = (int)strtol(time, &time, 10);
@@ -1471,6 +1483,122 @@ SetMachineTime(char *time)
     }
 }
 
+/*
+ * Set up a board position. Pieces are entered by typing the piece followed
+ * by the location. For example, Nf3 will place a knight on square f3.
+ */
+static void
+ReadFEN(char *fen)
+{
+    short a = white, r, c, sq, i, error = 0;
+    char s[80];
+
+    flag.regularstart = true;
+    Book = BOOKFAIL;
+
+    for (sq = 0; sq < NO_SQUARES; sq++)
+    {
+        board[sq] = no_piece;
+        color[sq] = neutral;
+    }
+
+    ClearCaptured();
+
+    /* read board */
+    r = NO_ROWS-1; c = 0;
+    while(*fen)
+    {
+        if (isdigit(*fen))
+        {
+            c += *fen++ - '0'; /* assumes single digit! */
+        }
+        else if (*fen == '/')
+        {   /* next rank */
+            if (c != NO_COLS) error++;
+            c = 0; fen++;
+            if (--r < 0) break;
+        }
+        else
+        {
+            int promo = 0, found = 0;
+            if (*fen == '+')
+            {
+                promo++; fen++;
+            }
+
+            if (!isalpha(*fen)) break;
+
+            for (i = no_piece; i <= king; i++)
+            {
+                if ((*fen == pxx[i]) || (*fen == qxx[i]))
+                {
+                    sq = locn(r, c);
+                    color[sq] = (islower(*fen) ? white : black);
+                    if (promo)
+                        board[sq] = promoted[i];
+                    else
+                        board[sq] = i;
+
+                    found = 1;
+                    break;
+                }
+            }
+
+            if (!found) error++;
+            c++; fen++;
+        }
+    }
+    if(r || c != NO_COLS) error++;
+
+    while (*fen == ' ') fen++;
+
+    /* read holdings */
+    if(!strncmp(fen, "[-]", 3)) fen += 3; /* empty holdings */
+    else if(*fen == '[')
+    {
+        fen++;
+        while(isalpha(*fen))
+        {
+            int found = 0;
+            for (i = pawn; i <= king; i++)
+            {
+                if ((*fen == pxx[i]) || (*fen == qxx[i]))
+                {
+                    Captured[islower(*fen) ? white : black][i]++;
+                    found = 1;
+                    break;
+                }
+            }
+            if (!found) error++;
+            fen++;
+        }
+        if(*fen == ']') fen++; else error++;
+    }
+
+    while (*fen == ' ') fen++;
+
+    if (*fen == 'w')
+        a = black;
+    else if (*fen == 'b')
+        a = white;
+    else
+        error++;
+
+    if (error) printf("tellusererror bad FEN\n");
+
+    for (sq = 0; sq < NO_SQUARES; sq++)
+        Mvboard[sq] = ((board[sq] != Stboard[sq]) ? 10 : 0);
+
+    computer = otherside[a];
+    opponent = a;
+    flag.force = true;
+    GameCnt = 0;
+    Game50 = 1;
+    ZeroRPT();
+    Sdepth = 0;
+    InitializeStats();
+}
+
 
 /* FIXME!  This is truly the function from hell! */
 
@@ -1482,13 +1610,16 @@ SetMachineTime(char *time)
  * the hint move, then set Sdepth to zero.
  */
 
-void
-InputCommand(char *command)
+int
+InputCommand(char *command, int root)
 {
+#ifdef QUIETBACKGROUND
     short have_shown_prompt = false;
+#endif
     short ok, done, is_move = false;
     unsigned short mv;
-    char s[80], sx[80];
+    char s[200], sx[200];
+    static char backlog[200];
 
     ok = flag.quit = done = false;
     player = opponent;
@@ -1498,7 +1629,7 @@ InputCommand(char *command)
         ZeroTTable();
 #endif
 
-    if ((hint > 0) && !flag.easy && !flag.force)
+    if ((hint > 0) && !flag.easy && !flag.force && !command && !backlog[0] && root)
     {
         /*
          * A hint move for the player is available.  Compute a move for the
@@ -1562,6 +1693,10 @@ InputCommand(char *command)
     {
         player = opponent;
 
+        if (flag.analyze && !command && !backlog[0] && root) {
+            SelectMove(opponent, BACKGROUND_MODE);
+        }
+
 #ifdef QUIETBACKGROUND
         if (!have_shown_prompt)
         {
@@ -1575,12 +1710,15 @@ InputCommand(char *command)
         have_shown_prompt = false;
 #endif /* QUIETBACKGROUND */
 
+        if (!command && backlog[0]) command = backlog; /* pick up backlogged command */
+
         if (command == NULL) {
             int eof = dsp->GetString(sx);
             if (eof)
                 dsp->ExitShogi();
         } else {
             strcpy(sx, command);
+            backlog[0]= '\0'; /* make sure no backlog is left */
             done = true;
         }
 
@@ -1588,6 +1726,12 @@ InputCommand(char *command)
         if (sscanf(sx, "%s", s) < 1)
             continue;
 
+        if (!root && strcmp(s, "."))
+        {   /* during search most commands can only be done after abort */
+            strcpy(backlog, sx); /* backlog the command    */
+            return true;         /* and order search abort */
+        }
+
         if (strcmp(s, "bd") == 0)   /* bd -- display board */
         {
             /* FIXME: Hack alert! */
@@ -1604,19 +1748,79 @@ InputCommand(char *command)
         }
         else if (strcmp(s, "post") == 0)
         {
-            flag.post = !flag.post;
+            flag.post = (xboard ? 1 : !flag.post);
+        }
+        else if (strcmp(s, "nopost") == 0)
+        {
+            flag.post = 0;
         }
-        else if (strcmp(s, "alg") == 0)
+#ifdef MINISHOGI
+        else if (strcmp(s, "variant") == 0)
+        {   /* only variant we play is minishogi */
+            printf("setup (P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k) 5x5+5_shogi rbsgk/4p/5/P4/KGSBR [-] w 0 1\n");
+        }
+#endif
+        else if (strcmp(s, "alg") == 0 ||
+                 strcmp(s, "accepted") == 0 || strcmp(s, "rejected") == 0 ||
+                 strcmp(s, "variant") == 0 || strcmp(s, "computer") == 0)
         {
             /* noop */ ;
         }
-        else if ((strcmp(s, "quit") == 0)
-                 || (strcmp(s, "exit") == 0))
+        else if ((strcmp(s, "quit") == 0) ||
+                 (strcmp(s, "exit") == 0) && !xboard)
         {
             flag.quit = true;
         }
-        else if ((strcmp(s, "set") == 0)
-                 || (strcmp(s, "edit") == 0))
+        else if (strcmp(s, "xboard") == 0)
+        {
+            xboard = true;
+            strcpy(ColorStr[0], "White");
+            strcpy(ColorStr[1], "Black");
+        }
+        else if (strcmp(s, "protover") == 0)
+        {
+            printf("feature option=\"tsume -check 0\"\n");
+            printf("feature option=\"contempt -spin %d -1000 1000\"\n", contempt);
+            printf("feature option=\"Hash-file search depth -spin %d 0 100\"\n", HashDepth);
+            printf("feature option=\"Hash-file move number -spin %d 0 100\"\n", HashMoveLimit);
+            printf("feature myname=\"GNU %s %s\" ",
+#ifdef MINISHOGI
+                   "MiniShogi",
+#else
+                   "Shogi",
+#endif
+                   PACKAGE_VERSION
+                );
+            printf("variants=\"%s\" ",
+#ifdef MINISHOGI
+                   "5x5+5_shogi,minishogi"
+#else
+                   "shogi"
+#endif
+                );
+            printf("debug=1 setboard=1 sigint=0 memory=1 done=1\n");
+        }
+        else if (strcmp(s, ".") == 0)
+        {   // periodic update request of analysis info: send stat01 info
+            ElapsedTime(2);
+            algbr((short)(currentMove >> 8), (short)(currentMove & 0xFF), 0);
+            printf("stat01: %4ld %8ld %2d %2d %2d %s\n",
+                    et, NodeCnt, Sdepth, movesLeft, TrPnt[2]-TrPnt[1], mvstr[0]);
+            fflush(stdout);
+            if (!root) return false; /* signal no abort needed */
+        }
+        else if (strcmp(s, "exit") == 0)
+        {
+            flag.analyze = false;
+            flag.force = true;
+        }
+        else if (strcmp(s, "analyze") == 0)
+        {
+            flag.analyze = true;
+            flag.force = true;
+        }
+        else if ((strcmp(s, "set") == 0) ||
+                 (strcmp(s, "edit") == 0))
         {
             dsp->EditBoard();
         }
@@ -1628,6 +1832,17 @@ InputCommand(char *command)
         {
             ok = true;
         }
+#if ttblsz
+        else if (strcmp(s, "memory") == 0)
+        {
+            unsigned int mem, size, t = 1;
+            sscanf(sx, "memory %d", &mem);
+            if(mem > 2048) mem = 2048; /* prevent integer overflow for > 2GB hash */
+            size = (mem << 20) / sizeof(struct hashentry) - rehash;
+            while(t <= size/4) t <<= 1;
+            AllocateTT(t);
+        }
+#endif
         else if (strcmp(s, "go") == 0)
         {
             ok = true;
@@ -1674,6 +1889,10 @@ InputCommand(char *command)
             NewGame();
             dsp->UpdateDisplay(0, 0, 1, 0);
         }
+        else if (strcmp(s, "setboard") == 0)
+        {
+            ReadFEN(sx + 9);
+        }
         else if (strcmp(s, "list") == 0)
         {
             ListGame();
@@ -1702,7 +1921,8 @@ InputCommand(char *command)
         {
             SetMachineTime(sx + strlen("time"));
         }
-        else if (strcmp(s, "otime") == 0)
+        else if ((strcmp(s, "otime") == 0) ||
+                 (xboard && (strcmp(s, "otim")) == 0))
         {
             SetOppTime(sx + strlen("otime"));
         }
@@ -1745,8 +1965,9 @@ InputCommand(char *command)
             flag.force = false;
             Sdepth = 0;
             ok = true;
+            dsp->UpdateDisplay(0, 0, 1, 0);
         }
-        else if (strcmp(s, "black") == 0)
+        else if (xboard ? strcmp(s, "white") == 0 : strcmp(s, "black") == 0)
         {
             computer = white;
             opponent = black;
@@ -1758,7 +1979,7 @@ InputCommand(char *command)
              * ok = true; don't automatically start with black command
              */
         }
-        else if (strcmp(s, "white") == 0)
+        else if (xboard ? strcmp(s, "black") == 0 : strcmp(s, "white") == 0)
         {
             computer = black;
             opponent = white;
@@ -1793,12 +2014,12 @@ InputCommand(char *command)
             BookSave();
         }
 #ifdef EASY_OPENINGS
-        else if ((strcmp(s, "?") == 0)
-                 || (strcmp(s, "!") == 0)
-                 || (strcmp(s, "~") == 0))
+        else if ((strcmp(s, "?") == 0) ||
+                 (strcmp(s, "!") == 0) ||
+                 (strcmp(s, "~") == 0))
 #else
-        else if ((strcmp(s, "?") == 0)
-                 || (strcmp(s, "!") == 0))
+        else if ((strcmp(s, "?") == 0) ||
+                 (strcmp(s, "!") == 0))
 #endif
         {
             FlagMove(*s);
@@ -1835,6 +2056,14 @@ InputCommand(char *command)
         {
             flag.easy = !flag.easy;
         }
+        else if (strcmp(s, "option") == 0)
+        {
+            sscanf(sx, "option tsume=%hd", &flag.tsume) ||
+            sscanf(sx, "option hash=%hd",  &flag.hash)  ||
+            sscanf(sx, "option Hash-file search depth=%hd", &HashDepth)    ||
+            sscanf(sx, "option Hash-file move number=%hd", &HashMoveLimit) ||
+            sscanf(sx, "option contempt=%hd", &contempt);
+        }
         else if (strcmp(s, "tsume") == 0)
         {
             flag.tsume = !flag.tsume;
@@ -1963,4 +2192,6 @@ InputCommand(char *command)
                    ++mycnt2, s, TimeControl.clock[player] * 10);
         }
     }
+
+    return true;
 }