X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=90b9269f15877453fd0e0316f74212d4017ab383;hb=de0ee08250c127975c1769b1e2f6bd078e39632a;hp=4abf6197f66a6e497c86361379fc26774f12b5b0;hpb=9d5cf883b49ff08738e437514a4d0eb978c23647;p=xboard.git diff --git a/backend.c b/backend.c index 4abf619..90b9269 100644 --- a/backend.c +++ b/backend.c @@ -5,7 +5,7 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -190,7 +190,7 @@ void ParseGameHistory P((char *game)); void ParseBoard12 P((char *string)); void KeepAlive P((void)); void StartClocks P((void)); -void SwitchClocks P((void)); +void SwitchClocks P((int nr)); void StopClocks P((void)); void ResetClocks P((void)); char *PGNDate P((void)); @@ -242,6 +242,8 @@ int endPV = -1; static int exiting = 0; /* [HGM] moved to top */ static int setboardSpoiledMachineBlack = 0 /*, errorExitFlag = 0*/; int startedFromPositionFile = FALSE; Board filePosition; /* [HGM] loadPos */ +Board partnerBoard; /* [HGM] bughouse: for peeking at partner game */ +Boolean partnerUp; char endingGame = 0; /* [HGM] crash: flag to prevent recursion of GameEnds() */ int whiteNPS, blackNPS; /* [HGM] nps: for easily making clocks aware of NPS */ VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */ @@ -2068,6 +2070,7 @@ int suppressKibitz = 0; Boolean soughtPending = FALSE; Boolean seekGraphUp; #define MAX_SEEK_ADS 200 +#define SQUARE 0x80 char *seekAdList[MAX_SEEK_ADS]; int ratingList[MAX_SEEK_ADS], xList[MAX_SEEK_ADS], yList[MAX_SEEK_ADS], seekNrList[MAX_SEEK_ADS], zList[MAX_SEEK_ADS]; float tcList[MAX_SEEK_ADS]; @@ -2086,7 +2089,7 @@ PlotSeekAd(int i) if(r > maxRating) r = maxRating; if(tc < 1.) tc = 1.; if(tc > 95.) tc = 95.; - x = (w-hMargin)* log(tc)/log(100.) + hMargin; + x = (w-hMargin-squareSize/8-7)* log(tc)/log(95.) + hMargin; y = ((double)r - minRating)/(maxRating - minRating) * (h-vMargin-squareSize/8-1) + vMargin; if(ratingList[i] < 0) y = vMargin + squareSize/4; @@ -2095,7 +2098,8 @@ PlotSeekAd(int i) !strstr(seekAdList[i], "bullet") && !strstr(seekAdList[i], "blitz") && !strstr(seekAdList[i], "standard") ) color = 2; - DrawSeekDot(xList[i]=x+3*color, yList[i]=h-1-y, colorList[i]=color); + if(strstr(seekAdList[i], "(C) ")) color |= SQUARE; // plot computer seeks as squares + DrawSeekDot(xList[i]=x+3*(color&~SQUARE), yList[i]=h-1-y, colorList[i]=color); } void @@ -2197,7 +2201,7 @@ DrawSeekGraph() } DrawSeekText("unrated", hMargin+squareSize/8+7, h-1-vMargin-squareSize/4); for(i=1; i<100; i+=(i<10?1:5)) { - int xx = (w-hMargin)* log((double)i)/log(100.) + hMargin; + int xx = (w-hMargin-squareSize/8-7)* log((double)i)/log(95.) + hMargin; DrawSeekAxis(xx, h-1-vMargin, xx, h-6-vMargin-3*(i%10==0)); // TC ticks if(i<=5 || (i>40 ? i%20 : i%10) == 0) { char buf[MSG_SIZ]; @@ -2233,15 +2237,16 @@ int SeekGraphClick(ClickType click, int x, int y, int moving) DisplayMessage(second ? "!" : "", seekAdList[closest]); lastSecond = second; displayed = closest; } - sprintf(buf, "play %d\n", seekNrList[closest]); if(click == Press) { if(moving == 2) zList[closest] = 100; // right-click; push to back on press lastDown = closest; return TRUE; } // on press 'hit', only show info if(moving == 2) return TRUE; // ignore right up-clicks on dot + sprintf(buf, "play %d\n", seekNrList[closest]); SendToICS(ics_prefix); - SendToICS(buf); // should this be "sought all"? + SendToICS(buf); + return TRUE; // let incoming board of started game pop down the graph } else if(click == Release) { // release 'miss' is ignored zList[lastDown] = 100; // make future selection of the rejected ad more difficult if(moving == 2) { // right up-click @@ -2537,6 +2542,7 @@ read_from_ics(isr, closure, data, count, error) sprintf(mess, "%s%s", talker, parse); OutputChatMessage(chattingPartner, mess); chattingPartner = -1; + next_out = i+1; // [HGM] suppress printing in ICS window } else if(!suppressKibitz) // [HGM] kibitz AppendComment(forwardMostMove, StripHighlight(parse), TRUE); @@ -2560,12 +2566,12 @@ read_from_ics(isr, closure, data, count, error) pvInfoList[forwardMostMove-1].score = 100*score; } OutputKibitz(suppressKibitz, parse); - next_out = i+1; // [HGM] suppress printing in ICS window } else { char tmp[MSG_SIZ]; sprintf(tmp, _("your opponent kibitzes: %s"), parse); SendToPlayer(tmp, strlen(tmp)); } + next_out = i+1; // [HGM] suppress printing in ICS window } started = STARTED_NONE; } else { @@ -2581,6 +2587,7 @@ read_from_ics(isr, closure, data, count, error) continue; } started = STARTED_NONE; + if(suppressKibitz) next_out = i+1; } /* Kludge to deal with rcmd protocol */ @@ -2638,10 +2645,12 @@ read_from_ics(isr, closure, data, count, error) continue; } + oldi = i; // [HGM] seekgraph: recognize sought lines and end-of-sought message if(appData.seekGraph) { if(soughtPending && MatchSoughtLine(buf+i)) { i = strstr(buf+i, "rated") - buf; + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); next_out = leftover_start = i; started = STARTED_CHATTER; suppressKibitz = TRUE; @@ -2661,16 +2670,19 @@ read_from_ics(isr, closure, data, count, error) AddAd(star_match[0], star_match[1], atoi(star_match[2+s]), atoi(star_match[3+s]), star_match[4+s][0], star_match[5-3*s], atoi(star_match[7]), TRUE); looking_at(buf, &i, "*% "); // eat prompt + if(oldi > 0 && buf[oldi-1] == '\n') oldi--; // suppress preceding LF, if any + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); next_out = i; // suppress continue; } - if(looking_at(buf, &i, "Ads removed: *\n") || looking_at(buf, &i, "\031(51 * *\031)")) { + if(looking_at(buf, &i, "\nAds removed: *\n") || looking_at(buf, &i, "\031(51 * *\031)")) { char *p = star_match[0]; while(*p) { if(seekGraphUp) RemoveSeekAd(atoi(p)); while(*p && *p++ != ' '); // next } looking_at(buf, &i, "*% "); // eat prompt + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); next_out = i; continue; } @@ -2685,7 +2697,6 @@ read_from_ics(isr, closure, data, count, error) continue; } - oldi = i; // [HGM] kibitz: try to recognize opponent engine-score kibitzes, to divert them to engine-output window if (appData.autoKibitz && started == STARTED_NONE && !appData.icsEngineAnalyze && // [HGM] [DM] ICS analyze @@ -2694,6 +2705,8 @@ read_from_ics(isr, closure, data, count, error) (StrStr(star_match[0], gameInfo.white) == star_match[0] || StrStr(star_match[0], gameInfo.black) == star_match[0] )) { // kibitz of self or opponent suppressKibitz = TRUE; + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); + next_out = i; if((StrStr(star_match[0], gameInfo.white) == star_match[0] && (gameMode == IcsPlayingWhite)) || (StrStr(star_match[0], gameInfo.black) == star_match[0] @@ -2708,24 +2721,29 @@ read_from_ics(isr, closure, data, count, error) } continue; } else - if(looking_at(buf, &i, "kibitzed to *\n") && atoi(star_match[0])) { + if((looking_at(buf, &i, "\nkibitzed to *\n") || looking_at(buf, &i, "kibitzed to *\n") || + looking_at(buf, &i, "\n(kibitzed to *\n") || looking_at(buf, &i, "(kibitzed to *\n")) + && atoi(star_match[0])) { // suppress the acknowledgements of our own autoKibitz char *p; + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); if(p = strchr(star_match[0], ' ')) p[1] = NULLCHAR; // clip off "players)" on FICS SendToPlayer(star_match[0], strlen(star_match[0])); - looking_at(buf, &i, "*% "); // eat prompt + if(looking_at(buf, &i, "*% ")) // eat prompt + suppressKibitz = FALSE; next_out = i; + continue; } } // [HGM] kibitz: end of patch -//if(appData.debugMode) fprintf(debugFP, "hunt for tell, buf = %s\n", buf+i); - // [HGM] chat: intercept tells by users for which we have an open chat window channel = -1; if(started == STARTED_NONE && (looking_at(buf, &i, "* tells you:") || looking_at(buf, &i, "* says:") || looking_at(buf, &i, "* whispers:") || looking_at(buf, &i, "*(*):") && (sscanf(star_match[1], "%d", &channel),1) || - looking_at(buf, &i, "*(*)(*):") && sscanf(star_match[2], "%d", &channel) == 1 )) { + looking_at(buf, &i, "*(*)(*):") && (sscanf(star_match[2], "%d", &channel),1) || + looking_at(buf, &i, "*(*)(*)(*):") && (sscanf(star_match[3], "%d", &channel),1) || + looking_at(buf, &i, "*(*)(*)(*)(*):") && sscanf(star_match[4], "%d", &channel) == 1 )) { int p; sscanf(star_match[0], "%[^(]", talker+1); // strip (C) or (U) off ICS handle chattingPartner = -1; @@ -2750,10 +2768,13 @@ read_from_ics(isr, closure, data, count, error) chattingPartner = p; break; } if(chattingPartner<0) i = oldi; else { + if(oldi > 0 && buf[oldi-1] == '\n') oldi--; + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); started = STARTED_COMMENT; parse_pos = 0; parse[0] = NULLCHAR; savingComment = 3 + chattingPartner; // counts as TRUE suppressKibitz = TRUE; + continue; } } // [HGM] chat: end of patch @@ -3316,10 +3337,10 @@ read_from_ics(isr, closure, data, count, error) looking_at(buf, &i, "It is not your move")) { /* Illegal move */ if (ics_user_moved && forwardMostMove > backwardMostMove) { // only backup if we already moved - currentMove = --forwardMostMove; + currentMove = forwardMostMove-1; DisplayMove(currentMove - 1); /* before DMError */ DrawPosition(FALSE, boards[currentMove]); - SwitchClocks(); + SwitchClocks(forwardMostMove-1); // [HGM] race DisplayBothClocks(); } DisplayMoveError(_("Illegal move (rejected by ICS)")); // [HGM] but always relay error msg @@ -3562,8 +3583,8 @@ read_from_ics(isr, closure, data, count, error) if (appData.debugMode) fprintf(debugFP, "Parsing holdings: %s, currentMove = %d\n", parse, currentMove); - if (sscanf(parse, " game %d", &gamenum) == 1 && - gamenum == ics_gamenum) { + if (sscanf(parse, " game %d", &gamenum) == 1) { + if(gamenum == ics_gamenum) { // [HGM] bughouse: old code if part of foreground game if (gameInfo.variant == VariantNormal) { /* [HGM] We seem to switch variant during a game! * Presumably no holdings were displayed, so we have @@ -3615,6 +3636,17 @@ read_from_ics(isr, closure, data, count, error) DrawPosition(FALSE, boards[currentMove]); DisplayTitle(str); + } else if(appData.bgObserve) { // [HGM] bughouse: holdings of other game => background + sscanf(parse, "game %d white [%s black [%s <- %s", + &gamenum, white_holding, black_holding, + new_piece); + white_holding[strlen(white_holding)-1] = NULLCHAR; + black_holding[strlen(black_holding)-1] = NULLCHAR; + /* [HGM] copy holdings to partner-board holdings area */ + CopyHoldings(partnerBoard, white_holding, WhitePawn); + CopyHoldings(partnerBoard, black_holding, BlackPawn); + if(partnerUp) DrawPosition(FALSE, partnerBoard); + } } /* Suppress following prompt */ if (looking_at(buf, &i, "*% ")) { @@ -3764,6 +3796,26 @@ ParseBoard12(string) break; } + if((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) + && newGameMode == IcsObserving && appData.bgObserve) { + // [HGM] bughouse: don't act on alien boards while we play. Just parse the board and save it */ + char buf[MSG_SIZ]; + for (k = 0; k < ranks; k++) { + for (j = 0; j < files; j++) + board[k][j+gameInfo.holdingsWidth] = CharToPiece(board_chars[(ranks-1-k)*(files+1) + j]); + if(gameInfo.holdingsWidth > 1) { + board[k][0] = board[k][BOARD_WIDTH-1] = EmptySquare; + board[k][1] = board[k][BOARD_WIDTH-2] = (ChessSquare) 0;; + } + } + CopyBoard(partnerBoard, board); + if(partnerUp) DrawPosition(FALSE, partnerBoard); + sprintf(buf, "W: %d:%d B: %d:%d (%d-%d) %c", white_time/60000, (white_time%60000)/1000, + (black_time/60000), (black_time%60000)/1000, white_stren, black_stren, to_play); + DisplayMessage(buf, ""); + return; + } + /* Modify behavior for initial board display on move listing of wild games. */ @@ -5336,6 +5388,8 @@ SendBoard(cps, moveNum) setboardSpoiledMachineBlack = 0; /* [HGM] assume WB 4.2.7 already solves this after sending setboard */ } +static int autoQueen; // [HGM] oneclick + int HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) { @@ -5406,7 +5460,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) *promoChoice = PieceToChar(BlackFerz); // no choice return FALSE; } - if(appData.alwaysPromoteToQueen) { // predetermined + if(autoQueen) { // predetermined if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantLosers) *promoChoice = PieceToChar(BlackKing); // in Suicide Q is the last thing we want else *promoChoice = PieceToChar(BlackQueen); @@ -5547,6 +5601,64 @@ OKToStartUserMove(x, y) return TRUE; } +Boolean +OnlyMove(int *x, int *y, Boolean captures) { + DisambiguateClosure cl; + if (appData.zippyPlay) return FALSE; + switch(gameMode) { + case MachinePlaysBlack: + case IcsPlayingWhite: + case BeginningOfGame: + if(!WhiteOnMove(currentMove)) return FALSE; + break; + case MachinePlaysWhite: + case IcsPlayingBlack: + if(WhiteOnMove(currentMove)) return FALSE; + break; + default: + return FALSE; + } + cl.pieceIn = EmptySquare; + cl.rfIn = *y; + cl.ffIn = *x; + cl.rtIn = -1; + cl.ftIn = -1; + cl.promoCharIn = NULLCHAR; + Disambiguate(boards[currentMove], PosFlags(currentMove), &cl); + if( cl.kind == NormalMove || + cl.kind == AmbiguousMove && captures && cl.captures == 1 || + cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen || + cl.kind == WhitePromotionKnight || cl.kind == BlackPromotionKnight || + cl.kind == WhiteCapturesEnPassant || cl.kind == BlackCapturesEnPassant) { + fromX = cl.ff; + fromY = cl.rf; + *x = cl.ft; + *y = cl.rt; + return TRUE; + } + if(cl.kind != ImpossibleMove) return FALSE; + cl.pieceIn = EmptySquare; + cl.rfIn = -1; + cl.ffIn = -1; + cl.rtIn = *y; + cl.ftIn = *x; + cl.promoCharIn = NULLCHAR; + Disambiguate(boards[currentMove], PosFlags(currentMove), &cl); + if( cl.kind == NormalMove || + cl.kind == AmbiguousMove && captures && cl.captures == 1 || + cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen || + cl.kind == WhitePromotionKnight || cl.kind == BlackPromotionKnight || + cl.kind == WhiteCapturesEnPassant || cl.kind == BlackCapturesEnPassant) { + fromX = cl.ff; + fromY = cl.rf; + *x = cl.ft; + *y = cl.rt; + autoQueen = TRUE; // act as if autoQueen on when we click to-square + return TRUE; + } + return FALSE; +} + FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL; int lastLoadGameNumber = 0, lastLoadPositionNumber = 0; int lastLoadGameUseList = FALSE; @@ -6036,7 +6148,10 @@ void LeftClick(ClickType clickType, int xPix, int yPix) || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) ) return; + autoQueen = appData.alwaysPromoteToQueen; + if (fromX == -1) { + if(!appData.oneClick || !OnlyMove(&x, &y, FALSE)) { if (clickType == Press) { /* First square */ if (OKToStartUserMove(x, y)) { @@ -6051,6 +6166,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) } } return; + } } /* fromX != -1 */ @@ -6076,6 +6192,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) !(fromP == BlackKing && toP == BlackRook && frc))) { /* Clicked again on same color piece -- changed his mind */ second = (x == fromX && y == fromY); + if(!second || !OnlyMove(&x, &y, TRUE)) { if (appData.highlightDragging) { SetHighlights(x, y, -1, -1); } else { @@ -6088,6 +6205,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) DragPieceBegin(xPix, yPix); } return; + } } // ignore clicks on holdings if(x < BOARD_LEFT || x >= BOARD_RGHT) return; @@ -6206,6 +6324,13 @@ int RightClick(ClickType action, int x, int y, int *fromX, int *fromY) return -2; } + if((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) + && !appData.zippyPlay && appData.bgObserve) { // [HGM] bughouse: show background game + if(action == Press) { flipView = !flipView; DrawPosition(TRUE, partnerBoard); partnerUp = TRUE; } else + if(action == Release) { flipView = !flipView; DrawPosition(TRUE, boards[currentMove]); partnerUp = FALSE; } + return -2; + } + xSqr = EventToSquare(x, BOARD_WIDTH); ySqr = EventToSquare(y, BOARD_HEIGHT); if (action == Release) UnLoadPV(); // [HGM] pv @@ -7219,9 +7344,9 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. gameMode = EditGame; ModeHighlight(); } - currentMove = --forwardMostMove; + currentMove = forwardMostMove-1; DisplayMove(currentMove-1); /* before DisplayMoveError */ - SwitchClocks(); + SwitchClocks(forwardMostMove-1); // [HGM] race DisplayBothClocks(); sprintf(buf1, _("Illegal move \"%s\" (rejected by %s chess program)"), parseList[currentMove], cps->which); @@ -8294,8 +8419,8 @@ MakeMove(fromX, fromY, toX, toY, promoChar) } CopyBoard(boards[forwardMostMove+1], boards[forwardMostMove]); ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove+1]); - forwardMostMove++; // [HGM] bare: moved to after ApplyMove, to make sure clock interrupt finds complete board - SwitchClocks(); // uses forwardMostMove, so must be done after incrementing it ! + // forwardMostMove++; // [HGM] bare: moved to after ApplyMove, to make sure clock interrupt finds complete board + SwitchClocks(forwardMostMove+1); // [HGM] race: incrementing move nr inside timeRemaining[0][forwardMostMove] = whiteTimeRemaining; timeRemaining[1][forwardMostMove] = blackTimeRemaining; gameInfo.result = GameUnfinished; @@ -8653,6 +8778,8 @@ GameEnds(result, resultDetails, whosays) result, resultDetails ? resultDetails : "(null)", whosays); } + fromX = fromY = -1; // [HGM] abort any move the user is entering. + if (appData.icsActive && (whosays == GE_ENGINE || whosays >= GE_ENGINE1)) { /* If we are playing on ICS, the server decides when the game is over, but the engine can offer to draw, claim @@ -13962,7 +14089,7 @@ DecrementClocks() from the color that is *not* on move now. */ void -SwitchClocks() +SwitchClocks(int newMoveNr) { long lastTickLength; TimeMark now; @@ -13972,7 +14099,7 @@ SwitchClocks() if (StopClockTimer() && appData.clockMode) { lastTickLength = SubtractTimeMarks(&now, &tickStartTM); - if (WhiteOnMove(forwardMostMove)) { + if (!WhiteOnMove(forwardMostMove)) { if(blackNPS >= 0) lastTickLength = 0; blackTimeRemaining -= lastTickLength; /* [HGM] PGNtime: save time for PGN file if engine did not give it */ @@ -13989,6 +14116,7 @@ SwitchClocks() } flagged = CheckFlags(); } + forwardMostMove = newMoveNr; // [HGM] race: change stm when no timer interrupt scheduled CheckTimeControl(); if (flagged || !appData.clockMode) return;