X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=79774fa7003ea717deb6d23389dd602b580be281;hb=7937bbea6d9e0644cd8a5c39e2c6d6320368945a;hp=47b443bc4698f268f821884085c70ac0a79aa7a6;hpb=6af61ce31b024cb65ba65e3b22586bc12839915d;p=xboard.git diff --git a/backend.c b/backend.c index 47b443b..79774fa 100644 --- a/backend.c +++ b/backend.c @@ -913,13 +913,66 @@ InitEngine (ChessProgramState *cps, int n) ChessProgramState *savCps; -GameMode oldMode; +GameMode oldMode, tryNr; + +extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params; +extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; +char *insert, *wbOptions, *currentEngine[2]; // point in ChessProgramNames were we should insert new engine +static char newEngineCommand[MSG_SIZ]; + +void +FloatToFront(char **list, char *engineLine) +{ + char buf[MSG_SIZ], tidy[MSG_SIZ], *p = buf, *q, *r = buf; + int i=0; + if(appData.recentEngines <= 0) return; + TidyProgramName(engineLine, "localhost", tidy+1); + tidy[0] = buf[0] = '\n'; strcat(tidy, "\n"); + strncpy(buf+1, *list, MSG_SIZ-50); + if(p = strstr(buf, tidy)) { // tidy name appears in list + q = strchr(++p, '\n'); if(q == NULL) return; // malformed, don't touch + while(*p++ = *++q); // squeeze out + } + strcat(tidy, buf+1); // put list behind tidy name + p = tidy + 1; while(q = strchr(p, '\n')) i++, r = p, p = q + 1; // count entries in new list + if(i > appData.recentEngines) *r = NULLCHAR; // if maximum rached, strip off last + ASSIGN(*list, tidy+1); +} + +void +AddToEngineList (int i) +{ + int len; + char quote, buf[MSG_SIZ]; + char *q = firstChessProgramNames, *p = newEngineCommand; + if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR; + quote = strchr(p, '"') ? '\'' : '"'; // use single quotes around engine command if it contains double quotes + snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s", + quote, p, quote, appData.directory[i], + useNick ? " -fn \"" : "", + useNick ? nickName : "", + useNick ? "\"" : "", + v1 ? " -firstProtocolVersion 1" : "", + hasBook ? "" : " -fNoOwnBookUCI", + isUCI ? (isUCI == TRUE ? " -fUCI" : gameInfo.variant == VariantShogi ? " -fUSI" : " -fUCCI") : "", + storeVariant ? " -variant " : "", + storeVariant ? VariantName(gameInfo.variant) : ""); + if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " %s", wbOptions); + firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 2); + if(insert != q) insert[-1] = NULLCHAR; + snprintf(firstChessProgramNames, len, "%s\n%s\n%s", q, buf, insert); + if(q) free(q); + FloatToFront(&appData.recentEngineList, buf); + ASSIGN(currentEngine[i], buf); +} void LoadEngine () { int i; if(WaitForEngine(savCps, LoadEngine)) return; + if(tryNr == 1 && !isUCI) { SendToProgram("uci\n", savCps); tryNr = 2; ScheduleDelayedEvent(LoadEngine, FEATURE_TIMEOUT); return; } + if(tryNr) v1 = (tryNr == 2), tryNr = 0, AddToEngineList(0); // deferred to after protocol determination CommonEngineInit(); // recalculate time odds if(gameInfo.variant != StringToVariant(appData.variant)) { // we changed variant when loading the engine; this forces us to reset @@ -953,9 +1006,6 @@ ReplaceEngine (ChessProgramState *cps, int n) LoadEngine(); } -extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params; -extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; - static char resetOptions[] = "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 " "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" " @@ -963,27 +1013,6 @@ static char resetOptions[] = "-firstOptions \"\" -firstNPS -1 -fn \"\" -firstScoreAbs false"; void -FloatToFront(char **list, char *engineLine) -{ - char buf[MSG_SIZ], tidy[MSG_SIZ], *p = buf, *q, *r = buf; - int i=0; - if(appData.recentEngines <= 0) return; - TidyProgramName(engineLine, "localhost", tidy+1); - tidy[0] = buf[0] = '\n'; strcat(tidy, "\n"); - strncpy(buf+1, *list, MSG_SIZ-50); - if(p = strstr(buf, tidy)) { // tidy name appears in list - q = strchr(++p, '\n'); if(q == NULL) return; // malformed, don't touch - while(*p++ = *++q); // squeeze out - } - strcat(tidy, buf+1); // put list behind tidy name - p = tidy + 1; while(q = strchr(p, '\n')) i++, r = p, p = q + 1; // count entries in new list - if(i > appData.recentEngines) *r = NULLCHAR; // if maximum rached, strip off last - ASSIGN(*list, tidy+1); -} - -char *insert, *wbOptions, *currentEngine[2]; // point in ChessProgramNames were we should insert new engine - -void Load (ChessProgramState *cps, int i) { char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ], buf3[MSG_SIZ], jar; @@ -1025,30 +1054,8 @@ Load (ChessProgramState *cps, int i) appData.hasOwnBookUCI[i] = hasBook; if(!nickName[0]) useNick = FALSE; if(useNick) ASSIGN(appData.pgnName[i], nickName); - if(addToList) { - int len; - char quote; - q = firstChessProgramNames; - if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR; - quote = strchr(p, '"') ? '\'' : '"'; // use single quotes around engine command if it contains double quotes - snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s", - quote, p, quote, appData.directory[i], - useNick ? " -fn \"" : "", - useNick ? nickName : "", - useNick ? "\"" : "", - v1 ? " -firstProtocolVersion 1" : "", - hasBook ? "" : " -fNoOwnBookUCI", - isUCI ? (isUCI == TRUE ? " -fUCI" : gameInfo.variant == VariantShogi ? " -fUSI" : " -fUCCI") : "", - storeVariant ? " -variant " : "", - storeVariant ? VariantName(gameInfo.variant) : ""); - if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " %s", wbOptions); - firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 2); - if(insert != q) insert[-1] = NULLCHAR; - snprintf(firstChessProgramNames, len, "%s\n%s\n%s", q, buf, insert); - if(q) free(q); - FloatToFront(&appData.recentEngineList, buf); - ASSIGN(currentEngine[i], buf); - } + safeStrCpy(newEngineCommand, p, MSG_SIZ); + tryNr = 1; ReplaceEngine(cps, i); } @@ -4741,7 +4748,13 @@ ParseBoard12 (char *string) boards[moveNum][EP_STATUS] = EP_NONE; if(str[0] == 'P') boards[moveNum][EP_STATUS] = EP_PAWN_MOVE; if(strchr(move_str, 'x')) boards[moveNum][EP_STATUS] = EP_CAPTURE; - if(double_push != -1) boards[moveNum][EP_STATUS] = double_push + BOARD_LEFT; + if(double_push != -1) { + int dir = WhiteOnMove(moveNum) ? 1 : -1, last = BOARD_HEIGHT-1; + boards[moveNum][EP_FILE] = // also set new e.p. variables + boards[moveNum][EP_STATUS] = double_push + BOARD_LEFT; + boards[moveNum][EP_RANK] = (last + 3*dir)/2; + boards[moveNum][LAST_TO] = 128*(last + dir) + boards[moveNum][EP_FILE]; + } else boards[moveNum][EP_FILE] = boards[moveNum][EP_RANK] = 100; if (ics_getting_history == H_GOT_REQ_HEADER || @@ -6342,10 +6355,11 @@ InitPosition (int redraw) shuffleOpenings = 1; break; case VariantNoCastle: - pieces = FIDEArray; - nrCastlingRights = 0; /* !!?unconstrained back-rank shuffle */ shuffleOpenings = 1; + case VariantSuicide: + pieces = FIDEArray; + nrCastlingRights = 0; break; } @@ -7581,6 +7595,7 @@ void ReportClick(char *action, int x, int y) Boolean right; // instructs front-end to use button-1 events as if they were button 3 Boolean deferChoice; +int createX = -1, createY = -1; // square where we last created a piece in EditPosition mode void LeftClick (ClickType clickType, int xPix, int yPix) @@ -7618,13 +7633,16 @@ LeftClick (ClickType clickType, int xPix, int yPix) } else if(y == BOARD_HEIGHT-1) { handOffsets &= ~2; DrawPosition(TRUE, boards[currentMove]); return; } } - if(appData.monoMouse && gameMode == EditPosition && fromX < 0 && clickType == Press && boards[currentMove][y][x] == EmptySquare) { + if(appData.monoMouse && gameMode == EditPosition && fromX < 0 && clickType == Press && + (boards[currentMove][y][x] == EmptySquare || x == createX && y == createY) ) { static int dummy; RightClick(clickType, xPix, yPix, &dummy, &dummy); right = TRUE; return; } + createX = createY = -1; + if(SeekGraphClick(clickType, xPix, yPix, 0)) return; prevClickTime = lastClickTime; GetTimeMark(&lastClickTime); @@ -8055,9 +8073,15 @@ RightClick (ClickType action, int x, int y, int *fromX, int *fromY) if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1; if (xSqr < 0 || ySqr < 0) return -1; if(appData.pieceMenu) { whichMenu = 0; break; } // edit-position menu + if(flipView) xSqr = BOARD_WIDTH - 1 - xSqr; else ySqr = BOARD_HEIGHT - 1 - ySqr; + if(xSqr == createX && ySqr == createY && xSqr != BOARD_LEFT-2 && xSqr != BOARD_RGHT+1) { + ChessSquare p = boards[currentMove][ySqr][xSqr]; + do { if(++p == EmptySquare) p = WhitePawn; } while(PieceToChar(p) == '.'); + boards[currentMove][ySqr][xSqr] = p; DrawPosition(FALSE, boards[currentMove]); + return -2; + } pieceSweep = shiftKey ? BlackPawn : WhitePawn; // [HGM] sweep: prepare selecting piece by mouse sweep - toX = xSqr; toY = ySqr; lastX = x, lastY = y; - if(flipView) toX = BOARD_WIDTH - 1 - toX; else toY = BOARD_HEIGHT - 1 - toY; + createX = toX = xSqr; createY = toY = ySqr; lastX = x, lastY = y; NextPiece(0); return 2; // grab case IcsObserving: @@ -8490,6 +8514,32 @@ Adjudicate (ChessProgramState *cps) return 1; } } else moveCount = 6; + + if(gameInfo.variant == VariantMakruk && // Makruk counting rules + (nrW == 1 || nrB == 1 || nr[WhitePawn] + nr[BlackPawn] == 0)) { // which only kick in when pawnless or bare King + int maxcnt, his, mine, c, wom = WhiteOnMove(forwardMostMove); + count = forwardMostMove; + while(count >= backwardMostMove) { + int np = nr[WhitePawn] + nr[BlackPawn]; + if(wom) mine = nrW, his = nrB, c = BlackPawn; + else mine = nrB, his = nrW, c = WhitePawn; + if(mine > 1 && np) { count++; break; } + if(mine > 1) maxcnt = 64; else + maxcnt = (nr[WhiteRook+c] > 1 ? 8 : nr[WhiteRook+c] ? 16 : nr[WhiteMan+c] > 1 ? 22 : + nr[WhiteKnight+c] > 1 ? 32 : nr[WhiteMan+c] ? 44 : 64) - his - 1; + while(boards[count][EP_STATUS] != EP_CAPTURE && count > backwardMostMove) count--; // seek previous character + if(count == backwardMostMove) break; + if(forwardMostMove - count >= 2*maxcnt + 1 - (mine == 1)) break; + Count(boards[--count], nr, &nrW, &nrB, &staleW, &staleB, &bishopColor); + } + if(forwardMostMove - count >= 2*maxcnt + 1 - (mine == 1)) { + boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; + if(canAdjudicate && appData.ruleMoves >= 0) { + GameEnds( GameIsDrawn, "Xboard adjudication: counting rule", GE_XBOARD ); + return 1; + } + } + } } // Repetition draws and 50-move rule can be applied independently of legality testing @@ -8598,7 +8648,7 @@ Adjudicate (ChessProgramState *cps) i++; } } - if( count >= 100) + if( count >= 100 && gameInfo.variant != VariantMakruk) // do not accept 50-move claims in Makruk boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; /* this is used to judge if draw claims are legal */ if(canAdjudicate && appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) { @@ -9184,7 +9234,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h cps->useSigterm = FALSE; } if (strncmp(message, "feature ", 8) == 0) { // [HGM] moved forward to pre-empt non-compliant commands - ParseFeatures(message+8, cps); + ParseFeatures(message+8, cps); if(tryNr < 3) tryNr = 3; return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands! } @@ -9395,6 +9445,11 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h first.highlight = f; return; } + if(strncmp(message, "uciok", 5) == 0) { // response to "uci" probe + appData.isUCI[0] = isUCI = 1; + ReplaceEngine(&first, 0); // retry install as UCI + return; + } /* * If the move is illegal, cancel it and redraw the board. * Also deal with other error cases. Matching is rather loose