Add quit-after-game checkbox in ICS options dialog XB
[xboard.git] / backend.c
index 618012f..6d243d7 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -388,6 +388,7 @@ PosFlags (index)
   case VariantShatranj:
   case VariantCourier:
   case VariantMakruk:
+  case VariantASEAN:
   case VariantGrand:
     flags &= ~F_ALL_CASTLE_OK;
     break;
@@ -557,6 +558,13 @@ ChessSquare makrukArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatran
         BlackKing, BlackMan, BlackKnight, BlackRook }
 };
 
+ChessSquare aseanArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */
+    { WhiteRook, WhiteKnight, WhiteMan, WhiteFerz,
+        WhiteKing, WhiteMan, WhiteKnight, WhiteRook },
+    { BlackRook, BlackKnight, BlackMan, BlackFerz,
+        BlackKing, BlackMan, BlackKnight, BlackRook }
+};
+
 
 #if (BOARD_FILES>=10)
 ChessSquare ShogiArray[2][BOARD_FILES] = {
@@ -1158,6 +1166,7 @@ InitBackEnd1 ()
       case Variant3Check:     /* should work except for win condition */
       case VariantShatranj:   /* should work except for all win conditions */
       case VariantMakruk:     /* should work except for draw countdown */
+      case VariantASEAN :     /* should work except for draw countdown */
       case VariantBerolina:   /* might work if TestLegality is off */
       case VariantCapaRandom: /* should work */
       case VariantJanus:      /* should work */
@@ -5090,7 +5099,8 @@ SendMoveToICS (ChessMove moveType, int fromX, int fromY, int toX, int toY, char
         break;
       case WhitePromotion:
       case BlackPromotion:
-        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
+        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+           gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
          snprintf(user_move, MSG_SIZ, "%c%c%c%c=%c\n",
                 AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,
                PieceToChar(WhiteFerz));
@@ -5154,7 +5164,7 @@ UploadGameEvent ()
        SendToICS(ics_prefix);
        SendToICS(buf);
        if(startedFromSetupPosition || backwardMostMove != 0) {
-         fen = PositionToFEN(backwardMostMove, NULL);
+         fen = PositionToFEN(backwardMostMove, NULL, 1);
          if(ics_type == ICS_ICC) { // on ICC we can simply send a complete FEN to set everything
            snprintf(buf, MSG_SIZ,"loadfen %s\n", fen);
            SendToICS(buf);
@@ -5899,9 +5909,13 @@ InitPosition (int redraw)
     case VariantMakruk:
       pieces = makrukArray;
       nrCastlingRights = 0;
-      startedFromSetupPosition = TRUE;
       SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk");
       break;
+    case VariantASEAN:
+      pieces = aseanArray;
+      nrCastlingRights = 0;
+      SetCharTable(pieceToChar, "PN.R.Q....BKpn.r.q....bk");
+      break;
     case VariantTwoKings:
       pieces = twoKingsArray;
       break;
@@ -6030,7 +6044,7 @@ InitPosition (int redraw)
 
     pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
     if(pawnRow < 1) pawnRow = 1;
-    if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) pawnRow = 2;
+    if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN || gameInfo.variant == VariantGrand) pawnRow = 2;
 
     /* User pieceToChar list overrules defaults */
     if(appData.pieceToCharTable != NULL)
@@ -6139,7 +6153,7 @@ SendBoard (ChessProgramState *cps, int moveNum)
     char message[MSG_SIZ];
 
     if (cps->useSetboard) {
-      char* fen = PositionToFEN(moveNum, cps->fenOverride);
+      char* fen = PositionToFEN(moveNum, cps->fenOverride, 1);
       snprintf(message, MSG_SIZ,"setboard %s\n", fen);
       SendToProgram(message, cps);
       free(fen);
@@ -6322,7 +6336,8 @@ ChessSquare
 DefaultPromoChoice (int white)
 {
     ChessSquare result;
-    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
+    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+       gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
        result = WhiteFerz; // no choice
     else if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway)
        result= WhiteKing; // in Suicide Q is the last thing we want
@@ -6407,7 +6422,8 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i
     }
 
     // we either have a choice what to promote to, or (in Shogi) whether to promote
-    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) {
+    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+       gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) {
        *promoChoice = PieceToChar(BlackFerz);  // no choice
        return FALSE;
     }
@@ -7053,7 +7069,7 @@ CanPromote (ChessSquare piece, int y)
        if(gameInfo.variant == VariantShogi    || gameInfo.variant == VariantXiangqi ||
           gameInfo.variant == VariantSuper    || gameInfo.variant == VariantGreat   ||
           gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
-                                                 gameInfo.variant == VariantMakruk) return FALSE;
+         gameInfo.variant == VariantMakruk   || gameInfo.variant == VariantASEAN) return FALSE;
        return (piece == BlackPawn && y == 1 ||
                piece == WhitePawn && y == BOARD_HEIGHT-2 ||
                piece == BlackLance && y == 1 ||
@@ -8289,6 +8305,17 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
 
        MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
 
+        /* Test suites abort the 'game' after one move */
+        if(*appData.finger) {
+           static FILE *f;
+           char *fen = PositionToFEN(backwardMostMove, NULL, 0); // no counts in EPD
+           if(!f) f = fopen(appData.finger, "w");
+           if(f) fprintf(f, "%s bm %s;\n", fen, parseList[backwardMostMove]), fflush(f);
+           else { DisplayFatalError("Bad output file", errno, 0); return; }
+           free(fen);
+           GameEnds(GameUnfinished, NULL, GE_XBOARD);
+        }
+
         /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */
         if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
             int count = 0;
@@ -10834,6 +10861,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays)
                    PlayIcsUnfinishedSound();
                }
            }
+           if(appData.quitNext) { ExitEvent(0); return; }
        } else if (gameMode == EditGame ||
                   gameMode == PlayFromGameFile ||
                   gameMode == AnalyzeMode ||
@@ -11184,11 +11212,17 @@ AutoPlayOneMove ()
     if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile)
       return FALSE;
 
-    if (gameMode == AnalyzeFile && currentMove > backwardMostMove) {
+    if (gameMode == AnalyzeFile && currentMove > backwardMostMove && programStats.depth) {
       pvInfoList[currentMove].depth = programStats.depth;
       pvInfoList[currentMove].score = programStats.score;
       pvInfoList[currentMove].time  = 0;
       if(currentMove < forwardMostMove) AppendComment(currentMove+1, lastPV[0], 2);
+      else { // append analysis of final position as comment
+       char buf[MSG_SIZ];
+       snprintf(buf, MSG_SIZ, "{final score %+4.2f/%d}", programStats.score/100., programStats.depth);
+       AppendComment(currentMove, buf, 3); // the 3 prevents stripping of the score/depth!
+      }
+      programStats.depth = 0;
     }
 
     if (currentMove >= forwardMostMove) {
@@ -12812,7 +12846,7 @@ SaveGamePGN (FILE *f)
     if(appData.numberTag && matchMode) fprintf(f, "[Number \"%d\"]\n", nextGame+1); // [HGM] number tag
 
     if (backwardMostMove > 0 || startedFromSetupPosition) {
-        char *fen = PositionToFEN(backwardMostMove, NULL);
+        char *fen = PositionToFEN(backwardMostMove, NULL, 1);
         fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen);
        fprintf(f, "\n{--------------\n");
        PrintPosition(f, backwardMostMove);
@@ -13081,7 +13115,7 @@ SavePosition (FILE *f, int dummy, char *dummy2)
        PrintPosition(f, currentMove);
        fprintf(f, "--------------]\n");
     } else {
-       fen = PositionToFEN(currentMove, NULL);
+       fen = PositionToFEN(currentMove, NULL, 1);
        fprintf(f, "%s\n", fen);
        free(fen);
     }
@@ -14502,6 +14536,7 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y)
         if(gameInfo.variant == VariantShatranj ||
            gameInfo.variant == VariantXiangqi  ||
            gameInfo.variant == VariantCourier  ||
+           gameInfo.variant == VariantASEAN    ||
            gameInfo.variant == VariantMakruk     )
             selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);
         goto defaultlabel;
@@ -15526,7 +15561,8 @@ AppendComment (int index, char *text, Boolean addBraces)
     int oldlen, len;
     char *old;
 
-if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); fflush(debugFP);
+if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces);
+    if(addBraces == 3) addBraces = 0; else // force appending literally
     text = GetInfoFromComment( index, text ); /* [HGM] PV time: strip PV info from comment */
 
     CrushCRs(text);
@@ -15627,6 +15663,7 @@ GetInfoFromComment (int index, char * text)
             }
 
             p = text;
+            if(!strncmp(p+1, "final score ", 12)) p += 12, index++; else
             if(p[1] == '(') { // comment starts with PV
                p = strchr(p, ')'); // locate end of PV
                if(p == NULL || sep < p+5) return text;
@@ -16993,7 +17030,7 @@ PGNDate ()
 
 
 char *
-PositionToFEN (int move, char *overrideCastling)
+PositionToFEN (int move, char *overrideCastling, int moveCounts)
 {
     int i, j, fromX, fromY, toX, toY;
     int whiteToPlay;
@@ -17123,7 +17160,8 @@ PositionToFEN (int move, char *overrideCastling)
   }
 
   if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
-     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
+     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&
+     gameInfo.variant != VariantMakruk   && gameInfo.variant != VariantASEAN ) {
     /* En passant target square */
     if (move > backwardMostMove) {
         fromX = moveList[move - 1][0] - AAA;
@@ -17155,9 +17193,10 @@ PositionToFEN (int move, char *overrideCastling)
   }
   }
 
-    /* [HGM] find reversible plies */
+    if(moveCounts)
     {   int i = 0, j=move;
 
+        /* [HGM] find reversible plies */
         if (appData.debugMode) { int k;
             fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);
             for(k=backwardMostMove; k<=forwardMostMove; k++)
@@ -17169,9 +17208,10 @@ PositionToFEN (int move, char *overrideCastling)
         if( j == backwardMostMove ) i += initialRulePlies;
         sprintf(p, "%d ", i);
         p += i>=100 ? 4 : i >= 10 ? 3 : 2;
-    }
-    /* Fullmove number */
-    sprintf(p, "%d", (move / 2) + 1);
+
+        /* Fullmove number */
+        sprintf(p, "%d", (move / 2) + 1);
+    } else *--p = NULLCHAR;
 
     return StrSave(buf);
 }
@@ -17407,7 +17447,8 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen)
 
     /* read e.p. field in games that know e.p. capture */
     if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
-       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
+       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&
+       gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN ) {
       if(*p=='-') {
         p++; board[EP_STATUS] = EP_NONE;
       } else {