X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=2df9b7dea0b8a694be57cd3e2f8c920059be58d8;hb=ee20915c04987acfee544c7fa37b856a791d3960;hp=1e1f78a6a49393886f1ec6a7d547d5b050878bcf;hpb=6112f15dc9df5810f2e487f32302c251069c2333;p=xboard.git diff --git a/backend.c b/backend.c index 1e1f78a..2df9b7d 100644 --- a/backend.c +++ b/backend.c @@ -243,6 +243,7 @@ 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 */ +int partnerHighlight[2]; Boolean partnerBoardValid = 0; char partnerStatus[MSG_SIZ]; Boolean partnerUp; @@ -1107,6 +1108,11 @@ InitBackEnd3 P((void)) InitChessProgram(&first, startedFromSetupPosition); + if(!appData.noChessProgram) { /* [HGM] tidy: redo program version to use name from myname feature */ + free(programVersion); + programVersion = (char*) malloc(8 + strlen(PACKAGE_STRING) + strlen(first.tidy)); + sprintf(programVersion, "%s + %s", PACKAGE_STRING, first.tidy); + } if (appData.icsActive) { #ifdef WIN32 @@ -1345,6 +1351,19 @@ establish() } } +void EscapeExpand(char *p, char *q) +{ // [HGM] initstring: routine to shape up string arguments + while(*p++ = *q++) if(p[-1] == '\\') + switch(*q++) { + case 'n': p[-1] = '\n'; break; + case 'r': p[-1] = '\r'; break; + case 't': p[-1] = '\t'; break; + case '\\': p[-1] = '\\'; break; + case 0: *p = 0; return; + default: p[-1] = q[-1]; break; + } +} + void show_bytes(fp, buf, count) FILE *fp; @@ -1977,7 +1996,7 @@ void VariantSwitch(Board board, VariantClass newVariant) { int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j; - Board oldBoard; + static Board oldBoard; startedFromPositionFile = FALSE; if(gameInfo.variant == newVariant) return; @@ -2705,7 +2724,7 @@ read_from_ics(isr, closure, data, count, error) if (appData.autoKibitz && started == STARTED_NONE && !appData.icsEngineAnalyze && // [HGM] [DM] ICS analyze (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || gameMode == IcsObserving)) { - if(looking_at(buf, &i, "* kibitzes: ") && + if((looking_at(buf, &i, "* kibitzes: ") || looking_at(buf, &i, "* whispers: ")) && (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; @@ -2744,6 +2763,7 @@ read_from_ics(isr, closure, data, count, error) 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, "* kibitzes:") || looking_at(buf, &i, "* shouts:") || looking_at(buf, &i, "* c-shouts:") || looking_at(buf, &i, "--> * ") || @@ -2763,6 +2783,13 @@ read_from_ics(isr, closure, data, count, error) chattingPartner = p; break; } } else + if(buf[i-3] == 'e') // kibitz; look if there is a KIBITZ chatbox + for(p=0; p') // shout, c-shout or it; look if there is a 'shouts' chatbox - for(p=0; p') {// shout, c-shout or it; look if there is a 'shouts' chatbox + if(buf[i-8] == '-' && buf[i-3] == 't') + for(p=0; p') { talker[0] = '<'; strcat(talker, "> "); Colorize(ColorShout, FALSE); } else if(buf[i-8] == '-') { talker[0] = '('; strcat(talker, ") "); Colorize(ColorSShout, FALSE); } else { talker[0] = '['; strcat(talker, "] "); Colorize(ColorShout, FALSE); } chattingPartner = p; break; } + } } if(chattingPartner<0) // if not, look if there is a chatbox for this indivdual for(p=0; p appData.drawRepeats-2 + if( rights == 0 && ++count > appData.drawRepeats-2 && canAdjudicate && appData.drawRepeats > 1) { /* adjudicate after user-specified nr of repeats */ - if(engineOpponent) { - SendToProgram("force\n", engineOpponent); // suppress reply - SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ - } - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + int result = GameIsDrawn; + char *details = "XBoard adjudication: repetition draw"; if(gameInfo.variant == VariantXiangqi && appData.testLegality) { // [HGM] xiangqi: check for forbidden perpetuals int m, ourPerpetual = 1, hisPerpetual = 1; @@ -6811,27 +6856,31 @@ Adjudicate(ChessProgramState *cps) if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n", ourPerpetual, hisPerpetual); if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit - GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, - "Xboard adjudication: perpetual checking", GE_XBOARD ); - return 1; - } - if(hisPerpetual && !ourPerpetual) // he is checking us, but did not repeat yet + result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; + details = "Xboard adjudication: perpetual checking"; + } else + if(hisPerpetual && !ourPerpetual) { // he is checking us, but did not repeat yet break; // (or we would have caught him before). Abort repetition-checking loop. + } else // Now check for perpetual chases if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase hisPerpetual = PerpetualChase(k, forwardMostMove); ourPerpetual = PerpetualChase(k+1, forwardMostMove); if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit - GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, - "Xboard adjudication: perpetual chasing", GE_XBOARD ); - return 1; - } + result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; + details = "Xboard adjudication: perpetual chasing"; + } else if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet break; // Abort repetition-checking loop. } // if neither of us is checking or chasing all the time, or both are, it is draw } - GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD ); + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( result, details, GE_XBOARD ); return 1; } if( rights == 0 && count > 1 ) /* occurred 2 or more times before */ @@ -6848,6 +6897,17 @@ Adjudicate(ChessProgramState *cps) if( count == backwardMostMove ) count -= initialRulePlies; count = forwardMostMove - count; + if(gameInfo.variant == VariantXiangqi && ( count >= 100 || count >= 2*appData.ruleMoves ) ) { + // adjust reversible move counter for checks in Xiangqi + int i = forwardMostMove - count, inCheck = 0, lastCheck; + if(i < backwardMostMove) i = backwardMostMove; + while(i <= forwardMostMove) { + lastCheck = inCheck; // check evasion does not count + inCheck = (MateTest(boards[i], PosFlags(i)) == MT_CHECK); + if(inCheck || lastCheck) count--; // check does not count + i++; + } + } if( count >= 100) boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; /* this is used to judge if draw claims are legal */ @@ -6916,8 +6976,7 @@ char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial) // after a book hit we never send 'go', and the code after the call to this routine // has '&& !bookHit' added to suppress potential sending there (based on 'firstMove'). char buf[MSG_SIZ]; - if (cps->useUsermove) sprintf(buf, "usermove "); // sorry, no SAN yet :( - sprintf(buf, "%s\n", bookHit); // force book move into program supposed to play it + sprintf(buf, "%s%s\n", (cps->useUsermove ? "usermove " : ""), bookHit); // force book move into program supposed to play it SendToProgram(buf, cps); if(!initial) firstMove = FALSE; // normally we would clear the firstMove condition after return & sending 'go' } else if(initial) { // 'go' was needed irrespective of firstMove, and it has to be done in this routine @@ -7134,6 +7193,11 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h strcat(machineMove, "\n"); strcpy(moveList[forwardMostMove], machineMove); + /* [AS] Save move info*/ + pvInfoList[ forwardMostMove ].score = programStats.score; + pvInfoList[ forwardMostMove ].depth = programStats.depth; + pvInfoList[ forwardMostMove ].time = programStats.time; // [HGM] PGNtime: take time from engine stats + MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/ /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */ @@ -7193,10 +7257,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } #endif - /* [AS] Save move info and clear stats for next move */ - pvInfoList[ forwardMostMove-1 ].score = programStats.score; - pvInfoList[ forwardMostMove-1 ].depth = programStats.depth; - pvInfoList[ forwardMostMove-1 ].time = programStats.time; // [HGM] PGNtime: take time from engine stats + /* [AS] Clear stats for next move */ ClearProgramStats(); thinkOutput[0] = NULLCHAR; hiddenThinkOutputState = 0; @@ -7302,11 +7363,13 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. * Look for communication commands */ if (!strncmp(message, "telluser ", 9)) { + EscapeExpand(message+9, message+9); // [HGM] esc: allow escape sequences in popup box DisplayNote(message + 9); return; } if (!strncmp(message, "tellusererror ", 14)) { cps->userError = 1; + EscapeExpand(message+14, message+14); // [HGM] esc: allow escape sequences in popup box DisplayError(message + 14, 0); return; } @@ -7760,6 +7823,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } if (!ignore) { + ChessProgramStats tempStats = programStats; // [HGM] info: filter out info lines buf1[0] = NULLCHAR; if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n", &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) { @@ -7781,11 +7845,11 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } - programStats.depth = plylev; - programStats.nodes = nodes; - programStats.time = time; - programStats.score = curscore; - programStats.got_only_move = 0; + tempStats.depth = plylev; + tempStats.nodes = nodes; + tempStats.time = time; + tempStats.score = curscore; + tempStats.got_only_move = 0; if(cps->nps >= 0) { /* [HGM] nps: use engine nodes or time to decrement clock */ int ticklen; @@ -7802,31 +7866,34 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. /* Buffer overflow protection */ if (buf1[0] != NULLCHAR) { - if (strlen(buf1) >= sizeof(programStats.movelist) + if (strlen(buf1) >= sizeof(tempStats.movelist) && appData.debugMode) { fprintf(debugFP, "PV is too long; using the first %u bytes.\n", - (unsigned) sizeof(programStats.movelist) - 1); + (unsigned) sizeof(tempStats.movelist) - 1); } - safeStrCpy( programStats.movelist, buf1, sizeof(programStats.movelist) ); + safeStrCpy( tempStats.movelist, buf1, sizeof(tempStats.movelist) ); } else { - sprintf(programStats.movelist, " no PV\n"); + sprintf(tempStats.movelist, " no PV\n"); } - if (programStats.seen_stat) { - programStats.ok_to_send = 1; + if (tempStats.seen_stat) { + tempStats.ok_to_send = 1; } - if (strchr(programStats.movelist, '(') != NULL) { - programStats.line_is_book = 1; - programStats.nr_moves = 0; - programStats.moves_left = 0; + if (strchr(tempStats.movelist, '(') != NULL) { + tempStats.line_is_book = 1; + tempStats.nr_moves = 0; + tempStats.moves_left = 0; } else { - programStats.line_is_book = 0; + tempStats.line_is_book = 0; } - SendProgramStatsToFrontend( cps, &programStats ); + if(tempStats.score != 0 || tempStats.nodes != 0 || tempStats.time != 0) + programStats = tempStats; // [HGM] info: only set stats if genuine PV and not an info line + + SendProgramStatsToFrontend( cps, &tempStats ); /* [AS] Protect the thinkOutput buffer from overflow... this @@ -8525,7 +8592,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar) if( (boards[forwardMostMove][fromY][fromX] == WhitePawn || boards[forwardMostMove][fromY][fromX] == BlackPawn ) && boards[forwardMostMove][toY][toX] == EmptySquare - && fromX != toX ) + && fromX != toX && fromY != toY) fprintf(serverMoves, ":%c%c:%c%c", AAA+fromX, ONE+fromY, AAA+toX, ONE+fromY); // promotion suffix if(promoChar != NULLCHAR) @@ -15179,3 +15246,4 @@ LoadVariation(int index, char *text) CommentPopDown(); ToNrEvent(currentMove+1); } +