Refined stalemate adjudication in Suicide, some cleanup
authorH.G. Muller <h.g.muller@hccnet.nl>
Fri, 19 Jun 2009 01:35:31 +0000 (18:35 -0700)
committerArun Persaud <arun@nubati.net>
Fri, 19 Jun 2009 01:35:31 +0000 (18:35 -0700)
Refined stalemate adjudication in Suicide, which seems to be not always won
for the stalemated side, but for the side with the smallest number of pieces.
Cleaned up the adjudication code in the process. (backend.c moves.c, moves.h)
Also includes a tiny change in the -autoKibitz format, as requested on
Talkchess.

backend.c
moves.c
moves.h

index 0b1b144..a49464a 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -2277,7 +2277,7 @@ read_from_ics(isr, closure, data, count, error)
                        }\r
                        if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info\r
                            int depth=0; float score;\r
-                           if(sscanf(parse, "%f/%d", &score, &depth) == 2 && depth>0) {\r
+                           if(sscanf(parse, "!!! %f/%d", &score, &depth) == 2 && depth>0) {\r
                                // [HGM] kibitz: save kibitzed opponent info for PGN and eval graph\r
                                pvInfoList[forwardMostMove-1].depth = depth;\r
                                pvInfoList[forwardMostMove-1].score = 100*score;\r
@@ -3750,6 +3750,7 @@ ParseBoard12(string)
                     strcat(parseList[moveNum - 1], "+");\r
                break;\r
              case MT_CHECKMATE:\r
+             case MT_STAINMATE: // [HGM] xq: for notation stalemate that wins counts as checkmate\r
                strcat(parseList[moveNum - 1], "#");\r
                break;\r
            }\r
@@ -5328,6 +5329,7 @@ if(appData.debugMode) fprintf(debugFP, "moveType 2 = %d, promochar = %x\n", move
     case MT_CHECK:\r
       break;\r
     case MT_CHECKMATE:\r
+    case MT_STAINMATE:\r
       if (WhiteOnMove(currentMove)) {\r
        GameEnds(BlackWins, "Black mates", GE_PLAYER);\r
       } else {\r
@@ -5646,7 +5648,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
          if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */\r
                char buf[3*MSG_SIZ];\r
 \r
-               sprintf(buf, "kibitz %+.2f/%d (%.2f sec, %.0f nodes, %1.0f knps) PV=%s\n",\r
+               sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %.0f nodes, %1.0f knps) PV=%s\n",\r
                        programStats.score / 100.,\r
                        programStats.depth,\r
                        programStats.time / 100.,\r
@@ -5713,6 +5715,8 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
                     NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0,\r
                     NrPieces=0, NrPawns=0, PawnAdvance=0, i, j;\r
                static int moveCount = 6;\r
+               ChessMove result;\r
+               char *reason = NULL;\r
 \r
                 /* Count what is on board. */\r
                for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
@@ -5776,9 +5780,9 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
                /* Bare King in Shatranj (loses) or Losers (wins) */\r
                 if( NrW == 1 || NrPieces - NrW == 1) {\r
                   if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first)\r
-                    epStatus[forwardMostMove] = EP_STALEMATE; // kludge to make position claimable as win\r
+                    epStatus[forwardMostMove] = EP_WINS;  // mark as win, so it becomes claimable\r
                     if(appData.checkMates) {\r
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
+                        SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move\r
                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
                          GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
                                                        "Xboard adjudication: Bare king", GE_XBOARD );\r
@@ -5787,7 +5791,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
                  } else\r
                   if( gameInfo.variant == VariantShatranj && --bare < 0)\r
                   {    /* bare King */\r
-                       epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as win for stm\r
+                       epStatus[forwardMostMove] = EP_WINS; // make claimable as win for stm\r
                        if(appData.checkMates) {\r
                            /* but only adjudicate if adjudication enabled */\r
                            SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move\r
@@ -5801,40 +5805,49 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
 \r
 \r
             // don't wait for engine to announce game end if we can judge ourselves\r
-            switch (MateTest(boards[forwardMostMove],\r
-                                 PosFlags(forwardMostMove), epFile,\r
+            switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove), epFile,\r
                                        castlingRights[forwardMostMove]) ) {\r
              case MT_NONE:\r
              case MT_CHECK:\r
              default:\r
                break;\r
              case MT_STALEMATE:\r
-               if(epStatus[forwardMostMove] != EP_CHECKMATE) // [HGM] spare win through baring or K-capt\r
-                   epStatus[forwardMostMove] = EP_STALEMATE;\r
-                if(appData.checkMates) {\r
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                   if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantSuicide\r
-                                                        || gameInfo.variant == VariantGiveaway) // [HGM] losers:\r
-                       GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, // stalemated side wins!\r
-                               "Xboard adjudication: Stalemate", GE_XBOARD );\r
-                   else\r
-                       GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", GE_XBOARD );\r
-                   return;\r
+             case MT_STAINMATE:\r
+               reason = "Xboard adjudication: Stalemate";\r
+               if(epStatus[forwardMostMove] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt\r
+                   epStatus[forwardMostMove] = EP_STALEMATE;   // default result for stalemate is draw\r
+                   if(gameInfo.variant == VariantLosers  || gameInfo.variant == VariantGiveaway) // [HGM] losers:\r
+                       epStatus[forwardMostMove] = EP_WINS;    // in these variants stalemated is always a win\r
+                   else if(gameInfo.variant == VariantSuicide) // in suicide it depends\r
+                       epStatus[forwardMostMove] = NrW == NrPieces-NrW ? EP_STALEMATE :\r
+                                                  ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ?\r
+                                                                       EP_CHECKMATE : EP_WINS);\r
+                   else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi)\r
+                       epStatus[forwardMostMove] = EP_CHECKMATE; // and in these variants being stalemated loses\r
                }\r
                break;\r
              case MT_CHECKMATE:\r
-               epStatus[forwardMostMove] = EP_CHECKMATE;\r
-                if(appData.checkMates) {\r
+               reason = "Xboard adjudication: Checkmate";\r
+               epStatus[forwardMostMove] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE);\r
+               break;\r
+           }\r
+\r
+               switch(i = epStatus[forwardMostMove]) {\r
+                   case EP_STALEMATE:\r
+                       result = GameIsDrawn; break;\r
+                   case EP_CHECKMATE:\r
+                       result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break;\r
+                   case EP_WINS:\r
+                       result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break;\r
+                   default:\r
+                       result = (ChessMove) 0;\r
+               }\r
+                if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested\r
                    SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
                    ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                   GameEnds( WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers) // [HGM] losers:\r
-                            ? BlackWins : WhiteWins,            // reverse the result ( A!=1 is !A for a boolean)\r
-                            "Xboard adjudication: Checkmate", GE_XBOARD );\r
+                   GameEnds( result, reason, GE_XBOARD );\r
                    return;\r
                }\r
-               break;\r
-           }\r
 \r
                 /* Next absolutely insufficient mating material. */\r
                 if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && \r
@@ -5960,7 +5973,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
                                if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase\r
                                    hisPerpetual = PerpetualChase(k, forwardMostMove);\r
                                    ourPerpetual = PerpetualChase(k+1, forwardMostMove);\r
-                                   if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit\r
+                                   if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit\r
                                        GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
                                                      "Xboard adjudication: perpetual chasing", GE_XBOARD );\r
                                        return;\r
@@ -6997,6 +7010,7 @@ ParseGameHistory(game)
                 strcat(parseList[boardIndex - 1], "+");\r
            break;\r
          case MT_CHECKMATE:\r
+         case MT_STAINMATE:\r
            strcat(parseList[boardIndex - 1], "#");\r
            break;\r
        }\r
@@ -7383,6 +7397,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
             strcat(parseList[forwardMostMove - 1], "+");\r
        break;\r
       case MT_CHECKMATE:\r
+      case MT_STAINMATE:\r
        strcat(parseList[forwardMostMove - 1], "#");\r
        break;\r
     }\r
@@ -7750,14 +7765,14 @@ GameEnds(result, resultDetails, whosays)
                // [HGM] losers: because the logic is becoming a bit hairy, determine true result first\r
                if(epStatus[forwardMostMove] == EP_CHECKMATE) {\r
                    /* [HGM] verify: engine mate claims accepted if they were flagged */\r
-                   trueResult = WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers)\r
-                       ? BlackWins : WhiteWins; // [HGM] losers: reverse the result in VariantLosers!\r
+                   trueResult = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins;\r
+               } else\r
+               if(epStatus[forwardMostMove] == EP_WINS) { // added code for games where being mated is a win\r
+                   /* [HGM] verify: engine mate claims accepted if they were flagged */\r
+                   trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;\r
                } else\r
-               if(epStatus[forwardMostMove] == EP_STALEMATE) {\r
+               if(epStatus[forwardMostMove] == EP_STALEMATE) { // only used to indicate draws now\r
                    trueResult = GameIsDrawn; // default; in variants where stalemate loses, Status is CHECKMATE\r
-                   if(gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuicide || \r
-                      gameInfo.variant == VariantLosers)  // [HGM] losers: in giveaway variants stalemate wins\r
-                       trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;\r
                }\r
 \r
                // now verify win claims, but not in drop games, as we don't understand those yet\r
@@ -8369,6 +8384,7 @@ LoadGameOneMove(readAhead)
          case MT_CHECK:\r
            break;\r
          case MT_CHECKMATE:\r
+         case MT_STAINMATE:\r
            if (WhiteOnMove(currentMove)) {\r
                GameEnds(BlackWins, "Black mates", GE_FILE);\r
            } else {\r
@@ -8404,6 +8420,7 @@ LoadGameOneMove(readAhead)
          case MT_CHECK:\r
            break;\r
          case MT_CHECKMATE:\r
+         case MT_STAINMATE:\r
            if (WhiteOnMove(currentMove)) {\r
                GameEnds(BlackWins, "Black mates", GE_FILE);\r
            } else {\r
@@ -8564,6 +8581,7 @@ MakeRegisteredMove()
                break;\r
                \r
              case MT_CHECKMATE:\r
+             case MT_STAINMATE:\r
                if (WhiteOnMove(currentMove)) {\r
                    GameEnds(BlackWins, "Black mates", GE_PLAYER);\r
                } else {\r
diff --git a/moves.c b/moves.c
index c11a8f3..970393f 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -1145,8 +1145,9 @@ int MateTest(board, flags, epfile, castlingRights)
     if (cl.count > 0) {
        return inCheck ? MT_CHECK : MT_NONE;
     } else {
-        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?
-                         MT_CHECKMATE : MT_STALEMATE;
+        return inCheck ? MT_CHECKMATE 
+                      : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj) ? 
+                         MT_STAINMATE : MT_STALEMATE;
     }
 }
 
diff --git a/moves.h b/moves.h
index 73cf604..8d7ea9c 100644 (file)
--- a/moves.h
+++ b/moves.h
@@ -88,6 +88,7 @@ typedef void (*MoveCallback) P((Board board, int flags, ChessMove kind,
 #define EP_RULE_DRAW  (-14)
 #define EP_INSUF_DRAW  (-13)
 #define EP_DRAWS (-10)
+#define EP_WINS (-9)
 #define EP_BEROLIN_A 16        /* [HGM] berolina: add to file if pawn to be taken of a-side of e.p.file */
 #define EP_CHECKMATE 100       /* [HGM] verify: record mates in epStatus for easy claim verification    */
 #define EP_STALEMATE -16
@@ -135,6 +136,7 @@ extern ChessMove LegalityTest P((Board board, int flags, int epfile,
 #define MT_CHECK 1
 #define MT_CHECKMATE 2
 #define MT_STALEMATE 3
+#define MT_STAINMATE 4 /* [HGM] xq: for games where being stalemate counts as a loss */
 
 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
 extern int MateTest P((Board board, int flags, int epfile,