X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=3c3ff374d9488a0cdefdbf4edae2ce1d107287fc;hb=39d0c966eae95ac31ffca6cec476e896bed31bf6;hp=0f24243dcbf1d27be1be30b9b3c957aedd80cd02;hpb=09efa4c46ec85dac85fc7275d93303de213c45c4;p=xboard.git diff --git a/backend.c b/backend.c index 0f24243..3c3ff37 100644 --- a/backend.c +++ b/backend.c @@ -157,7 +157,7 @@ int LoadGameFromFile P((char *filename, int n, char *title, int useList)); int LoadPositionFromFile P((char *filename, int n, char *title)); int SavePositionToFile P((char *filename)); void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar, - Board board)); + Board board, char *castle, char *ep)); void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar)); void ShowMove P((int fromX, int fromY, int toX, int toY)); int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, @@ -2276,6 +2276,12 @@ read_from_ics(isr, closure, data, count, error) nrAlph += (parse[i] >= 'A' && parse[i] <= 'Z'); } if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info + int depth=0; float score; + if(sscanf(parse, "!!! %f/%d", &score, &depth) == 2 && depth>0) { + // [HGM] kibitz: save kibitzed opponent info for PGN and eval graph + pvInfoList[forwardMostMove-1].depth = depth; + pvInfoList[forwardMostMove-1].score = 100*score; + } OutputKibitz(suppressKibitz, parse); } else { char tmp[MSG_SIZ]; @@ -3718,7 +3724,7 @@ ParseBoard12(string) else strcpy(buf, str); // might be castling if((prom = strstr(move_str, "=")) && !strstr(buf, "=")) strcat(buf, prom); // long move lacks promo specification! - if(!appData.testLegality) { + if(!appData.testLegality && move_str[1] != '@') { // drops never ambiguous (parser chokes on long form!) if(appData.debugMode) fprintf(debugFP, "replaced ICS move '%s' by '%s'\n", move_str, buf); strcpy(move_str, buf); @@ -3744,6 +3750,7 @@ ParseBoard12(string) strcat(parseList[moveNum - 1], "+"); break; case MT_CHECKMATE: + case MT_STAINMATE: // [HGM] xq: for notation stalemate that wins counts as checkmate strcat(parseList[moveNum - 1], "#"); break; } @@ -5210,9 +5217,9 @@ if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", move * If they don't match, display an error message. */ int saveAnimate; - Board testBoard; + Board testBoard; char testRights[BOARD_SIZE]; char testStatus; CopyBoard(testBoard, boards[currentMove]); - ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard); + ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard, testRights, &testStatus); if (CompareBoards(testBoard, boards[currentMove+1])) { ForwardInner(currentMove+1); @@ -5256,19 +5263,6 @@ if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", move MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/ - if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) - && promoChar != NULLCHAR && gameInfo.holdingsSize) { - // [HGM] superchess: take promotion piece out of holdings - int k = PieceToNumber(CharToPiece(ToUpper(promoChar))); - if(WhiteOnMove(forwardMostMove-1)) { - if(!--boards[forwardMostMove][k][BOARD_WIDTH-2]) - boards[forwardMostMove][k][BOARD_WIDTH-1] = EmptySquare; - } else { - if(!--boards[forwardMostMove][BOARD_HEIGHT-1-k][1]) - boards[forwardMostMove][BOARD_HEIGHT-1-k][0] = EmptySquare; - } - } - if (gameMode == BeginningOfGame) { if (appData.noChessProgram) { gameMode = EditGame; @@ -5322,6 +5316,7 @@ if(appData.debugMode) fprintf(debugFP, "moveType 2 = %d, promochar = %x\n", move case MT_CHECK: break; case MT_CHECKMATE: + case MT_STAINMATE: if (WhiteOnMove(currentMove)) { GameEnds(BlackWins, "Black mates", GE_PLAYER); } else { @@ -5640,9 +5635,9 @@ 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 */ char buf[3*MSG_SIZ]; - sprintf(buf, "kibitz %d/%+.2f (%.2f sec, %.0f nodes, %1.0f knps) PV = %s\n", - programStats.depth, + sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %.0f nodes, %1.0f knps) PV=%s\n", programStats.score / 100., + programStats.depth, programStats.time / 100., u64ToDouble(programStats.nodes), u64ToDouble(programStats.nodes) / (10*abs(programStats.time) + 1.), @@ -5700,12 +5695,15 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h int k, count = 0, epFile = epStatus[forwardMostMove]; static int bare = 1; if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { + if( appData.testLegality ) { /* [HGM] Some more adjudications for obstinate engines */ int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0, NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0, NrPieces=0, NrPawns=0, PawnAdvance=0, i, j; static int moveCount = 6; + ChessMove result; + char *reason = NULL; /* Count what is on board. */ for(i=0; iother); /* make sure opponent gets to see move */ + SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, "Xboard adjudication: Bare king", GE_XBOARD ); @@ -5780,7 +5778,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } else if( gameInfo.variant == VariantShatranj && --bare < 0) { /* bare King */ - epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as win for stm + epStatus[forwardMostMove] = EP_WINS; // make claimable as win for stm if(appData.checkMates) { /* but only adjudicate if adjudication enabled */ SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move @@ -5794,40 +5792,49 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h // don't wait for engine to announce game end if we can judge ourselves - switch (MateTest(boards[forwardMostMove], - PosFlags(forwardMostMove), epFile, + switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove), epFile, castlingRights[forwardMostMove]) ) { case MT_NONE: case MT_CHECK: default: break; case MT_STALEMATE: - if(epStatus[forwardMostMove] != EP_CHECKMATE) // [HGM] spare win through baring or K-capt - epStatus[forwardMostMove] = EP_STALEMATE; - if(appData.checkMates) { - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantSuicide - || gameInfo.variant == VariantGiveaway) // [HGM] losers: - GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, // stalemated side wins! - "Xboard adjudication: Stalemate", GE_XBOARD ); - else - GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", GE_XBOARD ); - return; + case MT_STAINMATE: + reason = "Xboard adjudication: Stalemate"; + if(epStatus[forwardMostMove] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt + epStatus[forwardMostMove] = EP_STALEMATE; // default result for stalemate is draw + if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantGiveaway) // [HGM] losers: + epStatus[forwardMostMove] = EP_WINS; // in these variants stalemated is always a win + else if(gameInfo.variant == VariantSuicide) // in suicide it depends + epStatus[forwardMostMove] = NrW == NrPieces-NrW ? EP_STALEMATE : + ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ? + EP_CHECKMATE : EP_WINS); + else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi) + epStatus[forwardMostMove] = EP_CHECKMATE; // and in these variants being stalemated loses } break; case MT_CHECKMATE: - epStatus[forwardMostMove] = EP_CHECKMATE; - if(appData.checkMates) { + reason = "Xboard adjudication: Checkmate"; + epStatus[forwardMostMove] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE); + break; + } + + switch(i = epStatus[forwardMostMove]) { + case EP_STALEMATE: + result = GameIsDrawn; break; + case EP_CHECKMATE: + result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break; + case EP_WINS: + result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break; + default: + result = (ChessMove) 0; + } + if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers) // [HGM] losers: - ? BlackWins : WhiteWins, // reverse the result ( A!=1 is !A for a boolean) - "Xboard adjudication: Checkmate", GE_XBOARD ); + GameEnds( result, reason, GE_XBOARD ); return; } - break; - } /* Next absolutely insufficient mating material. */ if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && @@ -5953,7 +5960,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase hisPerpetual = PerpetualChase(k, forwardMostMove); ourPerpetual = PerpetualChase(k+1, forwardMostMove); - if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit + if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, "Xboard adjudication: perpetual chasing", GE_XBOARD ); return; @@ -6974,11 +6981,13 @@ ParseGameHistory(game) EP_UNKNOWN, fromY, fromX, toY, toX, promoChar, parseList[boardIndex]); CopyBoard(boards[boardIndex + 1], boards[boardIndex]); + {int i; for(i=0; i 0) + /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */ { int i; if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A; - oldEP = epStatus[p-1]; - epStatus[p] = EP_NONE; + oldEP = *ep; + *ep = EP_NONE; if( board[toY][toX] != EmptySquare ) - epStatus[p] = EP_CAPTURE; + *ep = EP_CAPTURE; if( board[fromY][fromX] == WhitePawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers - epStatus[p] = EP_PAWN_MOVE; + *ep = EP_PAWN_MOVE; if( toY-fromY==2) { if(toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn && gameInfo.variant != VariantBerolina || toX < fromX) - epStatus[p] = toX | berolina; + *ep = toX | berolina; if(toX fromX) - epStatus[p] = toX; + *ep = toX; } } else if( board[fromY][fromX] == BlackPawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers - epStatus[p] = EP_PAWN_MOVE; + *ep = EP_PAWN_MOVE; if( toY-fromY== -2) { if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn && gameInfo.variant != VariantBerolina || toX < fromX) - epStatus[p] = toX | berolina; + *ep = toX | berolina; if(toX fromX) - epStatus[p] = toX; + *ep = toX; } } for(i=0; i= 0 && appData.saveExtendedInfoInPGN && pvInfoList[i].depth > 0 ) { + int p = movelen - 1; + if(move_buffer[p] == ' ') p--; + if(move_buffer[p] == ')') { // [HGM] pgn: strip off ICS time if we have extended info + while(p && move_buffer[--p] != '('); + if(p && move_buffer[p-1] == ' ') move_buffer[movelen=p-1] = 0; + } + } /* Print move */ blank = linelen > 0 && movelen > 0; @@ -9565,7 +9603,7 @@ SaveGamePGN(f) fprintf(f, " "); linelen++; } - fprintf(f, parseList[i]); + fprintf(f, move_buffer); linelen += movelen; /* [AS] Add PV info if present */ @@ -9573,14 +9611,14 @@ SaveGamePGN(f) /* [HGM] add time */ char buf[MSG_SIZ]; int seconds = 0; -#if 0 +#if 1 if(i >= backwardMostMove) { if(WhiteOnMove(i)) seconds = timeRemaining[0][i] - timeRemaining[0][i+1] - + GetTimeQuota(i/2) / WhitePlayer()->timeOdds; + + GetTimeQuota(i/2) / (1000*WhitePlayer()->timeOdds); else seconds = timeRemaining[1][i] - timeRemaining[1][i+1] - + GetTimeQuota(i/2) / WhitePlayer()->other->timeOdds; + + GetTimeQuota(i/2) / (1000*WhitePlayer()->other->timeOdds); } seconds = (seconds+50)/100; // deci-seconds, rounded to nearest #else @@ -12721,16 +12759,16 @@ DisplayComment(moveNumber, text) WhiteOnMove(moveNumber) ? " " : ".. ", parseList[moveNumber]); } + // [HGM] PV info: display PV info together with (or as) comment + if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) { + if(text == NULL) text = ""; + score = pvInfoList[moveNumber].score; + sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100., + depth, (pvInfoList[moveNumber].time+50)/100, text); + text = buf; + } } else title[0] = 0; - // [HGM] PV info: display PV info together with (or as) comment - if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) { - if(text == NULL) text = ""; - score = pvInfoList[moveNumber].score; - sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100., - depth, (pvInfoList[moveNumber].time+50)/100, text); - CommentPopUp(title, buf); - } else if (text != NULL) CommentPopUp(title, text); }