X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=6eba7f6b726eea12587e258756fecb88bcc15bf9;hb=b382d988c6f886f3a49483df9e3e36de0b6b0824;hp=49affeec63d6148a4d363e5ae42752f3e1030aa6;hpb=85f471c113ce3e3073afeda0b6e3535f979518f9;p=xboard.git diff --git a/backend.c b/backend.c index 49affee..6eba7f6 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 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -318,11 +318,11 @@ safeStrCpy( char *dst, const char *src, size_t count ) assert( count > 0 ); for(i=0; i ") || @@ -3854,7 +3845,7 @@ ParseBoard12(string) int j, k, n, moveNum, white_stren, black_stren, white_time, black_time, takeback; int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count; char to_play, board_chars[200]; - char move_str[500], str[500], elapsed_time[500]; + char move_str[MSG_SIZ], str[MSG_SIZ], elapsed_time[MSG_SIZ]; char black[32], white[32]; Board board; int prevMove = currentMove; @@ -3895,7 +3886,7 @@ ParseBoard12(string) &ticking); if (n < 21) { - snprintf(str, sizeof(str), _("Failed to parse board string:\n\"%s\""), string); + snprintf(str, MSG_SIZ, _("Failed to parse board string:\n\"%s\""), string); DisplayError(str, 0); return; } @@ -4344,7 +4335,7 @@ ParseBoard12(string) 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); - safeStrCpy(move_str, buf, sizeof(move_str)/sizeof(move_str[0])); + safeStrCpy(move_str, buf, MSG_SIZ); } valid = ParseOneMove(move_str, moveNum - 1, &moveType, &fromX, &fromY, &toX, &toY, &promoChar) @@ -5008,6 +4999,9 @@ fprintf(debugFP,"parsePV: %d %c%c%c%c yy='%s'\nPV = '%s'\n", valid, fromX+AAA, f moveList[endPV-1][1] = fromY + ONE; moveList[endPV-1][2] = toX + AAA; moveList[endPV-1][3] = toY + ONE; + moveList[endPV-1][4] = promoChar; + moveList[endPV-1][5] = NULLCHAR; + strncat(moveList[endPV-1], "\n", MOVE_LEN); if(storeComments) CoordsToAlgebraic(boards[endPV - 1], PosFlags(endPV - 1), @@ -5309,8 +5303,8 @@ InitPosition(redraw) int i, j, pawnRow, overrule, oldx = gameInfo.boardWidth, oldy = gameInfo.boardHeight, - oldh = gameInfo.holdingsWidth, - oldv = gameInfo.variant; + oldh = gameInfo.holdingsWidth; + static int oldv; if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request @@ -5348,12 +5342,12 @@ InitPosition(redraw) if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant SetCharTable(pieceNickName, appData.pieceNickNames); else SetCharTable(pieceNickName, "............"); + pieces = FIDEArray; switch (gameInfo.variant) { case VariantFischeRandom: shuffleOpenings = TRUE; default: - pieces = FIDEArray; break; case VariantShatranj: pieces = ShatranjArray; @@ -5381,6 +5375,10 @@ InitPosition(redraw) gameInfo.boardWidth = 10; SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); break; + case VariantSChess: + SetCharTable(pieceToChar, "PNBRQ..HEKpnbrq..hek"); + gameInfo.holdingsSize = 7; + break; case VariantJanus: pieces = JanusArray; gameInfo.boardWidth = 10; @@ -5423,6 +5421,10 @@ InitPosition(redraw) pieces = KnightmateArray; SetCharTable(pieceToChar, "P.BRQ.....M.........K.p.brq.....m.........k."); break; + case VariantSpartan: + pieces = SpartanArray; + SetCharTable(pieceToChar, "PNBRQ................K......lwg.....c...h..k"); + break; case VariantFairy: pieces = fairyArray; SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk"); @@ -5493,7 +5495,7 @@ InitPosition(redraw) if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue; initialPosition[0][j] = pieces[0][j-gameInfo.holdingsWidth]; initialPosition[pawnRow][j] = WhitePawn; - initialPosition[BOARD_HEIGHT-pawnRow-1][j] = BlackPawn; + initialPosition[BOARD_HEIGHT-pawnRow-1][j] = gameInfo.variant == VariantSpartan ? BlackLance : BlackPawn; if(gameInfo.variant == VariantXiangqi) { if(j&1) { initialPosition[pawnRow][j] = @@ -5537,6 +5539,14 @@ InitPosition(redraw) initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan; initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9; } + if( gameInfo.variant == VariantSChess ) { + initialPosition[1][0] = BlackMarshall; + initialPosition[2][0] = BlackAngel; + initialPosition[6][BOARD_WIDTH-1] = WhiteMarshall; + initialPosition[5][BOARD_WIDTH-1] = WhiteAngel; + initialPosition[1][1] = initialPosition[2][1] = + initialPosition[6][BOARD_WIDTH-2] = initialPosition[5][BOARD_WIDTH-2] = 1; + } if (appData.debugMode) { fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings); } @@ -5556,18 +5566,12 @@ InitPosition(redraw) if(oldx != gameInfo.boardWidth || oldy != gameInfo.boardHeight || + oldv != gameInfo.variant || oldh != gameInfo.holdingsWidth -#ifdef GOTHIC - || oldv == VariantGothic || // For licensing popups - gameInfo.variant == VariantGothic -#endif -#ifdef FALCON - || oldv == VariantFalcon || - gameInfo.variant == VariantFalcon -#endif ) InitDrawingSizes(-2 ,0); + oldv = gameInfo.variant; if (redraw) DrawPosition(TRUE, boards[currentMove]); } @@ -5670,6 +5674,12 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) promotionZoneSize = 3; } + // Treat Lance as Pawn when it is not representing Amazon + if(gameInfo.variant != VariantSuper) { + if(piece == WhiteLance) piece = WhitePawn; else + if(piece == BlackLance) piece = BlackPawn; + } + // next weed out all moves that do not touch the promotion zone at all if((int)piece >= BlackPawn) { if(toY >= promotionZoneSize && fromY >= promotionZoneSize) @@ -5975,6 +5985,7 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar) case BeginningOfGame: case AnalyzeMode: case Training: + if(fromY == DROP_RANK) break; // [HGM] drop moves (entered through move type-in) are automatically assigned to side-to-move if ((int) boards[currentMove][fromY][fromX] >= (int) BlackPawn && (int) boards[currentMove][fromY][fromX] < (int) EmptySquare) { /* User is moving for Black */ @@ -6069,15 +6080,15 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar) pup = boards[currentMove][toY][toX]; /* [HGM] If move started in holdings, it means a drop. Convert to standard form */ - if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { + if( (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && fromY != DROP_RANK ) { if( pup != EmptySquare ) return; moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop; - if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", + if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]); // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings - while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; + while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; fromY = DROP_RANK; } @@ -6232,6 +6243,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar) switch (gameMode) { case EditGame: + if(appData.testLegality) switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) { case MT_NONE: case MT_CHECK: @@ -6327,6 +6339,8 @@ Explode(Board board, int fromX, int fromY, int toX, int toY) return FALSE; } +ChessSquare gatingPiece = EmptySquare; // exported to front-end, for dragging + void LeftClick(ClickType clickType, int xPix, int yPix) { int x, y; @@ -6383,8 +6397,15 @@ void LeftClick(ClickType clickType, int xPix, int yPix) autoQueen = appData.alwaysPromoteToQueen; if (fromX == -1) { + gatingPiece = EmptySquare; + if (clickType != Press) { + if(dragging) { // [HGM] from-square must have been reset due to game end since last press + DragPieceEnd(xPix, yPix); dragging = 0; + DrawPosition(FALSE, NULL); + } + return; + } if(!appData.oneClick || !OnlyMove(&x, &y, FALSE)) { - if (clickType == Press) { /* First square */ if (OKToStartUserMove(x, y)) { fromX = x; @@ -6396,12 +6417,8 @@ void LeftClick(ClickType clickType, int xPix, int yPix) SetHighlights(x, y, -1, -1); } } - } else if(dragging) { // [HGM] from-square must have been reset due to game end since last press - DragPieceEnd(xPix, yPix); dragging = 0; - DrawPosition(FALSE, NULL); + return; } - return; - } } /* fromX != -1 */ @@ -6416,7 +6433,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) /* Check if clicking again on the same color piece */ fromP = boards[currentMove][fromY][fromX]; toP = boards[currentMove][y][x]; - frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom; + frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess; if ((WhitePawn <= fromP && fromP <= WhiteKing && WhitePawn <= toP && toP <= WhiteKing && !(fromP == WhiteKing && toP == WhiteRook && frc) && @@ -6434,13 +6451,19 @@ void LeftClick(ClickType clickType, int xPix, int yPix) ClearHighlights(); } if (OKToStartUserMove(x, y)) { + if(gameInfo.variant == VariantSChess && // S-Chess: back-rank piece selected after holdings means gating + (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && + y == (toP < BlackPawn ? 0 : BOARD_HEIGHT-1)) + gatingPiece = boards[currentMove][fromY][fromX]; + else gatingPiece = EmptySquare; fromX = x; fromY = y; dragging = 1; MarkTargetSquares(0); DragPieceBegin(xPix, yPix); } - return; } + if(x == fromX && y == fromY) return; // if OnlyMove altered (x,y) we go on + second = FALSE; } // ignore clicks on holdings if(x < BOARD_LEFT || x >= BOARD_RGHT) return; @@ -6456,6 +6479,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) /* Second up/down in same square; just abort move */ second = 0; fromX = fromY = -1; + gatingPiece = EmptySquare; ClearHighlights(); gotPremove = 0; ClearPremoveHighlights(); @@ -6518,7 +6542,9 @@ void LeftClick(ClickType clickType, int xPix, int yPix) } // off-board moves should not be highlighted - if(x < 0 || x < 0) ClearHighlights(); + if(x < 0 || y < 0) ClearHighlights(); + + if(gatingPiece != EmptySquare) promoChoice = ToLower(PieceToChar(gatingPiece)); if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice)) { SetHighlights(fromX, fromY, toX, toY); @@ -7304,11 +7330,6 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if (cps->sendTime == 2) cps->sendTime = 1; if (cps->offeredDraw) cps->offeredDraw--; - /* currentMoveString is set as a side-effect of ParseOneMove */ - safeStrCpy(machineMove, currentMoveString, sizeof(machineMove)/sizeof(machineMove[0])); - strcat(machineMove, "\n"); - safeStrCpy(moveList[forwardMostMove], machineMove, sizeof(moveList[forwardMostMove])/sizeof(moveList[forwardMostMove][0])); - /* [AS] Save move info*/ pvInfoList[ forwardMostMove ].score = programStats.score; pvInfoList[ forwardMostMove ].depth = programStats.depth; @@ -7345,7 +7366,11 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } } - if(Adjudicate(cps)) return; // [HGM] adjudicate: for all automatic game ends + if(Adjudicate(cps)) { + DrawPosition(FALSE, boards[currentMove = forwardMostMove-1]); + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + return; // [HGM] adjudicate: for all automatic game ends + } #if ZIPPY if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) && @@ -7667,6 +7692,13 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. gameMode = EditGame; ModeHighlight(); } + /* [HGM] illegal-move claim should forfeit game when Xboard */ + /* only passes fully legal moves */ + if( appData.testLegality && gameMode == TwoMachinesPlay ) { + GameEnds( cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins, + "False illegal-move claim", GE_XBOARD ); + return; // do not take back move we tested as valid + } currentMove = forwardMostMove-1; DisplayMove(currentMove-1); /* before DisplayMoveError */ SwitchClocks(forwardMostMove-1); // [HGM] race @@ -7675,13 +7707,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. parseList[currentMove], cps->which); DisplayMoveError(buf1); DrawPosition(FALSE, boards[currentMove]); - - /* [HGM] illegal-move claim should forfeit game when Xboard */ - /* only passes fully legal moves */ - if( appData.testLegality && gameMode == TwoMachinesPlay ) { - GameEnds( cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins, - "False illegal-move claim", GE_XBOARD ); - } return; } if (strncmp(message, "time", 4) == 0 && StrStr(message, "Illegal")) { @@ -8331,6 +8356,7 @@ ParseGameHistory(game) if (q != NULL) *q = NULLCHAR; p++; } + while(q = strchr(p, '\n')) *q = ' '; // [HGM] crush linefeeds in result message gameInfo.resultDetails = StrSave(p); continue; } @@ -8392,6 +8418,10 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) } else { int i; + if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) { + if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi ) + board[EP_STATUS] = EP_PAWN_MOVE; // Lance is Pawn-like in most variants + } else if( board[fromY][fromX] == WhitePawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; @@ -8431,21 +8461,21 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) king += (int) WhiteUnicorn - (int) WhiteKing; /* Code added by Tord: */ - /* FRC castling assumed when king captures friendly rook. */ - if (board[fromY][fromX] == WhiteKing && - board[toY][toX] == WhiteRook) { + /* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */ + if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook || + board[fromY][fromX] == WhiteRook && board[toY][toX] == WhiteKing) { board[fromY][fromX] = EmptySquare; board[toY][toX] = EmptySquare; - if(toX > fromX) { + if((toX > fromX) != (piece == WhiteRook)) { board[0][BOARD_RGHT-2] = WhiteKing; board[0][BOARD_RGHT-3] = WhiteRook; } else { board[0][BOARD_LEFT+2] = WhiteKing; board[0][BOARD_LEFT+3] = WhiteRook; } - } else if (board[fromY][fromX] == BlackKing && - board[toY][toX] == BlackRook) { + } else if (board[fromY][fromX] == BlackKing && board[toY][toX] == BlackRook || + board[fromY][fromX] == BlackRook && board[toY][toX] == BlackKing) { board[fromY][fromX] = EmptySquare; board[toY][toX] = EmptySquare; - if(toX > fromX) { + if((toX > fromX) != (piece == BlackRook)) { board[BOARD_HEIGHT-1][BOARD_RGHT-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_RGHT-3] = BlackRook; } else { board[BOARD_HEIGHT-1][BOARD_LEFT+2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_LEFT+3] = BlackRook; @@ -8466,9 +8496,9 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) board[toY][toX] = king; board[toY][toX+1] = board[fromY][BOARD_LEFT]; board[fromY][BOARD_LEFT] = EmptySquare; - } else if (board[fromY][fromX] == WhitePawn + } else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi || + board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi) && toY >= BOARD_HEIGHT-promoRank - && gameInfo.variant != VariantXiangqi ) { /* white pawn promotion */ board[toY][toX] = CharToPiece(ToUpper(promoChar)); @@ -8530,9 +8560,9 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) board[toY][toX] = BlackKing; board[fromY][0] = EmptySquare; board[toY][2] = BlackRook; - } else if (board[fromY][fromX] == BlackPawn + } else if ((board[fromY][fromX] == BlackPawn && gameInfo.variant != VariantXiangqi || + board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi) && toY < promoRank - && gameInfo.variant != VariantXiangqi ) { /* black pawn promotion */ board[toY][toX] = CharToPiece(ToLower(promoChar)); @@ -8578,10 +8608,11 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) /* [HGM] OK, so I have written it. Holdings are stored in the */ /* penultimate board files, so they are automaticlly stored */ /* in the game history. */ - if (fromY == DROP_RANK) { + if (fromY == DROP_RANK || gameInfo.variant == VariantSChess + && promoChar && piece != WhitePawn && piece != BlackPawn) { /* Delete from holdings, by decreasing count */ /* and erasing image if necessary */ - p = (int) fromX; + p = fromY == DROP_RANK ? (int) fromX : CharToPiece(piece > BlackPawn ? ToLower(promoChar) : ToUpper(promoChar)); if(p < (int) BlackPawn) { /* white drop */ p -= (int)WhitePawn; p = PieceToNumber((ChessSquare)p); @@ -8601,7 +8632,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) } } if (captured != EmptySquare && gameInfo.holdingsSize > 0 - && gameInfo.variant != VariantBughouse ) { + && gameInfo.variant != VariantBughouse && gameInfo.variant != VariantSChess ) { /* [HGM] holdings: Add to holdings, if holdings exist */ if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { // [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip @@ -8645,14 +8676,17 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) board[toY][toX] = EmptySquare; } } + if(gameInfo.variant == VariantSChess && promoChar != NULLCHAR && promoChar != '=' && piece != WhitePawn && piece != BlackPawn) { + board[fromY][fromX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); // S-Chess gating + } else if(promoChar == '+') { /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite orinary Pawn promotion) */ board[toY][toX] = (ChessSquare) (PROMOTED piece); } else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar board[toY][toX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); } - if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) - && promoChar != NULLCHAR && gameInfo.holdingsSize) { + 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((int)piece < (int)BlackPawn) { // determine stm from piece color @@ -8877,6 +8911,8 @@ InitChessProgram(cps, setup) overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8; if( gameInfo.variant == VariantGreat ) overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8; + if( gameInfo.variant == VariantSChess ) + overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 7; if(overruled) { snprintf(b, MSG_SIZ, "%dx%d+%d_%s", gameInfo.boardWidth, gameInfo.boardHeight, @@ -9419,6 +9455,13 @@ GameEnds(result, resultDetails, whosays) first.matchWins, second.matchWins, appData.matchGames - (first.matchWins + second.matchWins)); popupRequested++; // [HGM] crash: postpone to after resetting endingGame + if (appData.firstPlaysBlack) { // [HGM] match: back to original for next match + first.twoMachinesColor = "black\n"; + second.twoMachinesColor = "white\n"; + } else { + first.twoMachinesColor = "white\n"; + second.twoMachinesColor = "black\n"; + } } } if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && @@ -9588,7 +9631,7 @@ AutoPlayGameLoop() return; if (matchMode || appData.timeDelay == 0) continue; - if (appData.timeDelay < 0 || gameMode == AnalyzeFile) + if (appData.timeDelay < 0) return; StartLoadGameTimer((long)(1000.0 * appData.timeDelay)); break; @@ -9605,10 +9648,18 @@ AutoPlayOneMove() fprintf(debugFP, "AutoPlayOneMove(): current %d\n", currentMove); } - if (gameMode != PlayFromGameFile) + if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile) return FALSE; + if (gameMode == AnalyzeFile && currentMove > backwardMostMove) { + pvInfoList[currentMove].depth = programStats.depth; + pvInfoList[currentMove].score = programStats.score; + pvInfoList[currentMove].time = 0; + if(currentMove < forwardMostMove) AppendComment(currentMove+1, lastPV[0], 2); + } + if (currentMove >= forwardMostMove) { + if(gameMode == AnalyzeFile) { ExitAnalyzeMode(); SendToProgram("force\n", &first); } gameMode = EditGame; ModeHighlight(); @@ -9741,6 +9792,7 @@ LoadGameOneMove(readAhead) if (q != NULL) *q = NULLCHAR; p++; } + while(q = strchr(p, '\n')) *q = ' '; // [HGM] crush linefeeds in result message GameEnds(moveType, p, GE_FILE); done = TRUE; if (cmailMsgLoaded) { @@ -9873,8 +9925,6 @@ LoadGameOneMove(readAhead) return FALSE; } else { /* currentMoveString is set as a side-effect of yylex */ - strcat(currentMoveString, "\n"); - safeStrCpy(moveList[forwardMostMove], currentMoveString, sizeof(moveList[forwardMostMove])/sizeof(moveList[forwardMostMove][0])); thinkOutput[0] = NULLCHAR; MakeMove(fromX, fromY, toX, toY, promoChar); @@ -11613,7 +11663,7 @@ void EditTagsEvent() { char *tags = PGNTags(&gameInfo); - EditTagsPopUp(tags); + EditTagsPopUp(tags, NULL); free(tags); } @@ -12566,6 +12616,30 @@ CallFlagEvent() } void +ClockClick(int which) +{ // [HGM] code moved to back-end from winboard.c + if(which) { // black clock + if (gameMode == EditPosition || gameMode == IcsExamining) { + SetBlackToPlayEvent(); + } else if (gameMode == EditGame || shiftKey) { + AdjustClock(which, -1); + } else if (gameMode == IcsPlayingWhite || + gameMode == MachinePlaysBlack) { + CallFlagEvent(); + } + } else { // white clock + if (gameMode == EditPosition || gameMode == IcsExamining) { + SetWhiteToPlayEvent(); + } else if (gameMode == EditGame || shiftKey) { + AdjustClock(which, -1); + } else if (gameMode == IcsPlayingBlack || + gameMode == MachinePlaysWhite) { + CallFlagEvent(); + } + } +} + +void DrawEvent() { /* Offer draw or accept pending draw offer from opponent */ @@ -13269,7 +13343,13 @@ ReplaceComment(index, text) char *text; { int len; + char *p; + float score; + if(index && sscanf(text, "%f/%d", &score, &len) == 2 && + pvInfoList[index-1].depth == len && + fabs(pvInfoList[index-1].score - score*100.) < 0.5 && + (p = strchr(text, '\n'))) text = p; // [HGM] strip off first line with PV info, if any while (*text == '\n') text++; len = strlen(text); while (len > 0 && text[len - 1] == '\n') len--; @@ -13340,27 +13420,27 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); while(commentList[index][oldlen-1] == '\n') commentList[index][--oldlen] = NULLCHAR; commentList[index] = (char *) malloc(oldlen + len + 6); // might waste 4 - safeStrCpy(commentList[index], old, oldlen); + safeStrCpy(commentList[index], old, oldlen + len + 6); free(old); // [HGM] braces: join "{A\n}\n" + "{\nB}" as "{A\nB\n}" - if(commentList[index][oldlen-1] == '}' && (text[0] == '{' || addBraces)) { - if(addBraces) addBraces = FALSE; else { text++; len--; } + if(commentList[index][oldlen-1] == '}' && (text[0] == '{' || addBraces == TRUE)) { + if(addBraces == TRUE) addBraces = FALSE; else { text++; len--; } while (*text == '\n') { text++; len--; } commentList[index][--oldlen] = NULLCHAR; } - if(addBraces) strcat(commentList[index], "\n{\n"); + if(addBraces) strcat(commentList[index], addBraces == 2 ? "\n(" : "\n{\n"); else strcat(commentList[index], "\n"); strcat(commentList[index], text); - if(addBraces) strcat(commentList[index], "\n}\n"); + if(addBraces) strcat(commentList[index], addBraces == 2 ? ")\n" : "\n}\n"); else strcat(commentList[index], "\n"); } else { commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4... if(addBraces) - safeStrCpy(commentList[index], "{\n", 3); + safeStrCpy(commentList[index], addBraces == 2 ? "(" : "{\n", 3); else commentList[index][0] = NULLCHAR; strcat(commentList[index], text); - strcat(commentList[index], "\n"); - if(addBraces) strcat(commentList[index], "}\n"); + strcat(commentList[index], addBraces == 2 ? ")\n" : "\n"); + if(addBraces == TRUE) strcat(commentList[index], "}\n"); } } @@ -13379,7 +13459,7 @@ static char * FindStr( char * text, char * sub_text ) /* [HGM] PV time: and then remove it, to prevent it appearing twice */ char *GetInfoFromComment( int index, char * text ) { - char * sep = text; + char * sep = text, *p; if( text != NULL && index > 0 ) { int score = 0; @@ -13417,11 +13497,20 @@ char *GetInfoFromComment( int index, char * text ) return text; } + p = text; + if(p[1] == '(') { // comment starts with PV + p = strchr(p, ')'); // locate end of PV + if(p == NULL || sep < p+5) return text; + // at this point we have something like "{(.*) +0.23/6 ..." + p = text; while(*++p != ')') p[-1] = *p; p[-1] = ')'; + *p = '\n'; while(*p == ' ' || *p == '\n') p++; *--p = '{'; + // we now moved the brace to behind the PV: "(.*) {+0.23/6 ..." + } time = -1; sec = -1; deci = -1; - if( sscanf( text+1, "%d.%d/%d %d:%d", &score, &score_lo, &depth, &time, &sec ) != 5 && - sscanf( text+1, "%d.%d/%d %d.%d", &score, &score_lo, &depth, &time, &deci ) != 5 && - sscanf( text+1, "%d.%d/%d %d", &score, &score_lo, &depth, &time ) != 4 && - sscanf( text+1, "%d.%d/%d", &score, &score_lo, &depth ) != 3 ) { + if( sscanf( p+1, "%d.%d/%d %d:%d", &score, &score_lo, &depth, &time, &sec ) != 5 && + sscanf( p+1, "%d.%d/%d %d.%d", &score, &score_lo, &depth, &time, &deci ) != 5 && + sscanf( p+1, "%d.%d/%d %d", &score, &score_lo, &depth, &time ) != 4 && + sscanf( p+1, "%d.%d/%d", &score, &score_lo, &depth ) != 3 ) { return text; } @@ -13437,7 +13526,7 @@ char *GetInfoFromComment( int index, char * text ) /* [HGM] PV time: now locate end of PV info */ while( *++sep >= '0' && *sep <= '9'); // strip depth if(time >= 0) - while( *++sep >= '0' && *sep <= '9'); // strip time + while( *++sep >= '0' && *sep <= '9' || *sep == '\n'); // strip time if(sec >= 0) while( *++sep >= '0' && *sep <= '9'); // strip seconds if(deci >= 0) @@ -13457,6 +13546,7 @@ char *GetInfoFromComment( int index, char * text ) pvInfoList[index-1].score = score; pvInfoList[index-1].time = 10*time; // centi-sec if(*sep == '}') *sep = 0; else *--sep = '{'; + if(p != text) { while(*p++ = *sep++); sep = text; } // squeeze out space between PV and comment, and return both } return sep; } @@ -13560,6 +13650,7 @@ ReceiveFromProgram(isr, closure, message, count, error) sscanf(message, "error %c", &c)!=1 && sscanf(message, "illegal %c", &c)!=1 && sscanf(message, "tell%c", &c)!=1 && sscanf(message, "0-1 %c", &c)!=1 && sscanf(message, "1-0 %c", &c)!=1 && sscanf(message, "1/2-1/2 %c", &c)!=1 && + sscanf(message, "setboard %c", &c)!=1 && sscanf(message, "setup %c", &c)!=1 && sscanf(message, "hint: %c", &c)!=1 && sscanf(message, "pong %c", &c)!=1 && start != '#') { quote = appData.engineComments == 2 ? "# " : "### NON-COMPLIANT! ### "; @@ -14474,15 +14565,15 @@ SwitchClocks(int newMoveNr) if(blackNPS >= 0) lastTickLength = 0; blackTimeRemaining -= lastTickLength; /* [HGM] PGNtime: save time for PGN file if engine did not give it */ -// if(pvInfoList[forwardMostMove-1].time == -1) - pvInfoList[forwardMostMove-1].time = // use GUI time +// if(pvInfoList[forwardMostMove].time == -1) + pvInfoList[forwardMostMove].time = // use GUI time (timeRemaining[1][forwardMostMove-1] - blackTimeRemaining)/10; } else { if(whiteNPS >= 0) lastTickLength = 0; whiteTimeRemaining -= lastTickLength; /* [HGM] PGNtime: save time for PGN file if engine did not give it */ -// if(pvInfoList[forwardMostMove-1].time == -1) - pvInfoList[forwardMostMove-1].time = +// if(pvInfoList[forwardMostMove].time == -1) + pvInfoList[forwardMostMove].time = (timeRemaining[0][forwardMostMove-1] - whiteTimeRemaining)/10; } flagged = CheckFlags();