X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=5e346e5855e2d6ee197369487cd86934c150d1de;hb=785d5885cd9cc3feec1a1978ed30b83bdaacfb50;hp=7ffbd84199037dc318bff5b448feda98816b20eb;hpb=1f070c3ba500547459ad3df71fbdbad1e5b4b4a0;p=xboard.git diff --git a/backend.c b/backend.c index 7ffbd84..5e346e5 100644 --- a/backend.c +++ b/backend.c @@ -147,12 +147,6 @@ extern int gettimeofday(struct timeval *, struct timezone *); #endif -/* A point in time */ -typedef struct { - long sec; /* Assuming this is >= 32 bits */ - int ms; /* Assuming this is >= 16 bits */ -} TimeMark; - int establish P((void)); void read_from_player P((InputSourceRef isr, VOIDSTAR closure, char *buf, int count, int error)); @@ -168,8 +162,6 @@ int LoadGameOneMove P((ChessMove readAhead)); 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)); 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, @@ -204,7 +196,6 @@ void StopClocks P((void)); void ResetClocks P((void)); char *PGNDate P((void)); void SetGameInfo P((void)); -Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen)); int RegisterMove P((void)); void MakeRegisteredMove P((void)); void TruncateGame P((void)); @@ -213,8 +204,6 @@ void CopyPlayerNameIntoFileName P((char **, char *)); char *SavePart P((char *)); int SaveGameOldStyle P((FILE *)); int SaveGamePGN P((FILE *)); -void GetTimeMark P((TimeMark *)); -long SubtractTimeMarks P((TimeMark *, TimeMark *)); int CheckFlags P((void)); long NextTickLength P((long)); void CheckTimeControl P((void)); @@ -826,7 +815,7 @@ InitEngine(ChessProgramState *cps, int n) len = snprintf(buf, MSG_SIZ, _("protocol version %d not supported"), appData.protocolVersion[n]); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "InitBackEnd1: buffer truncated.\n"); DisplayFatalError(buf, 0, 2); @@ -837,6 +826,7 @@ InitEngine(ChessProgramState *cps, int n) } InitEngineUCI( installDir, cps ); // [HGM] moved here from winboard.c, to make available in xboard + ParseFeatures(appData.featureDefaults, cps); } ChessProgramState *savCps; @@ -1072,7 +1062,7 @@ InitBackEnd1() case VariantKriegspiel: /* need to hide pieces and move details */ /* case VariantFischeRandom: (Fabien: moved below) */ len = snprintf(buf,MSG_SIZ, _("Variant %s supported only in ICS mode"), appData.variant); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "InitBackEnd1: buffer truncated.\n"); DisplayFatalError(buf, 0, 2); @@ -1090,7 +1080,7 @@ InitBackEnd1() case Variant36: default: len = snprintf(buf, MSG_SIZ, _("Unknown variant name %s"), appData.variant); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "InitBackEnd1: buffer truncated.\n"); DisplayFatalError(buf, 0, 2); @@ -1495,7 +1485,7 @@ InitBackEnd3 P((void)) len = snprintf(buf, MSG_SIZ, _("Could not connect to host %s, port %s"), appData.icsHost, appData.icsPort); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "InitBackEnd3: buffer truncated.\n"); DisplayFatalError(buf, err, 1); @@ -1549,7 +1539,7 @@ InitBackEnd3 P((void)) initialMode = Training; } else { len = snprintf(buf, MSG_SIZ, _("Unknown initialMode %s"), appData.initialMode); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "InitBackEnd3: buffer truncated.\n"); DisplayFatalError(buf, 0, 2); @@ -2148,7 +2138,7 @@ StringToVariant(e) break; default: len = snprintf(buf, MSG_SIZ, _("Unknown wild type %d"), wnum); - if( (len > MSG_SIZ) && appData.debugMode ) + if( (len >= MSG_SIZ) && appData.debugMode ) fprintf(debugFP, "StringToVariant: buffer truncated.\n"); DisplayError(buf, 0); @@ -3638,7 +3628,7 @@ read_from_ics(isr, closure, data, count, error) flipView = appData.flipView; DrawPosition(TRUE, boards[currentMove]); DisplayBothClocks(); - snprintf(str, MSG_SIZ, "%s vs. %s", + snprintf(str, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black); DisplayTitle(str); gameMode = IcsIdle; @@ -3865,6 +3855,7 @@ read_from_ics(isr, closure, data, count, error) strncmp(why, "Continuing ", 11) == 0) { gs_gamenum = gamenum; safeStrCpy(gs_kind, strchr(why, ' ') + 1,sizeof(gs_kind)/sizeof(gs_kind[0])); + if(ics_gamenum == -1) // [HGM] only if we are not already involved in a game (because gin=1 sends us such messages) VariantSwitch(boards[currentMove], StringToVariant(gs_kind)); // [HGM] variantswitch: even before we get first board #if ZIPPY if (appData.zippyPlay) { @@ -4052,10 +4043,10 @@ read_from_ics(isr, closure, data, count, error) char wh[16], bh[16]; PackHolding(wh, white_holding); PackHolding(bh, black_holding); - snprintf(str, MSG_SIZ,"[%s-%s] %s-%s", wh, bh, + snprintf(str, MSG_SIZ, "[%s-%s] %s-%s", wh, bh, gameInfo.white, gameInfo.black); } else { - snprintf(str, MSG_SIZ, "%s [%s] vs. %s [%s]", + snprintf(str, MSG_SIZ, _("%s [%s] vs. %s [%s]"), gameInfo.white, white_holding, gameInfo.black, black_holding); } @@ -4779,11 +4770,11 @@ ParseBoard12(string) basetime, increment, (int) gameInfo.variant); } else { if(gameInfo.variant == VariantNormal) - snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d}", + snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d}"), gameInfo.white, white_stren, gameInfo.black, black_stren, basetime, increment); else - snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d %s}", + snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d %s}"), gameInfo.white, white_stren, gameInfo.black, black_stren, basetime, increment, VariantName(gameInfo.variant)); } @@ -4953,6 +4944,12 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar) char promoChar; { char user_move[MSG_SIZ]; + char suffix[4]; + + if(gameInfo.variant == VariantSChess && promoChar) { + snprintf(suffix, 4, "=%c", toX == BOARD_WIDTH<<1 ? ToUpper(promoChar) : ToLower(promoChar)); + if(toX == BOARD_WIDTH>>1) moveType = WhitePromotion; // kludge to do gating at Rook + } else suffix[0] = NULLCHAR; switch (moveType) { default: @@ -4968,7 +4965,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar) case WhiteHSideCastleFR: case BlackHSideCastleFR: /* POP Fabien */ - snprintf(user_move, MSG_SIZ, "o-o\n"); + snprintf(user_move, MSG_SIZ, "o-o%s\n", suffix); break; case WhiteQueenSideCastle: case BlackQueenSideCastle: @@ -4978,7 +4975,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar) case WhiteASideCastleFR: case BlackASideCastleFR: /* POP Fabien */ - snprintf(user_move, MSG_SIZ, "o-o-o\n"); + snprintf(user_move, MSG_SIZ, "o-o-o%s\n",suffix); break; case WhiteNonPromotion: case BlackNonPromotion: @@ -5026,8 +5023,8 @@ UploadGameEvent() int i, last = forwardMostMove; // make sure ICS reply cannot pre-empt us by clearing fmm static char *castlingStrings[4] = { "none", "kside", "qside", "both" }; if(gameMode == IcsObserving || gameMode == IcsPlayingBlack || gameMode == IcsPlayingWhite) { - DisplayError("You cannot do this while you are playing or observing", 0); - return; + DisplayError(_("You cannot do this while you are playing or observing"), 0); + return; } if(gameMode != IcsExamining) { // is this ever not the case? char buf[MSG_SIZ], *p, *fen, command[MSG_SIZ], bsetup = 0; @@ -5139,7 +5136,7 @@ Sweep(int step) else if((int)promoSweep == -1) promoSweep = WhiteKing; else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn; else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing; - if(!step) step = 1; + if(!step) step = -1; } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn || appData.testLegality && (promoSweep == king || gameInfo.variant == VariantShogi && promoSweep != PROMOTED last && last != PROMOTED promoSweep && last != promoSweep)); @@ -6659,7 +6656,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar) gameMode = MachinePlaysBlack; StartClocks(); SetGameInfo(); - snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black); + snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black); DisplayTitle(buf); if (first.sendName) { snprintf(buf, MSG_SIZ,"name %s\n", gameInfo.white); @@ -7629,8 +7626,10 @@ Adjudicate(ChessProgramState *cps) hisPerpetual = PerpetualChase(k, forwardMostMove); ourPerpetual = PerpetualChase(k+1, forwardMostMove); if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit + static char resdet[MSG_SIZ]; result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; - details = "Xboard adjudication: perpetual chasing"; + details = resdet; + snprintf(resdet, MSG_SIZ, "Xboard adjudication: perpetual chasing of %c%c", ourPerpetual>>8, ourPerpetual&255); } else if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet break; // Abort repetition-checking loop. @@ -8119,10 +8118,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands! } - if (!appData.testLegality && !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position + if ((!appData.testLegality || gameInfo.variant == VariantFairy) && + !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position int dummy, s=6; char buf[MSG_SIZ]; - if(appData.icsActive || forwardMostMove != 0 || cps != &first || startedFromSetupPosition) return; + if(appData.icsActive || forwardMostMove != 0 || cps != &first) return; if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf); + if(startedFromSetupPosition) return; ParseFEN(boards[0], &dummy, message+s); DrawPosition(TRUE, boards[0]); startedFromSetupPosition = TRUE; @@ -8655,7 +8656,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if(f = fopen(buf, "w")) { // export PV to applicable PV file fprintf(f, "%5.2f/%-2d %s", curscore/100., plylev, pv); fclose(f); - } else DisplayError("failed writing PV", 0); + } else DisplayError(_("failed writing PV"), 0); } tempStats.depth = plylev; @@ -9538,6 +9539,7 @@ InitChessProgram(cps, setup) hintRequested = FALSE; bookRequested = FALSE; + ParseFeatures(appData.features[cps == &second], cps); // [HGM] allow user to overrule features /* [HGM] some new WB protocol commands to configure engine are sent now, if engine supports them */ /* moved to before sending initstring in 4.3.15, so Polyglot can delay UCI 'isready' to recepton of 'new' */ if(cps->memSize) { /* [HGM] memory */ @@ -9924,6 +9926,7 @@ void SwapEngines(int n) SWAP(logo, p) SWAP(pgnName, p) SWAP(pvSAN, h) + SWAP(engOptions, p) } void @@ -10470,6 +10473,7 @@ GameEnds(result, resultDetails, whosays) first.matchWins, second.matchWins, appData.matchGames - (first.matchWins + second.matchWins)); if(!appData.tourneyFile[0]) matchGame++, DisplayTwoMachinesTitle(); // [HGM] update result in window title + if(strcmp(ranking, "busy") && appData.afterTourney && appData.afterTourney[0]) RunCommand(appData.afterTourney); popupRequested++; // [HGM] crash: postpone to after resetting endingGame if (appData.firstPlaysBlack) { // [HGM] match: back to original for next match first.twoMachinesColor = "black\n"; @@ -11182,19 +11186,22 @@ int pieceList[256], quickBoard[256]; ChessSquare pieceType[256] = { EmptySquare }; Board soughtBoard, reverseBoard, flipBoard, rotateBoard; int counts[EmptySquare], minSought[EmptySquare], minReverse[EmptySquare], maxSought[EmptySquare], maxReverse[EmptySquare]; +int soughtTotal, turn; Boolean epOK, flipSearch; typedef struct { unsigned char piece, to; } Move; -#define DATABASESIZE 10000000 /* good for 100k games */ -Move moveDatabase[DATABASESIZE]; -int movePtr; +#define DSIZE (250000) -void MakePieceList(Board board, int *counts) +Move initialSpace[DSIZE+1000]; // gamble on that game will not be more than 500 moves +Move *moveDatabase = initialSpace; +unsigned int movePtr, dataSize = DSIZE; + +int MakePieceList(Board board, int *counts) { - int r, f, n=Q_PROMO; + int r, f, n=Q_PROMO, total=0; for(r=0;r DATABASESIZE - 500) return 0; // gamble on that game will not be more than 250 moves + if(movePtr > dataSize) { + if(appData.debugMode) fprintf(debugFP, "move-cache overflow, enlarge to %d MB\n", dataSize/128); + dataSize *= 8; // increase size by factor 8 (512KB -> 4MB -> 32MB -> 256MB -> 2GB) + if(dataSize) newSpace = (Move*) calloc(8*dataSize + 1000, sizeof(Move)); + if(newSpace) { + int i; + Move *p = moveDatabase, *q = newSpace; + for(i=0; i 8*DSIZE) free(moveDatabase); // and free old space (if it was allocated) + moveDatabase = newSpace; + } else { // calloc failed, we must be out of memory. Too bad... + dataSize = 0; // prevent calloc events for all subsequent games + return 0; // and signal this one isn't cached + } + } movePtr++; MakePieceList(board, counts); return movePtr; @@ -11260,16 +11284,17 @@ int QuickCompare(Board board, int *minCounts, int *maxCounts) switch(appData.searchMode) { case 1: // exact position match + if(!(turn & board[EP_STATUS-1])) return FALSE; // wrong side to move for(r=0; r maxCounts[r]) return FALSE; - return TRUE; } + return TRUE; } int QuickScan(Board board, Move *move) { // reconstruct game,and compare all positions in it - int cnt=0, stretch=0; - MakePieceList(board, counts); + int cnt=0, stretch=0, total = MakePieceList(board, counts); do { int piece = move->piece; int to = move->to, from = pieceList[piece]; @@ -11304,7 +11328,7 @@ int QuickScan(Board board, Move *move) counts[move->to]++; } else if(piece == Q_EP) { // e.p. capture, encoded as (Q_EP, ep-sqr) + (piece, to) counts[pieceType[quickBoard[to]]]--; - quickBoard[to] = 0; + quickBoard[to] = 0; total--; move++; continue; } else if(piece <= Q_BCASTL) { // castling, encoded as (Q_XCASTL, king-to) + (rook, rook-to) @@ -11318,10 +11342,11 @@ int QuickScan(Board board, Move *move) } } if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture + if((total -= (quickBoard[to] != 0)) < soughtTotal) return -1; // piece count dropped below what we search for quickBoard[from] = 0; quickBoard[to] = piece; pieceList[piece] = to; - cnt++; + cnt++; turn ^= 3; if(QuickCompare(soughtBoard, minSought, maxSought) || appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) || flipSearch && (QuickCompare(flipBoard, minSought, maxSought) || @@ -11337,18 +11362,21 @@ int QuickScan(Board board, Move *move) } while(1); } -InitSearch() +void InitSearch() { int r, f; flipSearch = FALSE; CopyBoard(soughtBoard, boards[currentMove]); - MakePieceList(soughtBoard, maxSought); + soughtTotal = MakePieceList(soughtBoard, maxSought); + soughtBoard[EP_STATUS-1] = (currentMove & 1) + 1; + if(currentMove == 0 && gameMode == EditPosition) soughtBoard[EP_STATUS-1] = blackPlaysFirst + 1; // (!) CopyBoard(reverseBoard, boards[currentMove]); for(r=0; rgameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen); else CopyBoard(boards[scratch], initialPosition); // default start position if(lg->moves) { + turn = btm + 1; if((next = QuickScan( boards[scratch], &moveDatabase[lg->moves] )) < 0) return -1; // quick scan rules out it is there if(appData.searchMode >= 4) return next; // for material searches, trust QuickScan. } @@ -11459,6 +11490,7 @@ int GameContainsPosition(FILE *f, ListGame *lg) fromY = DROP_RANK; toX = currentMoveString[2] - AAA; toY = currentMoveString[3] - ONE; + promoChar = 0; break; } // Move encountered; peform it. We need to shuttle between two boards, as even/odd index determines side to move @@ -11540,7 +11572,7 @@ LoadGame(f, gameNumber, title, useList) yynewfile(f); if (lg && lg->gameInfo.white && lg->gameInfo.black) { - snprintf(buf, sizeof(buf), "%s vs. %s", lg->gameInfo.white, + snprintf(buf, sizeof(buf), _("%s vs. %s"), lg->gameInfo.white, lg->gameInfo.black); DisplayTitle(buf); } else if (*title != NULLCHAR) { @@ -12168,7 +12200,7 @@ SaveGameToFile(filename, append) DisplayMessage(_("Waiting for access to save file"), ""); flock(fileno(f), LOCK_EX); // [HGM] lock: lock file while we are writing DisplayMessage(_("Saving game"), ""); - if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError("Bad Seek", errno); // better safe than sorry... + if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError(_("Bad Seek"), errno); // better safe than sorry... result = SaveGame(f, 0, NULL); DisplayMessage(buf, ""); return result; @@ -13155,7 +13187,7 @@ MachineWhiteEvent() pausing = FALSE; ModeHighlight(); SetGameInfo(); - snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black); + snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black); DisplayTitle(buf); if (first.sendName) { snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.black); @@ -13232,7 +13264,7 @@ MachineBlackEvent() pausing = FALSE; ModeHighlight(); SetGameInfo(); - snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black); + snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black); DisplayTitle(buf); if (first.sendName) { snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.white); @@ -13277,24 +13309,24 @@ DisplayTwoMachinesTitle() char buf[MSG_SIZ]; if (appData.matchGames > 0) { if(appData.tourneyFile[0]) { - snprintf(buf, MSG_SIZ, "%s vs. %s (%d/%d%s)", + snprintf(buf, MSG_SIZ, _("%s vs. %s (%d/%d%s)"), gameInfo.white, gameInfo.black, nextGame+1, appData.matchGames+1, appData.tourneyType>0 ? "gt" : appData.tourneyType<0 ? "sw" : "rr"); } else if (first.twoMachinesColor[0] == 'w') { - snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)", + snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"), gameInfo.white, gameInfo.black, first.matchWins, second.matchWins, matchGame - 1 - (first.matchWins + second.matchWins)); } else { - snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)", + snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"), gameInfo.white, gameInfo.black, second.matchWins, first.matchWins, matchGame - 1 - (first.matchWins + second.matchWins)); } } else { - snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black); + snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black); } DisplayTitle(buf); } @@ -14198,6 +14230,8 @@ ForwardInner(target) if (gameMode == EditPosition) return; + MarkTargetSquares(1); + if (gameMode == PlayFromGameFile && !pausing) PauseEvent(); @@ -14303,6 +14337,7 @@ BackwardInner(target) target, currentMove, forwardMostMove); if (gameMode == EditPosition) return; + MarkTargetSquares(1); if (currentMove <= backwardMostMove) { ClearHighlights(); DrawPosition(full_redraw, boards[currentMove]);