allowe parsing / disambiguation of SAN moves like Xe4 in certain situations
[xboard.git] / backend.c
index 06796c1..e608307 100755 (executable)
--- a/backend.c
+++ b/backend.c
@@ -607,7 +607,7 @@ InitBackEnd1()
     ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options
 
     GetTimeMark(&programStartTime);
-    srand(programStartTime.ms); // [HGM] book: makes sure random is unpredictabe to msec level
+    srandom(programStartTime.ms); // [HGM] book: makes sure random is unpredictabe to msec level
 
     ClearProgramStats();
     programStats.ok_to_send = 1;
@@ -1042,6 +1042,7 @@ InitBackEnd2()
        fprintf(debugFP, "%s\n", programVersion);
     }
 
+    set_cont_sequence(appData.wrapContSeq);
     if (appData.matchGames > 0) {
        appData.matchMode = TRUE;
     } else if (appData.matchMode) {
@@ -1976,7 +1977,7 @@ VariantSwitch(Board board, VariantClass newVariant)
      case VariantSuper:
        newHoldingsWidth = 2;
        gameInfo.holdingsSize = 8;
-       return;
+       break;
      case VariantGothic:
      case VariantCapablanca:
      case VariantCapaRandom:
@@ -2010,10 +2011,8 @@ VariantSwitch(Board board, VariantClass newVariant)
      gameInfo.holdingsWidth = newHoldingsWidth;
      gameInfo.variant = newVariant;
      InitDrawingSizes(-2, 0);
-     InitPosition(FALSE);          /* this sets up board[0], but also other stuff        */
-   } else { gameInfo.variant = newVariant; InitPosition(FALSE); }
-   
-   DrawPosition(TRUE, boards[currentMove]);
+     InitPosition(TRUE);          /* this sets up board[0], but also other stuff        */
+   } else { gameInfo.variant = newVariant; InitPosition(TRUE); }
 }
 
 static int loggedOn = FALSE;
@@ -2730,7 +2729,7 @@ read_from_ics(isr, closure, data, count, error)
                           moves and soak them up so user can step
                           through them and/or save them.
                           */
-                       Reset(FALSE, TRUE);
+                       Reset(TRUE, TRUE);
                        gameMode = IcsObserving;
                        ModeHighlight();
                        ics_gamenum = -1;
@@ -3280,7 +3279,13 @@ read_from_ics(isr, closure, data, count, error)
                            * to move the position two files to the right to
                            * create room for them!
                            */
-                          VariantSwitch(boards[currentMove], VariantCrazyhouse); /* temp guess */
+                         VariantClass newVariant;
+                         switch(gameInfo.boardWidth) { // base guess on board width
+                               case 9:  newVariant = VariantShogi; break;
+                               case 10: newVariant = VariantGreat; break;
+                               default: newVariant = VariantCrazyhouse; break;
+                         }
+                          VariantSwitch(boards[currentMove], newVariant); /* temp guess */
                          /* Get a move list just to see the header, which
                             will tell us whether this is really bug or zh */
                          if (ics_getting_history == H_FALSE) {
@@ -3390,6 +3395,7 @@ ParseBoard12(string)
     char promoChar;
     int ranks=1, files=0; /* [HGM] ICS80: allow variable board size */
     char *bookHit = NULL; // [HGM] book
+    Boolean weird = FALSE;
 
     fromX = fromY = toX = toY = -1;
     
@@ -3405,6 +3411,7 @@ ParseBoard12(string)
         while(i < 199 && (string[i] != ' ' || string[i+2] != ' ')) {
            if(string[i] == ' ') { ranks++; files = 0; }
             else files++;
+           if(!strchr(" -pnbrqkPNBRQK" , string[i])) weird = TRUE; // test for fairies
            i++;
        }
        for(j = 0; j <i; j++) board_chars[j] = string[j];
@@ -3418,6 +3425,27 @@ ParseBoard12(string)
               &moveNum, str, elapsed_time, move_str, &ics_flip,
               &ticking);
 
+   if (gameInfo.boardHeight != ranks || gameInfo.boardWidth != files || 
+                                       weird && (int)gameInfo.variant <= (int)VariantShogi) {
+     /* [HGM] We seem to switch variant during a game!
+      * Try to guess new variant from board size
+      */
+         VariantClass newVariant = VariantFairy; // if 8x8, but fairies present
+         if(ranks == 8 && files == 10) newVariant = VariantCapablanca; else
+         if(ranks == 10 && files == 9) newVariant = VariantXiangqi; else
+         if(ranks == 8 && files == 12) newVariant = VariantCourier; else
+         if(ranks == 9 && files == 9)  newVariant = VariantShogi; else
+         if(!weird) newVariant = VariantNormal;
+          VariantSwitch(boards[currentMove], newVariant); /* temp guess */
+         /* Get a move list just to see the header, which
+            will tell us whether this is really bug or zh */
+         if (ics_getting_history == H_FALSE) {
+           ics_getting_history = H_REQUESTED;
+           sprintf(str, "%smoves %d\n", ics_prefix, gamenum);
+           SendToICS(str);
+         }
+    }
+
     if (n < 21) {
         snprintf(str, sizeof(str), _("Failed to parse board string:\n\"%s\""), string);
        DisplayError(str, 0);
@@ -3502,7 +3530,7 @@ ParseBoard12(string)
        
        /* Forget the old game and get the history (if any) of the new one */
        if (gameMode != BeginningOfGame) {
-         Reset(FALSE, TRUE);
+         Reset(TRUE, TRUE);
        }
        newGame = TRUE;
        if (appData.autoRaiseBoard) BoardToTop();
@@ -6394,7 +6422,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
             DisplayError(_("Bad FEN received from engine"), 0);
             return ;
         } else {
-           Reset(FALSE, FALSE);
+           Reset(TRUE, FALSE);
            CopyBoard(boards[0], initial_position);
            initialRulePlies = FENrulePlies;
            epStatus[0] = FENepStatus;
@@ -7513,14 +7541,20 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
         p = (int) fromX;
         if(p < (int) BlackPawn) { /* white drop */
              p -= (int)WhitePawn;
+                p = PieceToNumber((ChessSquare)p);
              if(p >= gameInfo.holdingsSize) p = 0;
-             if(--board[p][BOARD_WIDTH-2] == 0)
+             if(--board[p][BOARD_WIDTH-2] <= 0)
                   board[p][BOARD_WIDTH-1] = EmptySquare;
+             if((int)board[p][BOARD_WIDTH-2] < 0)
+                       board[p][BOARD_WIDTH-2] = 0;
         } else {                  /* black drop */
              p -= (int)BlackPawn;
+                p = PieceToNumber((ChessSquare)p);
              if(p >= gameInfo.holdingsSize) p = 0;
-             if(--board[BOARD_HEIGHT-1-p][1] == 0)
+             if(--board[BOARD_HEIGHT-1-p][1] <= 0)
                   board[BOARD_HEIGHT-1-p][0] = EmptySquare;
+             if((int)board[BOARD_HEIGHT-1-p][1] < 0)
+                       board[BOARD_HEIGHT-1-p][1] = 0;
         }
       }
       if (captured != EmptySquare && gameInfo.holdingsSize > 0
@@ -7554,7 +7588,6 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
           board[BOARD_HEIGHT-1-p][0] = WHITE_TO_BLACK captured;
        }
       }
-
     } else if (gameInfo.variant == VariantAtomic) {
       if (captured != EmptySquare) {
        int y, x;
@@ -7932,7 +7965,7 @@ TwoMachinesEventIfReady P((void))
 void
 NextMatchGame P((void))
 {
-    int index; /* [HGM] autoinc: step lod index during match */
+    int index; /* [HGM] autoinc: step load index during match */
     Reset(FALSE, TRUE);
     if (*appData.loadGameFile != NULLCHAR) {
        index = appData.loadGameIndex;
@@ -10924,7 +10957,9 @@ TwoMachinesEvent P((void))
 
        strcpy(bookMove, "move ");
        strcat(bookMove, bookHit);
-       HandleMachineMove(bookMove, &first);
+       savedMessage = bookMove; // args for deferred call
+       savedState = onmove;
+       ScheduleDelayedEvent(DeferredBookMove, 1);
     }
 }
 
@@ -13968,3 +14003,110 @@ EditPositionPasteFEN(char *fen)
     }
   }
 }
+
+static char cseq[12] = "\\   ";
+
+Boolean set_cont_sequence(char *new_seq)
+{
+    int len;
+    Boolean ret;
+
+    // handle bad attempts to set the sequence
+       if (!new_seq)
+               return 0; // acceptable error - no debug
+
+    len = strlen(new_seq);
+    ret = (len > 0) && (len < sizeof(cseq));
+    if (ret)
+        strcpy(cseq, new_seq);
+    else if (appData.debugMode)
+        fprintf(debugFP, "Invalid continuation sequence \"%s\"  (maximum length is: %d)\n", new_seq, sizeof(cseq)-1);
+    return ret;
+}
+
+/*
+    reformat a source message so words don't cross the width boundary.  internal
+    newlines are not removed.  returns the wrapped size (no null character unless
+    included in source message).  If dest is NULL, only calculate the size required
+    for the dest buffer.  lp argument indicats line position upon entry, and it's
+    passed back upon exit.
+*/
+int wrap(char *dest, char *src, int count, int width, int *lp)
+{
+    int len, i, ansi, cseq_len, line, old_line, old_i, old_len, clen;
+
+    cseq_len = strlen(cseq);
+    old_line = line = *lp;
+    ansi = len = clen = 0;
+
+    for (i=0; i < count; i++)
+    {
+        if (src[i] == '\033')
+            ansi = 1;
+
+        // if we hit the width, back up
+        if (!ansi && (line >= width) && src[i] != '\n' && src[i] != ' ')
+        {
+            // store i & len in case the word is too long
+            old_i = i, old_len = len;
+
+            // find the end of the last word
+            while (i && src[i] != ' ' && src[i] != '\n')
+            {
+                i--;
+                len--;
+            }
+
+            // word too long?  restore i & len before splitting it
+            if ((old_i-i+clen) >= width)
+            {
+                i = old_i;
+                len = old_len;
+            }
+
+            // extra space?
+            if (i && src[i-1] == ' ')
+                len--;
+
+            if (src[i] != ' ' && src[i] != '\n')
+            {
+                i--;
+                if (len)
+                    len--;
+            }
+
+            // now append the newline and continuation sequence
+            if (dest)
+                dest[len] = '\n';
+            len++;
+            if (dest)
+                strncpy(dest+len, cseq, cseq_len);
+            len += cseq_len;
+            line = cseq_len;
+            clen = cseq_len;
+            continue;
+        }
+
+        if (dest)
+            dest[len] = src[i];
+        len++;
+        if (!ansi)
+            line++;
+        if (src[i] == '\n')
+            line = 0;
+        if (src[i] == 'm')
+            ansi = 0;
+    }
+    if (dest && appData.debugMode)
+    {
+        fprintf(debugFP, "wrap(count:%d,width:%d,line:%d,len:%d,*lp:%d,src: ",
+            count, width, line, len, *lp);
+        show_bytes(debugFP, src, count);
+        fprintf(debugFP, "\ndest: ");
+        show_bytes(debugFP, dest, len);
+        fprintf(debugFP, "\n");
+    }
+    *lp = dest ? line : old_line;
+
+    return len;
+}