X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=43f7926c6102febcc10ae048a2bd430403541ff9;hb=86473f8c47a82552a7766df71bdd7e99a4830181;hp=e4a9031c331b42c28e756443b011024844da52c7;hpb=01bccb194cfca30703d9b49b05a6f2837d67f0f0;p=xboard.git diff --git a/backend.c b/backend.c index e4a9031..43f7926 100644 --- a/backend.c +++ b/backend.c @@ -55,8 +55,6 @@ #ifdef WIN32 #include -#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) ); - int flock(int f, int code); #define LOCK_EX 2 #define SLASH '\\' @@ -64,7 +62,6 @@ int flock(int f, int code); #else #include -#define DoSleep( n ) if( (n) >= 0) sleep(n) #define SLASH '/' #endif @@ -621,10 +618,10 @@ ChessSquare GothicArray[2][BOARD_FILES] = { #ifdef FALCON ChessSquare FalconArray[2][BOARD_FILES] = { - { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen, - WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook }, - { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen, - BlackKing, BlackLance, BlackBishop, BlackKnight, BlackRook } + { WhiteRook, WhiteKnight, WhiteBishop, WhiteFalcon, WhiteQueen, + WhiteKing, WhiteFalcon, WhiteBishop, WhiteKnight, WhiteRook }, + { BlackRook, BlackKnight, BlackBishop, BlackFalcon, BlackQueen, + BlackKing, BlackFalcon, BlackBishop, BlackKnight, BlackRook } }; #else // !FALCON #define FalconArray CapablancaArray @@ -882,16 +879,17 @@ extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; static char resetOptions[] = "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 " + "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" " "-firstOptions \"\" -firstNPS -1 -fn \"\""; void Load(ChessProgramState *cps, int i) { char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ]; - if(engineLine[0]) { // an engine was selected from the combo box + if(engineLine && engineLine[0]) { // an engine was selected from the combo box snprintf(buf, MSG_SIZ, "-fcp %s", engineLine); SwapEngines(i); // kludge to parse -f* / -first* like it is -s* / -second* - ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; + ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE; ParseArgsFromString(buf); SwapEngines(i); ReplaceEngine(cps, i); @@ -907,8 +905,8 @@ Load(ChessProgramState *cps, int i) appData.directory[i] = strdup(engineName); p[-1] = SLASH; } else appData.directory[i] = "."; - if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces if(params[0]) { + if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces snprintf(command, MSG_SIZ, "%s %s", p, params); p = command; } @@ -981,6 +979,7 @@ InitBackEnd1() GetTimeMark(&programStartTime); srandom((programStartTime.ms + 1000*programStartTime.sec)*0x1001001); // [HGM] book: makes sure random is unpredictabe to msec level + appData.seedBase = random() + (random()<<15); pauseStart = programStartTime; pauseStart.sec -= 100; // [HGM] matchpause: fake a pause that has long since ended ClearProgramStats(); @@ -1664,6 +1663,18 @@ InitBackEnd3 P((void)) } } +void +HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current ) +{ + DisplayBook(current+1); + + MoveHistorySet( movelist, first, last, current, pvInfoList ); + + EvalGraphSet( first, last, current, pvInfoList ); + + MakeEngineOutputTitle(); +} + /* * Establish will establish a contact to a remote host.port. * Sets icsPR to a ProcRef for a process (or pseudo-process) @@ -5139,7 +5150,7 @@ int PromoScroll(int x, int y) int step = 0; if(promoSweep == EmptySquare || !appData.sweepSelect) return FALSE; - if(abs(x - lastX) < 15 && abs(y - lastY) < 15) return FALSE; + if(abs(x - lastX) < 25 && abs(y - lastY) < 25) return FALSE; if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1; if(!step) return FALSE; lastX = x; lastY = y; @@ -5467,11 +5478,11 @@ UnLoadPV() void MovePV(int x, int y, int h) { // step through PV based on mouse coordinates (called on mouse move) - int margin = h>>3, step = 0; + int margin = h>>3, step = 0, threshold = (pieceSweep == EmptySquare ? 10 : 15); // we must somehow check if right button is still down (might be released off board!) if(endPV < 0 && pieceSweep == EmptySquare) return; // needed in XBoard because lastX/Y is shared :-( - if(abs(x - lastX) < 7 && abs(y - lastY) < 7) return; + if(abs(x - lastX) < threshold && abs(y - lastY) < threshold) return; if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1; if(!step) return; lastX = x; lastY = y; @@ -8267,7 +8278,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if (StrStr(message, "analyze")) { cps->analysisSupport = FALSE; cps->analyzing = FALSE; - Reset(FALSE, TRUE); +// Reset(FALSE, TRUE); // [HGM] this caused discrepancy between display and internal state! + EditGameEvent(); // [HGM] try to preserve loaded game snprintf(buf2,MSG_SIZ, _("%s does not support analysis"), cps->tidy); DisplayError(buf2, 0); return; @@ -8632,6 +8644,19 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if(appData.pvSAN[cps==&second]) pv = PvToSAN(buf1); + if(serverMoves && (time > 100 || time == 0 && plylev > 7)) { + char buf[MSG_SIZ]; + FILE *f; + snprintf(buf, MSG_SIZ, "%s", appData.serverMovesName); + buf[strlen(buf)-1] = gameMode == MachinePlaysWhite ? 'w' : + gameMode == MachinePlaysBlack ? 'b' : cps->twoMachinesColor[0]; + if(appData.debugMode) fprintf(debugFP, "write PV on file '%s'\n", buf); + 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); + } + tempStats.depth = plylev; tempStats.nodes = nodes; tempStats.time = time; @@ -8917,6 +8942,7 @@ ParseGameHistory(game) break; case WhiteDrop: case BlackDrop: + if(currentMoveString[0] == '@') continue; // no null moves in ICS mode! fromX = moveType == WhiteDrop ? (int) CharToPiece(ToUpper(currentMoveString[0])) : (int) CharToPiece(ToLower(currentMoveString[0])); @@ -9341,6 +9367,11 @@ MakeMove(fromX, fromY, toX, toY, promoChar) { // forwardMostMove++; // [HGM] bare: moved downstream + (void) CoordsToAlgebraic(boards[forwardMostMove], + PosFlags(forwardMostMove), + fromY, fromX, toY, toX, promoChar, + parseList[forwardMostMove]); + if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */ int timeLeft; static int lastLoadFlag=0; int king, piece; piece = boards[forwardMostMove][fromY][fromX]; @@ -9348,10 +9379,14 @@ MakeMove(fromX, fromY, toX, toY, promoChar) if(gameInfo.variant == VariantKnightmate) king += (int) WhiteUnicorn - (int) WhiteKing; if(forwardMostMove == 0) { - if(blackPlaysFirst) + if(gameMode == MachinePlaysBlack || gameMode == BeginningOfGame) + fprintf(serverMoves, "%s;", UserName()); + else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b') fprintf(serverMoves, "%s;", second.tidy); fprintf(serverMoves, "%s;", first.tidy); - if(!blackPlaysFirst) + if(gameMode == MachinePlaysWhite) + fprintf(serverMoves, "%s;", UserName()); + else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w') fprintf(serverMoves, "%s;", second.tidy); } else fprintf(serverMoves, loadFlag|lastLoadFlag ? ":" : ";"); lastLoadFlag = loadFlag; @@ -9372,20 +9407,24 @@ MakeMove(fromX, fromY, toX, toY, promoChar) fprintf(serverMoves, ":%c%c:%c%c", AAA+fromX, ONE+fromY, AAA+toX, ONE+fromY); // promotion suffix if(promoChar != NULLCHAR) - fprintf(serverMoves, ":%c:%c%c", promoChar, AAA+toX, ONE+toY); + fprintf(serverMoves, ":%c:%c%c", ToLower(promoChar), AAA+toX, ONE+toY); if(!loadFlag) { + char buf[MOVE_LEN*2], *p; int len; fprintf(serverMoves, "/%d/%d", pvInfoList[forwardMostMove].depth, pvInfoList[forwardMostMove].score); if(forwardMostMove+1 & 1) timeLeft = whiteTimeRemaining/1000; else timeLeft = blackTimeRemaining/1000; fprintf(serverMoves, "/%d", timeLeft); + strncpy(buf, parseList[forwardMostMove], MOVE_LEN*2); + if(p = strchr(buf, '=')) *p = NULLCHAR; + len = strlen(buf); if(len > 1 && buf[len-2] != '-') buf[len-2] = NULLCHAR; // strip to-square + fprintf(serverMoves, "/%s", buf); } fflush(serverMoves); } - if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations - DisplayFatalError(_("Game too long; increase MAX_MOVES and recompile"), - 0, 1); + if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations.. + GameEnds(GameUnfinished, _("Game too long; increase MAX_MOVES and recompile"), GE_XBOARD); return; } UnLoadPV(); // [HGM] pv: if we are looking at a PV, abort this @@ -9406,10 +9445,6 @@ MakeMove(fromX, fromY, toX, toY, promoChar) } CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar, moveList[forwardMostMove - 1]); - (void) CoordsToAlgebraic(boards[forwardMostMove - 1], - PosFlags(forwardMostMove - 1), - fromY, fromX, toY, toX, promoChar, - parseList[forwardMostMove - 1]); switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) { case MT_NONE: case MT_STALEMATE: @@ -9456,7 +9491,6 @@ ShowMove(fromX, fromY, toX, toY) DrawPosition(FALSE, boards[currentMove]); DisplayBothClocks(); HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); - DisplayBook(currentMove); } void SendEgtPath(ChessProgramState *cps) @@ -9726,6 +9760,7 @@ WriteTourneyFile(char *results, FILE *f) if(f == NULL) DisplayError(_("Could not write on tourney file"), 0); else { // create a file with tournament description fprintf(f, "-participants {%s}\n", appData.participants); + fprintf(f, "-seedBase %d\n", appData.seedBase); fprintf(f, "-tourneyType %d\n", appData.tourneyType); fprintf(f, "-tourneyCycles %d\n", appData.tourneyCycles); fprintf(f, "-defaultMatchGames %d\n", appData.defaultMatchGames); @@ -9737,6 +9772,7 @@ WriteTourneyFile(char *results, FILE *f) fprintf(f, "-loadPositionFile \"%s\"\n", appData.loadPositionFile); fprintf(f, "-loadPositionIndex %d\n", appData.loadPositionIndex); fprintf(f, "-rewindIndex %d\n", appData.rewindIndex); + fprintf(f, "-discourageOwnBooks %s\n", appData.defNoBook ? "true" : "false"); if(searchTime > 0) fprintf(f, "-searchTime \"%d:%02d\"\n", searchTime/60, searchTime%60); else { @@ -9898,7 +9934,8 @@ SetPlayer(int player) for(i=1; command[i]; i++) if(!strcmp(mnemonic[i], engineName)) break; if(mnemonic[i]) { snprintf(buf, MSG_SIZ, "-fcp %s", command[i]); - ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; + ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE; + appData.firstHasOwnBookUCI = !appData.defNoBook; ParseArgsFromString(buf); } free(engineName); @@ -10019,16 +10056,18 @@ NextTourneyGame(int nr, int *swapColors) void NextMatchGame() { // performs game initialization that does not invoke engines, and then tries to start the game - int firstWhite, swapColors = 0; + int res, firstWhite, swapColors = 0; if(!NextTourneyGame(nextGame, &swapColors)) return; // this sets matchGame, -fcp / -scp and other options for next game, if needed firstWhite = appData.firstPlaysBlack ^ (matchGame & 1 | appData.sameColorGames > 1); // non-incremental default firstWhite ^= swapColors; // reverses if NextTourneyGame says we are in an odd round first.twoMachinesColor = firstWhite ? "white\n" : "black\n"; // perform actual color assignement second.twoMachinesColor = firstWhite ? "black\n" : "white\n"; appData.noChessProgram = (first.pr == NoProc); // kludge to prevent Reset from starting up chess program + if(appData.loadGameIndex == -2) srandom(appData.seedBase + 68163*(nextGame & ~1)); // deterministic seed to force same opening Reset(FALSE, first.pr != NoProc); - appData.noChessProgram = FALSE; - if(!LoadGameOrPosition(matchGame)) return; // setup game; abort when bad game/pos file + res = LoadGameOrPosition(matchGame); // setup game + appData.noChessProgram = FALSE; // LoadGameOrPosition might call Reset too! + if(!res) return; // abort when bad game/pos file TwoMachinesEvent(); } @@ -10215,7 +10254,7 @@ GameEnds(result, resultDetails, whosays) if(result==WhiteWins) c = '+'; if(result==BlackWins) c = '-'; if(resultDetails != NULL) - fprintf(serverMoves, ";%c;%s\n", c, resultDetails); + fprintf(serverMoves, ";%c;%s\n", c, resultDetails), fflush(serverMoves); } if (resultDetails != NULL) { gameInfo.result = result; @@ -10409,6 +10448,7 @@ GameEnds(result, resultDetails, whosays) if(waitingForGame) resChar = ' '; // quit while waiting for round sync: unreserve already reserved game if(appData.tourneyFile[0]){ // [HGM] we are in a tourney; update tourney file with game result + if(appData.afterGame && appData.afterGame[0]) RunCommand(appData.afterGame); ReserveGame(nextGame, resChar); // sets nextGame if(nextGame > appData.matchGames) appData.tourneyFile[0] = 0, ranking = TourneyStandings(3); // tourney is done else ranking = strdup("busy"); //suppress popup when aborted but not finished @@ -11141,7 +11181,7 @@ int GameContainsPosition(FILE *f, ListGame *lg) static int initDone=FALSE; if(!initDone) { - for(next = WhitePawn; next>8 ^ rand()<<6 ^rand()<<20; + for(next = WhitePawn; next>8 ^ random()<<6 ^random()<<20; initDone = TRUE; } dummyInfo.variant = VariantNormal; @@ -11768,7 +11808,7 @@ LoadPosition(f, positionNumber, title) lastLoadPositionFP = f; lastLoadPositionNumber = positionNumber; safeStrCpy(lastLoadPositionTitle, title, sizeof(lastLoadPositionTitle)/sizeof(lastLoadPositionTitle[0])); - if (first.pr == NoProc) { + if (first.pr == NoProc && !appData.noChessProgram) { StartChessProgram(&first); InitChessProgram(&first, FALSE); } @@ -11840,7 +11880,6 @@ LoadPosition(f, positionNumber, title) } startedFromSetupPosition = TRUE; - SendToProgram("force\n", &first); CopyBoard(boards[0], initial_position); if (blackPlaysFirst) { currentMove = forwardMostMove = backwardMostMove = 1; @@ -11853,7 +11892,10 @@ LoadPosition(f, positionNumber, title) DisplayMessage("", _("White to play")); } initialRulePlies = FENrulePlies; /* [HGM] copy FEN attributes as well */ - SendBoard(&first, forwardMostMove); + if(first.pr != NoProc) { // [HGM] in tourney-mode a position can be loaded before the chess engine is installed + SendToProgram("force\n", &first); + SendBoard(&first, forwardMostMove); + } if (appData.debugMode) { int i, j; for(i=0;i<2;i++){for(j=0;j<6;j++)fprintf(debugFP, " %d", boards[i][CASTLING][j]);fprintf(debugFP,"\n");} @@ -11919,12 +11961,18 @@ SaveGameToFile(filename, append) { FILE *f; char buf[MSG_SIZ]; - int result; + int result, i, t,tot=0; if (strcmp(filename, "-") == 0) { return SaveGame(stdout, 0, NULL); } else { - f = fopen(filename, append ? "a" : "w"); + for(i=0; i<10; i++) { // upto 10 tries + f = fopen(filename, append ? "a" : "w"); + if(f && i) fprintf(f, "[Delay \"%d retries, %d msec\"]\n",i,tot); + if(f || errno != 13) break; + DoSleep(t = 5 + random()%11); // wait 5-15 msec + tot += t; + } if (f == NULL) { snprintf(buf, sizeof(buf), _("Can't open \"%s\""), filename); DisplayError(buf, errno); @@ -12877,6 +12925,7 @@ AnalyzeFileEvent() StartAnalysisClock(); GetTimeMark(&lastNodeCountTime); lastNodeCount = 0; + if(appData.timeDelay > 0) StartLoadGameTimer((long)(1000.0 * appData.timeDelay)); } void @@ -14011,7 +14060,6 @@ ForwardInner(target) if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty DisplayComment(currentMove - 1, commentList[currentMove]); } - DisplayBook(currentMove); } @@ -14124,7 +14172,6 @@ BackwardInner(target) HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); // [HGM] PV info: routine tests if comment empty DisplayComment(currentMove - 1, commentList[currentMove]); - DisplayBook(currentMove); } void @@ -14617,6 +14664,7 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); if (len == 0) return; if (commentList[index] != NULL) { + Boolean addClosingBrace = addBraces; old = commentList[index]; oldlen = strlen(old); while(commentList[index][oldlen-1] == '\n') @@ -14633,7 +14681,7 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); if(addBraces) strcat(commentList[index], addBraces == 2 ? "\n(" : "\n{\n"); else strcat(commentList[index], "\n"); strcat(commentList[index], text); - if(addBraces) strcat(commentList[index], addBraces == 2 ? ")\n" : "\n}\n"); + if(addClosingBrace) strcat(commentList[index], addClosingBrace == 2 ? ")\n" : "\n}\n"); else strcat(commentList[index], "\n"); } else { commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4... @@ -14733,7 +14781,7 @@ char *GetInfoFromComment( int index, char * text ) while( *++sep >= '0' && *sep <= '9'); // strip seconds if(deci >= 0) while( *++sep >= '0' && *sep <= '9'); // strip fractional seconds - while(*sep == ' ') sep++; + while(*sep == ' ' || *sep == '\n' || *sep == '\r') sep++; } if( depth <= 0 ) {