Prevent transmission of spurious promo char to other engine
[xboard.git] / backend.c
index d4549bf..b124be6 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -131,9 +131,16 @@ extern int gettimeofday(struct timeval *, struct timezone *);
 #ifdef ENABLE_NLS 
 # define _(s) gettext (s) 
 # define N_(s) gettext_noop (s) 
+# define T_(s) gettext(s)
 #else 
-# define _(s) (s) 
-# define N_(s) s 
+# ifdef WIN32
+#   define _(s) T_(s)
+#   define N_(s) s
+# else
+#   define _(s) (s) 
+#   define N_(s) s 
+#   define T_(s) s
+# endif
 #endif 
 
 
@@ -714,8 +721,8 @@ InitBackEnd1()
     /* [AS] Adjudication threshold */
     adjudicateLossThreshold = appData.adjudicateLossThreshold;
     
-    first.which = "first";
-    second.which = "second";
+    first.which = _("first");
+    second.which = _("second");
     first.maybeThinking = second.maybeThinking = FALSE;
     first.pr = second.pr = NoProc;
     first.isr = second.isr = NULL;
@@ -2206,8 +2213,8 @@ MatchSoughtLine(char *line)
 int
 DrawSeekGraph()
 {
-    if(!seekGraphUp) return FALSE;
     int i;
+    if(!seekGraphUp) return FALSE;
     h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
     w = BOARD_WIDTH  * (squareSize + lineGap) + lineGap;
 
@@ -4568,6 +4575,10 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY)
       /* POP Fabien */
        sprintf(user_move, "o-o-o\n");
        break;
+      case WhiteNonPromotion:
+      case BlackNonPromotion:
+        sprintf(user_move, "%c%c%c%c=\n", AAA + fromX, ONE + fromY, AAA + toX, ONE + toY);
+        break;
       case WhitePromotionQueen:
       case BlackPromotionQueen:
       case WhitePromotionRook:
@@ -4796,6 +4807,8 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
       case BlackPromotionKnight:
       case WhitePromotionKing:
       case BlackPromotionKing:
+      case WhiteNonPromotion:
+      case BlackNonPromotion:
       case NormalMove:
       case WhiteCapturesEnPassant:
       case BlackCapturesEnPassant:
@@ -6595,8 +6608,9 @@ Count(Board board, int pCnt[], int *nW, int *nB, int *wStale, int *bStale, int *
        for(p=WhitePawn; p<=EmptySquare; p++) pCnt[p] = 0;
        for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
                p = board[r][f];
+               pCnt[p]++;
                if(p == WhitePawn && r == BOARD_HEIGHT-1) (*wStale)++; else
-               if(p == BlackPawn && r == 0) (*bStale)++; else pCnt[p]++; // count last-Rank Pawns (XQ) separately
+               if(p == BlackPawn && r == 0) (*bStale)++; // count last-Rank Pawns (XQ) separately
                if(p <= WhiteKing) (*nW)++; else if(p <= BlackKing) (*nB)++;
                if(p == WhiteBishop || p == WhiteFerz || p == WhiteAlfil ||
                   p == BlackBishop || p == BlackFerz || p == BlackAlfil   )
@@ -6605,6 +6619,35 @@ Count(Board board, int pCnt[], int *nW, int *nB, int *wStale, int *bStale, int *
 }
 
 int
+SufficientDefence(int pCnt[], int side, int nMine, int nHis)
+{
+       int myPawns = pCnt[WhitePawn+side]; // my total Pawn count;
+       int majorDefense = pCnt[BlackRook-side] + pCnt[BlackCannon-side] + pCnt[BlackKnight-side];
+                  
+       nMine -= pCnt[WhiteFerz+side] + pCnt[WhiteAlfil+side]; // discount defenders
+       if(nMine - myPawns > 2) return FALSE; // no trivial draws with more than 1 major
+       if(myPawns == 2 && nMine == 3) // KPP
+           return majorDefense || pCnt[BlackFerz-side] + pCnt[BlackAlfil-side] >= 3;
+       if(myPawns == 1 && nMine == 2) // KP
+           return majorDefense || pCnt[BlackFerz-side] + pCnt[BlackAlfil-side]  + pCnt[BlackPawn-side] >= 1;
+       if(myPawns == 1 && nMine == 3 && pCnt[WhiteKnight+side]) // KHP
+           return majorDefense || pCnt[BlackFerz-side] + pCnt[BlackAlfil-side]*2 >= 5;
+       if(myPawns) return FALSE;
+       if(pCnt[WhiteRook+side])
+           return pCnt[BlackRook-side] || 
+                  pCnt[BlackCannon-side] && (pCnt[BlackFerz-side] >= 2 || pCnt[BlackAlfil-side] >= 2) ||
+                  pCnt[BlackKnight-side] && pCnt[BlackFerz-side] + pCnt[BlackAlfil-side] > 2 ||
+                  pCnt[BlackFerz-side] + pCnt[BlackAlfil-side] >= 4;
+       if(pCnt[WhiteCannon+side]) {
+           if(pCnt[WhiteFerz+side] + myPawns == 0) return TRUE; // Cannon needs platform
+           return majorDefense || pCnt[BlackAlfil-side] >= 2;
+       }
+       if(pCnt[WhiteKnight+side])
+           return majorDefense || pCnt[BlackFerz-side] >= 2 || pCnt[BlackAlfil-side] + pCnt[BlackPawn-side] >= 1;
+       return FALSE;
+}
+
+int
 MatingPotential(int pCnt[], int side, int nMine, int nHis, int stale, int bisColor)
 {
        VariantClass v = gameInfo.variant;
@@ -6798,12 +6841,14 @@ Adjudicate(ChessProgramState *cps)
                 }
 
                 /* Then some trivial draws (only adjudicate, cannot be claimed) */
-                if(nrW + nrB == 4 && 
+                if(gameInfo.variant == VariantXiangqi ?
+                       SufficientDefence(nr, WhitePawn, nrW, nrB) && SufficientDefence(nr, BlackPawn, nrB, nrW)
+                 : nrW + nrB == 4 && 
                    (   nr[WhiteRook] == 1 && nr[BlackRook] == 1 /* KRKR */
                    || nr[WhiteQueen] && nr[BlackQueen]==1     /* KQKQ */
                    || nr[WhiteKnight]==2 || nr[BlackKnight]==2     /* KNNK */
                    || nr[WhiteKnight]+nr[WhiteBishop] == 1 && nr[BlackKnight]+nr[BlackBishop] == 1 /* KBKN, KBKB, KNKN */
-                  ) ) {
+                   ) ) {
                      if(--moveCount < 0 && appData.trivialDraws && canAdjudicate)
                      {    /* if the first 3 moves do not show a tactical win, declare draw */
                          if(engineOpponent) {
@@ -8131,6 +8176,8 @@ ParseGameHistory(game)
          case BlackPromotionKnight:
          case WhitePromotionKing:
          case BlackPromotionKing:
+         case WhiteNonPromotion:
+         case BlackNonPromotion:
          case NormalMove:
          case WhiteCapturesEnPassant:
          case BlackCapturesEnPassant:
@@ -9334,7 +9381,12 @@ GameEnds(result, resultDetails, whosays)
     gameMode = nextGameMode;
     ModeHighlight();
     endingGame = 0;  /* [HGM] crash */
-    if(popupRequested) DisplayFatalError(buf, 0, 0); // [HGM] crash: this call GameEnds recursively through ExitEvent! Make it a harmless tail recursion.
+    if(popupRequested) { // [HGM] crash: this calls GameEnds recursively through ExitEvent! Make it a harmless tail recursion.
+      if(matchMode == TRUE) DisplayFatalError(buf, 0, 0); else {
+       matchMode = FALSE; appData.matchGames = matchGame = 0;
+       DisplayNote(buf);
+      }
+    }
 }
 
 /* Assumes program was just initialized (initString sent).
@@ -9602,6 +9654,8 @@ LoadGameOneMove(readAhead)
       case BlackPromotionKnight:
       case WhitePromotionKing:
       case BlackPromotionKing:
+      case WhiteNonPromotion:
+      case BlackNonPromotion:
       case NormalMove:
       case WhiteKingSideCastle:
       case WhiteQueenSideCastle:
@@ -13970,7 +14024,7 @@ DisplayMove(moveNumber)
            sprintf(res, " %s", PGNResult(gameInfo.result));
        } else {
            sprintf(res, " {%s} %s",
-                   gameInfo.resultDetails, PGNResult(gameInfo.result));
+                   T_(gameInfo.resultDetails), PGNResult(gameInfo.result));
        }
     } else {
        res[0] = NULLCHAR;
@@ -14762,7 +14816,7 @@ ParseFEN(board, blackPlaysFirst, fen)
      char *fen;
 {
     int i, j;
-    char *p;
+    char *p, c;
     int emptycount;
     ChessSquare piece;
 
@@ -14855,7 +14909,12 @@ ParseFEN(board, blackPlaysFirst, fen)
     while(*p == ' ') p++;
 
     /* Active color */
-    switch (*p++) {
+    c = *p++;
+    if(appData.colorNickNames) {
+      if( c == appData.colorNickNames[0] ) c = 'w'; else
+      if( c == appData.colorNickNames[1] ) c = 'b';
+    }
+    switch (c) {
       case 'w':
         *blackPlaysFirst = FALSE;
        break;