X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=7749cba8bbd330dc59533d06ed021076498fc2a1;hb=1c76e2f7041aae8763d5ef06578e1d93e9bc900d;hp=9c734eb1979f4519dc05a175f0f752dbf3ff97b0;hpb=0bf664e507241790adc9f419b24be4d1d5963b28;p=xboard.git diff --git a/backend.c b/backend.c index 9c734eb..7749cba 100644 --- a/backend.c +++ b/backend.c @@ -5,7 +5,7 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -296,6 +296,8 @@ int promoDefaultAltered; int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */ static int initPing = -1; int border; /* [HGM] width of board rim, needed to size seek graph */ +char bestMove[MSG_SIZ]; +int solvingTime, totalTime; /* States for ics_getting_history */ #define H_FALSE 0 @@ -5228,7 +5230,7 @@ SendMoveToICS (ChessMove moveType, int fromX, int fromY, int toX, int toY, char case WhitePromotion: case BlackPromotion: if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || - gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) + gameInfo.variant == VariantMakruk) snprintf(user_move, MSG_SIZ, "%c%c%c%c=%c\n", AAA + fromX, ONE + fromY, AAA + toX, ONE + toY, PieceToChar(WhiteFerz)); @@ -5334,11 +5336,11 @@ UploadGameEvent () SendToICS(ics_type == ICS_ICC ? "tag result Game in progress\n" : "commit\n"); } -int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove +int killX = -1, killY = -1, kill2X = -1, kill2Y = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove int legNr = 1; void -CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7]) +CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[9]) { if (rf == DROP_RANK) { if(ff == EmptySquare) sprintf(move, "@@@@\n"); else // [HGM] pass @@ -5348,7 +5350,10 @@ CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char if (promoChar == 'x' || promoChar == NULLCHAR) { sprintf(move, "%c%c%c%c\n", AAA + ff, ONE + rf, AAA + ft, ONE + rt); - if(killX >= 0 && killY >= 0) sprintf(move+4, ";%c%c\n", AAA + killX, ONE + killY); + if(killX >= 0 && killY >= 0) { + sprintf(move+4, ";%c%c\n", AAA + killX, ONE + killY); + if(kill2X >= 0 && kill2Y >= 0) sprintf(move+7, "%c%c\n", AAA + killX, ONE + killY); + } } else { sprintf(move, "%c%c%c%c%c\n", AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar); @@ -5976,7 +5981,7 @@ SetCharTableEsc (unsigned char *table, const char * map, char * escapes) table[(int) WhiteKing] = map[j++]; for( i=0; i= 0) snprintf(move, MSG_SIZ, "%c%dx%c%d-%c%d", fromX + AAA, fromY + ONE - '0', killX + AAA, killY + ONE - '0', toX + AAA, toY + ONE - '0'); snprintf(buf, MSG_SIZ, " 0.0%% 1 %s\n", move); AddBookMove(buf); addToBookFlag = FALSE; @@ -7357,7 +7365,7 @@ CanPromote (ChessSquare piece, int y) if(IS_SHOGI(gameInfo.variant) || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || - gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) return FALSE; + gameInfo.variant == VariantMakruk) return FALSE; return (piece == BlackPawn && y <= zone || piece == WhitePawn && y >= BOARD_HEIGHT-1-zone || piece == BlackLance && y <= zone || @@ -7706,7 +7714,9 @@ printf("(%d,%d)-(%d,%d) %d %d\n",fromX,fromY,toX,toY,x,y); if(marker[y][x] == 5) { // [HGM] lion: this was the release of a to-click or drag on a cyan square dragging *= 2; // flag button-less dragging if we are dragging MarkTargetSquares(1); - if(x == killX && y == killY) killX = killY = -1; else { + if(x == killX && y == killY) killX = kill2X, killY = kill2Y, kill2X = kill2Y = -1; // cancel last kill + else { + kill2X = killX; kill2Y = killY; killX = x; killY = y; //remeber this square as intermediate ReportClick("put", x, y); // and inform engine ReportClick("lift", x, y); @@ -8099,7 +8109,7 @@ Adjudicate (ChessProgramState *cps) // most tests only when we understand the game, i.e. legality-checking on if( appData.testLegality ) { /* [HGM] Some more adjudications for obstinate engines */ - int nrW, nrB, bishopColor, staleW, staleB, nr[EmptySquare+1], i; + int nrW, nrB, bishopColor, staleW, staleB, nr[EmptySquare+2], i; static int moveCount = 6; ChessMove result; char *reason = NULL; @@ -8691,11 +8701,16 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(cps->alphaRank) AlphaRank(machineMove, 4); // [HGM] lion: (some very limited) support for Alien protocol - killX = killY = -1; + killX = killY = kill2X = kill2Y = -1; if(machineMove[strlen(machineMove)-1] == ',') { // move ends in coma: non-final leg of composite move safeStrCpy(firstLeg, machineMove, 20); // just remember it for processing when second leg arrives return; - } else if(firstLeg[0]) { // there was a previous leg; + } + if(p = strchr(machineMove, ',')) { // we got both legs in one (happens on book move) + safeStrCpy(firstLeg, machineMove, 20); // kludge: fake we received the first leg earlier, and clip it off + safeStrCpy(machineMove, firstLeg + (p - machineMove) + 1, 20); + } + if(firstLeg[0]) { // there was a previous leg; // only support case where same piece makes two step char buf[20], *p = machineMove+1, *q = buf+1, f; safeStrCpy(buf, machineMove, 20); @@ -8714,8 +8729,8 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h snprintf(buf1, MSG_SIZ*10, _("Illegal move \"%s\" from %s machine"), machineMove, _(cps->which)); DisplayMoveError(buf1); - snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c via %c%c) res=%d", - machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, killX+AAA, killY+ONE, moveType); + snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c via %c%c, %c%c) res=%d", + machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, killX+AAA, killY+ONE, kill2X+AAA, kill2Y+ONE, moveType); if (gameMode == TwoMachinesPlay) { GameEnds(machineWhite ? BlackWins : WhiteWins, buf1, GE_XBOARD); @@ -8780,6 +8795,17 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h free(fen); GameEnds(GameUnfinished, NULL, GE_XBOARD); } + if(appData.epd) { + if(solvingTime >= 0) { + snprintf(buf1, MSG_SIZ, "%d. %4.2fs\n", matchGame, solvingTime/100.); + totalTime += solvingTime; first.matchWins++; + } else { + snprintf(buf1, MSG_SIZ, "%d. wrong (%s)\n", matchGame, parseList[backwardMostMove]); + second.matchWins++; + } + OutputKibitz(2, buf1); + GameEnds(GameUnfinished, NULL, GE_XBOARD); + } /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */ if( gameMode == TwoMachinesPlay && appData.adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) { @@ -8954,9 +8980,10 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } if(sscanf(message, "piece %s %s", buf2, buf1) == 2) { ChessSquare piece = WhitePawn; - char *p=buf2; - if(*p == '+') piece = CHUPROMOTED WhitePawn, p++; - piece += CharToPiece(*p) - WhitePawn; + char *p=message+6, *q, *s = SUFFIXES, ID = *p; + if(*p == '+') piece = CHUPROMOTED WhitePawn, ID = *++p; + if(q = strchr(s, p[1])) ID += 64*(q - s + 1), p++; + piece += CharToPiece(ID & 255) - WhitePawn; if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR /* always accept definition of */ && piece != WhiteFalcon && piece != BlackFalcon /* wild-card pieces. */ && piece != WhiteCobra && piece != BlackCobra @@ -8968,7 +8995,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(piece < EmptySquare) { pieceDefs = TRUE; ASSIGN(pieceDesc[piece], buf1); - if(isupper(*p) && p[1] == '&') { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], buf1); } + if((ID & 32) == 0 && p[1] == '&') { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], buf1); } } return; } @@ -9091,7 +9118,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h return; } if(!strncmp(message, "highlight ", 10)) { - if(appData.testLegality && appData.markers) return; + if(appData.testLegality && !*engineVariant && appData.markers) return; MarkByFEN(message+10); // [HGM] alien: allow engine to mark board squares return; } @@ -9506,6 +9533,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h buf1[0] = NULLCHAR; if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n", &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) { + char score_buf[MSG_SIZ]; if(nodes>>32 == u64Const(0xFFFFFFFF)) // [HGM] negative node count read nodes += u64Const(0x100000000); @@ -9528,6 +9556,14 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(appData.pvSAN[cps==&second]) pv = PvToSAN(buf1); + if(*bestMove) { // rememer time best EPD move was first found + int ff1, tf1, fr1, tr1, ff2, tf2, fr2, tr2; char pp1, pp2; + ChessMove mt; + int ok = ParseOneMove(bestMove, forwardMostMove, &mt, &ff1, &fr1, &tf1, &tr1, &pp1); + ok &= ParseOneMove(pv, forwardMostMove, &mt, &ff2, &fr2, &tf2, &tr2, &pp2); + solvingTime = (ok && ff1==ff2 && fr1==fr2 && tf1==tf2 && tr1==tr2 && pp1==pp2 ? time : -1); + } + if(serverMoves && (time > 100 || time == 0 && plylev > 7)) { char buf[MSG_SIZ]; FILE *f; @@ -9598,11 +9634,17 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h [AS] Protect the thinkOutput buffer from overflow... this is only useful if buf1 hasn't overflowed first! */ - snprintf(thinkOutput, sizeof(thinkOutput)/sizeof(thinkOutput[0]), "[%d]%c%+.2f %s%s", + if(curscore >= MATE_SCORE) + snprintf(score_buf, MSG_SIZ, "#%d", curscore - MATE_SCORE); + else if(curscore <= -MATE_SCORE) + snprintf(score_buf, MSG_SIZ, "#%d", curscore + MATE_SCORE); + else + snprintf(score_buf, MSG_SIZ, "%+.2f", ((double) curscore) / 100.0); + snprintf(thinkOutput, sizeof(thinkOutput)/sizeof(thinkOutput[0]), "[%d]%c%s %s%s", plylev, (gameMode == TwoMachinesPlay ? ToUpper(cps->twoMachinesColor[0]) : ' '), - ((double) curscore) / 100.0, + score_buf, prefixHint ? lastHint : "", prefixHint ? " " : "" ); @@ -9944,7 +9986,7 @@ ParseGameHistory (char *game) void ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) { - ChessSquare captured = board[toY][toX], piece, pawn, king, killed; int p, rookX, oldEP, epRank, berolina = 0; + ChessSquare captured = board[toY][toX], piece, pawn, king, killed, killed2; int p, rookX, oldEP, epRank, berolina = 0; int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1; /* [HGM] compute & store e.p. status and castling rights for new position */ @@ -9966,11 +10008,14 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) // ChessSquare victim; int i; - if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something + if( killX >= 0 && killY >= 0 ) { // [HGM] lion: Lion trampled over something // victim = board[killY][killX], killed = board[killY][killX], board[killY][killX] = EmptySquare, board[EP_STATUS] = EP_CAPTURE; + if( kill2X >= 0 && kill2Y >= 0) + killed2 = board[kill2Y][kill2X], board[kill2Y][kill2X] = EmptySquare; + } if( board[toY][toX] != EmptySquare ) { board[EP_STATUS] = EP_CAPTURE; @@ -11375,16 +11420,17 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) && gameInfo.variant != VariantLosers && gameInfo.variant != VariantGiveaway && gameInfo.variant != VariantSuicide // [HGM] losers: except in losers, of course... && result != GameIsDrawn) - { int i, j, k=0, color = (result==WhiteWins ? (int)WhitePawn : (int)BlackPawn); + { int i, j, k=0, oppoKings = 0, color = (result==WhiteWins ? (int)WhitePawn : (int)BlackPawn); for(j=BOARD_LEFT; j= 0 && p <= (int)WhiteKing) k++; + oppoKings += (p + color == WhiteKing + BlackPawn - color); } if (appData.debugMode) { fprintf(debugFP, "GE(%d, %s, %d) bare king k=%d color=%d\n", result, resultDetails ? resultDetails : "(null)", whosays, k, color); } - if(k <= 1) { + if(k <= 1 && oppoKings > 0) { // the latter needed in Atomic, where bare K wins if opponent King already destroyed result = GameIsDrawn; snprintf(buf, MSG_SIZ, "%s but bare king", resultDetails); resultDetails = buf; @@ -13295,10 +13341,14 @@ LoadPosition (FILE *f, int positionNumber, char *title) } if (fenMode) { + char *p; if (!ParseFEN(initial_position, &blackPlaysFirst, line, TRUE)) { DisplayError(_("Bad FEN position in file"), 0); return FALSE; } + if((p = strstr(line, ";")) && (p = strstr(p+1, "bm "))) { // EPD with best move + sscanf(p+3, "%s", bestMove); + } else *bestMove = NULLCHAR; } else { (void) fgets(line, MSG_SIZ, f); (void) fgets(line, MSG_SIZ, f);