X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=3c3ff374d9488a0cdefdbf4edae2ce1d107287fc;hb=39d0c966eae95ac31ffca6cec476e896bed31bf6;hp=b2dad3b39f84b46066948f7e5b1a825e93189b6c;hpb=069d9d85da438602b0afbc84748689a8b6ad5e72;p=xboard.git diff --git a/backend.c b/backend.c index b2dad3b..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, @@ -351,6 +351,8 @@ PosFlags(index) flags &= ~F_ALL_CASTLE_OK; case VariantGiveaway: // [HGM] moved this case label one down: seems Giveaway does have castling on ICC! flags |= F_IGNORE_CHECK; + case VariantLosers: + flags |= F_MANDATORY_CAPTURE; //[HGM] losers: sets flag so TestLegality rejects non-capts if capts exist break; case VariantAtomic: flags |= F_IGNORE_CHECK | F_ATOMIC_CAPTURE; @@ -617,6 +619,7 @@ InitBackEnd1() ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options GetTimeMark(&programStartTime); + srand(programStartTime.ms); // [HGM] book: makes sure random is unpredictabe to msec level ClearProgramStats(); programStats.ok_to_send = 1; @@ -746,6 +749,8 @@ InitBackEnd1() first.useFEN960 = FALSE; second.useFEN960 = FALSE; first.useOOCastle = TRUE; second.useOOCastle = TRUE; /* End of new features added by Tord. */ + first.fenOverride = appData.fenOverride1; + second.fenOverride = appData.fenOverride2; /* [HGM] time odds: set factor for each machine */ first.timeOdds = appData.firstTimeOdds; @@ -2271,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]; @@ -3713,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); @@ -3739,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; } @@ -4253,106 +4265,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar) } } -#if 0 -/* [AS] FRC game initialization */ -static int FindEmptySquare( Board board, int n ) -{ - int i = 0; - - while( 1 ) { - while( board[0][i] != EmptySquare ) i++; - if( n == 0 ) - break; - n--; - i++; - } - - return i; -} - -static void ShuffleFRC( Board board ) -{ - int i; - - srand( time(0) ); - - for( i=0; i<8; i++ ) { - board[0][i] = EmptySquare; - } - - board[0][(rand() % 4)*2 ] = WhiteBishop; /* On dark square */ - board[0][(rand() % 4)*2+1] = WhiteBishop; /* On lite square */ - board[0][FindEmptySquare(board, rand() % 6)] = WhiteQueen; - board[0][FindEmptySquare(board, rand() % 5)] = WhiteKnight; - board[0][FindEmptySquare(board, rand() % 4)] = WhiteKnight; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook; - initialRights[1] = initialRights[4] = - castlingRights[0][1] = castlingRights[0][4] = i; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing; - initialRights[2] = initialRights[5] = - castlingRights[0][2] = castlingRights[0][5] = i; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook; - initialRights[0] = initialRights[3] = - castlingRights[0][0] = castlingRights[0][3] = i; - - for( i=BOARD_LEFT; i> 8 ^ random() << 8; if(seed<0) seed = -seed; @@ -4508,8 +4420,6 @@ void SetUpShuffle(Board board, int number) if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize } -#endif - int SetCharTable( char *table, const char * map ) /* [HGM] moved here from winboard.c because of its general usefulness */ /* Basically a safe strcpy that uses the last character as King */ @@ -4627,11 +4537,6 @@ InitPosition(redraw) break; case VariantTwoKings: pieces = twoKingsArray; - nrCastlingRights = 8; /* add rights for second King */ - castlingRights[0][6] = initialRights[2] = 5; - castlingRights[0][7] = initialRights[5] = 5; - castlingRank[6] = 0; - castlingRank[7] = BOARD_HEIGHT-1; break; case VariantCapaRandom: shuffleOpenings = TRUE; @@ -4797,8 +4702,8 @@ InitPosition(redraw) if(gameInfo.variant == VariantSuper) Prelude(initialPosition); if(gameInfo.variant == VariantGreat) { // promotion commoners - initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-1] = WhiteMan; - initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-2] = 9; + initialPosition[PieceToNumber(WhiteMan)][BOARD_WIDTH-1] = WhiteMan; + initialPosition[PieceToNumber(WhiteMan)][BOARD_WIDTH-2] = 9; initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan; initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9; } @@ -4857,7 +4762,7 @@ SendBoard(cps, moveNum) char message[MSG_SIZ]; if (cps->useSetboard) { - char* fen = PositionToFEN(moveNum, cps->useFEN960); + char* fen = PositionToFEN(moveNum, cps->fenOverride); sprintf(message, "setboard %s\n", fen); SendToProgram(message, cps); free(fen); @@ -5312,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); @@ -5358,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; @@ -5424,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 { @@ -5708,6 +5601,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0); GameEnds(machineWhite ? BlackWins : WhiteWins, buf1, GE_XBOARD); + return; } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom) /* [HGM] Kludge to handle engines that send FRC-style castling when they shouldn't (like TSCP-Gothic) */ @@ -5741,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.), @@ -5801,50 +5695,26 @@ 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) - // don't wait for engine to announce game end if we can judge ourselves - switch (MateTest(boards[forwardMostMove], - PosFlags(forwardMostMove), epFile, - castlingRights[forwardMostMove]) ) { - case MT_NONE: - case MT_CHECK: - default: - break; - case MT_STALEMATE: - 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*/ - GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", - GE_XBOARD ); - } - break; - case MT_CHECKMATE: - epStatus[forwardMostMove] = EP_CHECKMATE; - if(appData.checkMates) { - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, - "Xboard adjudication: Checkmate", - GE_XBOARD ); - } - break; - } 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, bishopsColor = 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; - /* First absolutely insufficient mating material. Count what is on board. */ + /* Count what is on board. */ for(i=0; iother); // make sure opponent gets move + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, + "Xboard adjudication: King destroyed", GE_XBOARD ); + return; + } + } + + /* Bare King in Shatranj (loses) or Losers (wins) */ + if( NrW == 1 || NrPieces - NrW == 1) { + if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first) + epStatus[forwardMostMove] = EP_WINS; // mark as win, so it becomes claimable + if(appData.checkMates) { + 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 ); + return; + } + } else + if( gameInfo.variant == VariantShatranj && --bare < 0) + { /* bare King */ + 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 + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, + "Xboard adjudication: Bare king", GE_XBOARD ); + return; + } + } + } else bare = 1; + + + // don't wait for engine to announce game end if we can judge ourselves + switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove), epFile, + castlingRights[forwardMostMove]) ) { + case MT_NONE: + case MT_CHECK: + default: + break; + case MT_STALEMATE: + 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: + 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( result, reason, GE_XBOARD ); + return; + } + + /* Next absolutely insufficient mating material. */ if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 || @@ -5900,20 +5856,6 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } } - /* Shatranj baring rule */ - if( gameInfo.variant == VariantShatranj && (NrW == 1 || NrPieces - NrW == 1) ) - { /* bare King */ - - if(--bare < 0 && appData.checkMates) { - /* but only adjudicate them if adjudication enabled */ - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, - "Xboard adjudication: Bare king", GE_XBOARD ); - return; - } - } else bare = 1; - /* Then some trivial draws (only adjudicate, cannot be claimed) */ if(NrPieces == 4 && ( NrWR == 1 && NrBR == 1 /* KRKR */ @@ -6018,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; @@ -7039,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= GE_ENGINE1 ) { char claimer; + ChessMove trueResult = (ChessMove) -1; claimer = whosays == GE_ENGINE1 ? /* color of claimer */ first.twoMachinesColor[0] : second.twoMachinesColor[0] ; - if( (gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && - (result == WhiteWins && claimer == 'w' || - result == BlackWins && claimer == 'b' ) ) { - if (appData.debugMode) { - fprintf(debugFP, "result=%d sp=%d move=%d\n", - result, epStatus[forwardMostMove], forwardMostMove); + + // [HGM] losers: because the logic is becoming a bit hairy, determine true result first + if(epStatus[forwardMostMove] == EP_CHECKMATE) { + /* [HGM] verify: engine mate claims accepted if they were flagged */ + trueResult = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; + } else + if(epStatus[forwardMostMove] == EP_WINS) { // added code for games where being mated is a win + /* [HGM] verify: engine mate claims accepted if they were flagged */ + trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; + } else + if(epStatus[forwardMostMove] == EP_STALEMATE) { // only used to indicate draws now + trueResult = GameIsDrawn; // default; in variants where stalemate loses, Status is CHECKMATE } - /* [HGM] verify: engine mate claims accepted if they were flagged */ - if(epStatus[forwardMostMove] != EP_CHECKMATE && - result != (WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins)) { + + // now verify win claims, but not in drop games, as we don't understand those yet + if( (gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper + || gameInfo.variant == VariantGreat) && + (result == WhiteWins && claimer == 'w' || + result == BlackWins && claimer == 'b' ) ) { // case to verify: engine claims own win + if (appData.debugMode) { + fprintf(debugFP, "result=%d sp=%d move=%d\n", + result, epStatus[forwardMostMove], forwardMostMove); + } + if(result != trueResult) { sprintf(buf, "False win claim: '%s'", resultDetails); result = claimer == 'w' ? BlackWins : WhiteWins; resultDetails = buf; @@ -7832,7 +7808,9 @@ GameEnds(result, resultDetails, whosays) } /* [HGM] bare: don't allow bare King to win */ if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) - && result != GameIsDrawn) + && 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); for(j=BOARD_LEFT; j 0 || startedFromSetupPosition) { - char *fen = PositionToFEN(backwardMostMove, 1); + char *fen = PositionToFEN(backwardMostMove, NULL); fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen); fprintf(f, "\n{--------------\n"); PrintPosition(f, backwardMostMove); @@ -9600,7 +9581,16 @@ SaveGamePGN(f) linelen += numlen; /* Get move */ - movelen = strlen(parseList[i]); /* [HGM] pgn: line-break point before move */ + strcpy(move_buffer, parseList[i]); // [HGM] pgn: print move via buffer, so it can be edited + movelen = strlen(move_buffer); /* [HGM] pgn: line-break point before move */ + if( 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; @@ -9613,7 +9603,7 @@ SaveGamePGN(f) fprintf(f, " "); linelen++; } - fprintf(f, parseList[i]); + fprintf(f, move_buffer); linelen += movelen; /* [AS] Add PV info if present */ @@ -9621,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 @@ -9810,7 +9800,7 @@ SavePosition(f, dummy, dummy2) PrintPosition(f, currentMove); fprintf(f, "--------------]\n"); } else { - fen = PositionToFEN(currentMove, 1); + fen = PositionToFEN(currentMove, NULL); fprintf(f, "%s\n", fen); free(fen); } @@ -12769,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); } @@ -13346,9 +13336,9 @@ PGNDate() char * -PositionToFEN(move, useFEN960) +PositionToFEN(move, overrideCastling) int move; - int useFEN960; + char *overrideCastling; { int i, j, fromX, fromY, toX, toY; int whiteToPlay; @@ -13423,6 +13413,9 @@ PositionToFEN(move, useFEN960) *p++ = whiteToPlay ? 'w' : 'b'; *p++ = ' '; + if(q = overrideCastling) { // [HGM] FRC: override castling & e.p fields for non-compliant engines + while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; + } else { if(nrCastlingRights) { q = p; if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) { @@ -13480,6 +13473,7 @@ PositionToFEN(move, useFEN960) } *p++ = ' '; } + } /* [HGM] find reversible plies */ { int i = 0, j=move;