X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=e670eaf7808d8187eda4cc37453e350cf37a6cad;hb=ca6061cbffe88ff5eb2332e733e0a534b89cc5e7;hp=9b8194323f98d24af9c4f3b4ba2eaa877dcfd4ad;hpb=84af44b79b8d6ce50f809cac441d21157be5a32b;p=xboard.git diff --git a/backend.c b/backend.c index 9b81943..e670eaf 100644 --- a/backend.c +++ b/backend.c @@ -465,6 +465,7 @@ int have_sent_ICS_logon = 0; int movesPerSession; int suddenDeath, whiteStartMove, blackStartMove; /* [HGM] for implementation of 'any per time' sessions, as in first part of byoyomi TC */ long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement, lastWhite, lastBlack; +Boolean adjustedClock; long timeControl_2; /* [AS] Allow separate time controls */ char *fullTimeControlString = NULL, *nextSession, *whiteTC, *blackTC; /* [HGM] secondary TC: merge of MPS, TC and inc */ long timeRemaining[2][MAX_MOVES]; @@ -618,10 +619,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 @@ -879,6 +880,7 @@ 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 @@ -1665,6 +1667,8 @@ 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 ); @@ -1864,7 +1868,7 @@ SendToICS(s) { int count, outCount, outError; - if (icsPR == NULL) return; + if (icsPR == NoProc) return; count = strlen(s); outCount = OutputMaybeTelnet(icsPR, s, count, &outError); @@ -1883,7 +1887,7 @@ SendToICSDelayed(s,msdelay) { int count, outCount, outError; - if (icsPR == NULL) return; + if (icsPR == NoProc) return; count = strlen(s); if (appData.debugMode) { @@ -3896,7 +3900,7 @@ read_from_ics(isr, closure, data, count, error) #if ZIPPY if (appData.zippyPlay && first.initDone) { ZippyGameEnd(endtype, why); - if (first.pr == NULL) { + if (first.pr == NoProc) { /* Start the next process early so that we'll be ready for the next challenge */ StartChessProgram(&first); @@ -5422,7 +5426,7 @@ char * PvToSAN(char *pv) { static char buf[10*MSG_SIZ]; - int i, k=0, savedEnd=endPV; + int i, k=0, savedEnd=endPV, saveFMM = forwardMostMove; *buf = NULLCHAR; if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV); ParsePV(pv, FALSE, 2); // this appends PV to game, suppressing any display of it @@ -5432,7 +5436,7 @@ PvToSAN(char *pv) k += strlen(buf+k); } snprintf(buf+k, 10*MSG_SIZ-k, "%s", lastParseAttempt); // if we ran into stuff that could not be parsed, print it verbatim - if(forwardMostMove < savedEnd) PopInner(0); + if(forwardMostMove < savedEnd) { PopInner(0); forwardMostMove = saveFMM; } // PopInner would set fmm to endPV! endPV = savedEnd; return buf; } @@ -9435,6 +9439,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar) SwitchClocks(forwardMostMove+1); // [HGM] race: incrementing move nr inside timeRemaining[0][forwardMostMove] = whiteTimeRemaining; timeRemaining[1][forwardMostMove] = blackTimeRemaining; + adjustedClock = FALSE; gameInfo.result = GameUnfinished; if (gameInfo.resultDetails != NULL) { free(gameInfo.resultDetails); @@ -9488,7 +9493,6 @@ ShowMove(fromX, fromY, toX, toY) DrawPosition(FALSE, boards[currentMove]); DisplayBothClocks(); HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); - DisplayBook(currentMove); } void SendEgtPath(ChessProgramState *cps) @@ -9770,6 +9774,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 { @@ -9932,6 +9937,7 @@ SetPlayer(int player) if(mnemonic[i]) { snprintf(buf, MSG_SIZ, "-fcp %s", command[i]); ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE; + appData.firstHasOwnBookUCI = !appData.defNoBook; ParseArgsFromString(buf); } free(engineName); @@ -10034,7 +10040,7 @@ NextTourneyGame(int nr, int *swapColors) matchGame = 1; roundNr = nr / syncInterval + 1; } - if(first.pr != NoProc) return 1; // engines already loaded + if(first.pr != NoProc || second.pr != NoProc) return 1; // engines already loaded // redefine engines, engine dir, etc. NamesToList(firstChessProgramNames, command, mnemonic); // get mnemonics of installed engines @@ -10642,7 +10648,7 @@ Reset(redraw, init) timeRemaining[0][0] = whiteTimeRemaining; timeRemaining[1][0] = blackTimeRemaining; - if (first.pr == NULL) { + if (first.pr == NoProc) { StartChessProgram(&first); } if (init) { @@ -11167,6 +11173,187 @@ PositionMatches(Board b1, Board b2) return TRUE; } +#define Q_PROMO 4 +#define Q_EP 3 +#define Q_BCASTL 2 +#define Q_WCASTL 1 + +int pieceList[256], quickBoard[256]; +ChessSquare pieceType[256] = { EmptySquare }; +Board soughtBoard, reverseBoard; +int counts[EmptySquare], minSought[EmptySquare], minReverse[EmptySquare], maxSought[EmptySquare], maxReverse[EmptySquare]; +Boolean epOK; + +typedef struct { + unsigned char piece, to; +} Move; + +#define DATABASESIZE 10000000 /* good for 100k games */ +Move moveDatabase[DATABASESIZE]; +int movePtr; + +void MakePieceList(Board board, int *counts) +{ + int r, f, n=Q_PROMO; + for(r=0;r fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) { + int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT; + moveDatabase[movePtr++].piece = Q_WCASTL; + quickBoard[sq] = piece; + piece = quickBoard[from]; quickBoard[from] = 0; + moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1; + } else + if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) { + int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4); + moveDatabase[movePtr++].piece = Q_BCASTL; + quickBoard[sq] = piece; + piece = quickBoard[from]; quickBoard[from] = 0; + moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1; + } else + if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) { + quickBoard[(fromY<<4)+toX] = 0; + moveDatabase[movePtr].piece = Q_EP; + moveDatabase[movePtr++].to = (fromY<<4)+toX; + moveDatabase[movePtr].to = sq; + } else + if(promoPiece != pieceType[piece]) { + moveDatabase[movePtr++].piece = Q_PROMO; + moveDatabase[movePtr].to = pieceType[piece] = (int) promoPiece; + } + moveDatabase[movePtr].piece = piece; + quickBoard[sq] = piece; + movePtr++; +} + +int PackGame(Board board) +{ + moveDatabase[movePtr].piece = 0; // terminate previous game + if(movePtr > DATABASESIZE - 500) return 0; // gamble on that game will not be more than 250 moves + movePtr++; + MakePieceList(board, counts); + return movePtr; +} + +int QuickCompare(Board board, int *minCounts, int *maxCounts) +{ // compare according to search mode + int r, f; + switch(appData.searchMode) + { + case 1: // exact position match + for(r=0; r maxCounts[r]) return FALSE; + return TRUE; + } +} + +int QuickScan(Board board, Move *move) +{ // reconstruct game,and compare all positions in it + int cnt=0, stretch=0; + MakePieceList(board, counts); + do { + int piece = move->piece; + int to = move->to, from = pieceList[piece]; + if(piece <= Q_PROMO) { // special moves encoded by otherwise invalid piece numbers 1-4 + if(!piece) return -1; + if(piece == Q_PROMO) { // promotion, encoded as (Q_PROMO, to) + (piece, promoType) + piece = (++move)->piece; + from = pieceList[piece]; + counts[pieceType[piece]]--; + pieceType[piece] = (ChessSquare) move->to; + 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; + move++; + continue; + } else if(piece <= Q_BCASTL) { // castling, encoded as (Q_XCASTL, king-to) + (rook, rook-to) + piece = pieceList[piece]; // first two elements of pieceList contain King numbers + from = pieceList[piece]; // so this must be King + quickBoard[from] = 0; + quickBoard[to] = piece; + pieceList[piece] = to; + move++; + continue; + } + } + if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture + quickBoard[from] = 0; + quickBoard[to] = piece; + pieceList[piece] = to; + cnt++; + if(QuickCompare(soughtBoard, minSought, maxSought) || + appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse)) { + static int lastCounts[EmptySquare+1]; + int i; + if(stretch) for(i=0; i= appData.stretch)) return cnt + 1 - stretch; + move++; + } while(1); +} + +InitSearch() +{ + int r, f; + CopyBoard(soughtBoard, boards[currentMove]); + MakePieceList(soughtBoard, maxSought); + CopyBoard(reverseBoard, boards[currentMove]); + for(r=0; r= 5) { + for(r=BOARD_HEIGHT/2; rgameInfo.variant != gameInfo.variant) return -1; // wrong variant + if(appData.eloThreshold1 && (lg->gameInfo.whiteRating < appData.eloThreshold1 && lg->gameInfo.blackRating < appData.eloThreshold1)) return -1; + if(appData.eloThreshold2 && (lg->gameInfo.whiteRating < appData.eloThreshold2 || lg->gameInfo.blackRating < appData.eloThreshold2)) return -1; + if(appData.dateThreshold && (!lg->gameInfo.date || atoi(lg->gameInfo.date) < appData.dateThreshold)) return -1; if(!initDone) { for(next = WhitePawn; next>8 ^ random()<<6 ^random()<<20; initDone = TRUE; } - dummyInfo.variant = VariantNormal; - FREE(dummyInfo.fen); dummyInfo.fen = NULL; - dummyInfo.whiteRating = 0; - dummyInfo.blackRating = 0; - FREE(dummyInfo.date); dummyInfo.date = NULL; + if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen); + else CopyBoard(boards[scratch], initialPosition); // default start position + if(lg->moves) { + 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. + } + if(btm) plyNr++; + if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr; fseek(f, lg->offset, 0); yynewfile(f); - CopyBoard(boards[scratch], initialPosition); // default start position while(1) { - yyboardindex = scratch + (plyNr&1); - quickFlag = 1; + yyboardindex = scratch; + quickFlag = plyNr+1; next = Myylex(); - quickFlag = 0; + quickFlag = 0; switch(next) { case PGNTag: if(plyNr) return -1; // after we have seen moves, any tags will be start of next game -#if 0 - ParsePGNTag(yy_text, &dummyInfo); // this has a bad memory leak... - if(dummyInfo.fen) ParseFEN(boards[scratch], &btm, dummyInfo.fen), free(dummyInfo.fen), dummyInfo.fen = NULL; -#else - // do it ourselves avoiding malloc - { char *p = yy_text+1, *q; - while(!isdigit(*p) && !isalpha(*p)) p++; - q = p; while(*p != ' ' && *p != '\t' && *p != '\n') p++; - *p = NULLCHAR; - if(!StrCaseCmp(q, "Date") && (p = strchr(p+1, '"'))) { if(atoi(p+1) < appData.dateThreshold) return -1; } else - if(!StrCaseCmp(q, "Variant") && (p = strchr(p+1, '"'))) dummyInfo.variant = StringToVariant(p+1); else - if(!StrCaseCmp(q, "WhiteElo") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else - if(!StrCaseCmp(q, "BlackElo") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else - if(!StrCaseCmp(q, "WhiteUSCF") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else - if(!StrCaseCmp(q, "BlackUSCF") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else - if(!StrCaseCmp(q, "FEN") && (p = strchr(p+1, '"'))) ParseFEN(boards[scratch], &btm, p+1); - } -#endif default: continue; @@ -11268,18 +11444,10 @@ int GameContainsPosition(FILE *f, ListGame *lg) break; } // Move encountered; peform it. We need to shuttle between two boards, as even/odd index determines side to move - if(plyNr == 0) { // but first figure out variant and initial position - if(dummyInfo.variant != gameInfo.variant) return -1; // wrong variant - if(appData.eloThreshold1 && (dummyInfo.whiteRating < appData.eloThreshold1 && dummyInfo.blackRating < appData.eloThreshold1)) return -1; - if(appData.eloThreshold2 && (dummyInfo.whiteRating < appData.eloThreshold2 || dummyInfo.blackRating < appData.eloThreshold2)) return -1; - if(appData.dateThreshold && (!dummyInfo.date || atoi(dummyInfo.date) < appData.dateThreshold)) return -1; - if(btm) CopyBoard(boards[scratch+1], boards[scratch]), plyNr++; - if(PositionMatches(boards[scratch + plyNr], boards[currentMove])) return plyNr; - } - CopyBoard(boards[scratch + (plyNr+1&1)], boards[scratch + (plyNr&1)]); plyNr++; - ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch + (plyNr&1)]); - if(PositionMatches(boards[scratch + (plyNr&1)], boards[currentMove])) return plyNr; + ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch]); + if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr; + if(appData.ignoreColors && PositionMatches(boards[scratch], reverseBoard)) return plyNr; } } @@ -11804,7 +11972,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); } @@ -11876,7 +12044,6 @@ LoadPosition(f, positionNumber, title) } startedFromSetupPosition = TRUE; - SendToProgram("force\n", &first); CopyBoard(boards[0], initial_position); if (blackPlaysFirst) { currentMove = forwardMostMove = backwardMostMove = 1; @@ -11889,7 +12056,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");} @@ -13124,7 +13294,7 @@ int WaitForEngine(ChessProgramState *cps, DelayedEventCallback retry) { char buf[MSG_SIZ]; - if (cps->pr == NULL) { + if (cps->pr == NoProc) { StartChessProgram(cps); if (cps->protocolVersion == 1) { retry(); @@ -13409,9 +13579,11 @@ EditGameEvent() SendToProgram("undo\n", &first); i--; } + if(!adjustedClock) { whiteTimeRemaining = timeRemaining[0][currentMove]; blackTimeRemaining = timeRemaining[1][currentMove]; DisplayBothClocks(); + } if (whiteFlag || blackFlag) { whiteFlag = blackFlag = 0; } @@ -14054,7 +14226,6 @@ ForwardInner(target) if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty DisplayComment(currentMove - 1, commentList[currentMove]); } - DisplayBook(currentMove); } @@ -14167,7 +14338,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 @@ -14805,7 +14975,7 @@ SendToProgram(message, cps) int count, outCount, error; char buf[MSG_SIZ]; - if (cps->pr == NULL) return; + if (cps->pr == NoProc) return; Attention(cps); if (appData.debugMode) { @@ -15735,9 +15905,11 @@ NextTickLength(timeRemaining) void AdjustClock(Boolean which, int dir) { + if(appData.autoCallFlag) { DisplayError(_("Clock adjustment not allowed in auto-flag mode"), 0); return; } if(which) blackTimeRemaining += 60000*dir; else whiteTimeRemaining += 60000*dir; DisplayBothClocks(); + adjustedClock = TRUE; } /* Stop clocks and reset to a fresh time control */ @@ -15761,6 +15933,7 @@ ResetClocks() } lastWhite = lastBlack = whiteStartMove = blackStartMove = 0; DisplayBothClocks(); + adjustedClock = FALSE; } #define FUDGE 25 /* 25ms = 1/40 sec; should be plenty even for 50 Hz clocks */