X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=dd962a39acd391b30de7e570a5ed76ff52bc102b;hb=b5529b539614b61fa62d9f6cc374f335e7103024;hp=96458f271cbe2e6c2237e2d9e6bf5d2fe474ea01;hpb=0a8f96e95c703feb86bb9770442d6842e3d67248;p=xboard.git diff --git a/backend.c b/backend.c index 96458f2..dd962a3 100644 --- a/backend.c +++ b/backend.c @@ -5,7 +5,7 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -148,6 +148,7 @@ extern int gettimeofday(struct timeval *, struct timezone *); #endif #include "backendz.h" #include "evalgraph.h" +#include "engineoutput.h" #include "gettext.h" #ifdef ENABLE_NLS @@ -250,7 +251,6 @@ static int NonStandardBoardSize P((VariantClass v, int w, int h, int s)); #endif ChessProgramState *WhitePlayer(); -void InsertIntoMemo P((int which, char *text)); // [HGM] kibitz: in engineo.c int VerifyDisplayMode P(()); char *GetInfoFromComment( int, char * ); // [HGM] PV time: returns stripped comment @@ -289,6 +289,7 @@ int chattingPartner; char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */ char legal[BOARD_RANKS][BOARD_FILES]; /* [HGM] legal target squares */ char lastMsg[MSG_SIZ]; +char lastTalker[MSG_SIZ]; ChessSquare pieceSweep = EmptySquare; ChessSquare promoSweep = EmptySquare, defaultPromoChoice; int promoDefaultAltered; @@ -415,6 +416,7 @@ PosFlags (index) default: break; } + if(appData.fischerCastling) flags |= F_FRC_TYPE_CASTLING, flags &= ~F_ALL_CASTLE_OK; // [HGM] fischer return flags; } @@ -777,8 +779,7 @@ UnloadEngine (ChessProgramState *cps) ExitAnalyzeMode(); DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", cps); - DoSleep( appData.delayAfterQuit ); - DestroyChildProcess(cps->pr, cps->useSigterm); + DestroyChildProcess(cps->pr, 4 + cps->useSigterm); } cps->pr = NoProc; if(appData.debugMode) fprintf(debugFP, "Unload %s\n", cps->which); @@ -2829,7 +2830,7 @@ read_from_ics (InputSourceRef isr, VOIDSTAR closure, char *data, int count, int int backup; /* [DM] For zippy color lines */ char *p; char talker[MSG_SIZ]; // [HGM] chat - int channel; + int channel, collective=0; connectionAlive = TRUE; // [HGM] alive: I think, therefore I am... @@ -3071,8 +3072,18 @@ read_from_ics (InputSourceRef isr, VOIDSTAR closure, char *data, int count, int char mess[MSG_SIZ]; snprintf(mess, MSG_SIZ, "%s%s", talker, parse); OutputChatMessage(chattingPartner, mess); + if(collective == 1) { // broadcasted talk also goes to private chatbox of talker + int p; + talker[strlen(talker+1)-1] = NULLCHAR; // strip closing delimiter + for(p=0; p= 0) // channel broadcast; look if there is a chatbox for this channel for(p=0; p= '0' && chatPartner[p][0] <= '9' && channel == atoi(chatPartner[p])) { talker[0] = '['; strcat(talker, "] "); - Colorize(channel == 1 ? ColorChannel1 : ColorChannel, FALSE); + Colorize((channel == 1 ? ColorChannel1 : ColorChannel), FALSE); 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 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); } @@ -3332,18 +3348,23 @@ read_from_ics (InputSourceRef isr, VOIDSTAR closure, char *data, int count, int } if(chattingPartner<0) // if not, look if there is a chatbox for this indivdual for(p=0; p 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; + if(collective == 3) i = oldi; else { + suppressKibitz = TRUE; + if(oldi > 0 && buf[oldi-1] == '\n') oldi--; + if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out); + continue; + } } } // [HGM] chat: end of patch @@ -3427,7 +3448,7 @@ read_from_ics (InputSourceRef isr, VOIDSTAR closure, char *data, int count, int parse[parse_pos] = NULLCHAR; started = STARTED_COMMENT; savingComment = TRUE; - } else { + } else if(collective != 3) { started = STARTED_CHATTER; savingComment = FALSE; } @@ -5094,8 +5115,7 @@ SendMoveToProgram (int moveNum, ChessProgramState *cps) /* Added by Tord: Send castle moves in "O-O" in FRC games if required by * the engine. It would be nice to have a better way to identify castle * moves here. */ - if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) - && cps->useOOCastle) { + if(appData.fischerCastling && cps->useOOCastle) { int fromX = moveList[moveNum][0] - AAA; int fromY = moveList[moveNum][1] - ONE; int toX = moveList[moveNum][2] - AAA; @@ -5648,6 +5668,9 @@ LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane) } else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked ExcludeClick(origIndex - lineStart); return FALSE; + } else if(!strncmp(buf+lineStart, "dep\t", 4)) { // column headers clicked + Collapse(origIndex - lineStart); + return FALSE; } ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode); *start = startPV; *end = index-1; @@ -5969,7 +5992,7 @@ InitPosition (int redraw) oldh = gameInfo.holdingsWidth; static int oldv; - if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request + if(appData.icsActive) shuffleOpenings = appData.fischerCastling = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request /* [AS] Initialize pv info list [HGM] and game status */ { @@ -6010,6 +6033,7 @@ InitPosition (int redraw) switch (gameInfo.variant) { case VariantFischeRandom: shuffleOpenings = TRUE; + appData.fischerCastling = TRUE; default: break; case VariantShatranj: @@ -6040,6 +6064,7 @@ InitPosition (int redraw) break; case VariantCapaRandom: shuffleOpenings = TRUE; + appData.fischerCastling = TRUE; case VariantCapablanca: pieces = CapablancaArray; gameInfo.boardWidth = 10; @@ -6520,8 +6545,8 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i promotionZoneSize = 3; } - // Treat Lance as Pawn when it is not representing Amazon - if(gameInfo.variant != VariantSuper) { + // Treat Lance as Pawn when it is not representing Amazon or Lance + if(gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu) { if(piece == WhiteLance) piece = WhitePawn; else if(piece == BlackLance) piece = BlackPawn; } @@ -6791,6 +6816,7 @@ int lastLoadGameUseList = FALSE; char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ]; ChessMove lastLoadGameStart = EndOfFile; int doubleClick; +Boolean addToBookFlag; void UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) @@ -6970,6 +6996,16 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) return; } + if(addToBookFlag) { // adding moves to book + char buf[MSG_SIZ], move[MSG_SIZ]; + CoordsToAlgebraic(boards[currentMove], PosFlags(currentMove), fromY, fromX, toY, toX, promoChar, move); + snprintf(buf, MSG_SIZ, " 0.0%% 1 %s\n", move); + AddBookMove(buf); + addToBookFlag = FALSE; + ClearHighlights(); + return; + } + FinishMove(moveType, fromX, fromY, toX, toY, promoChar); } @@ -7442,7 +7478,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) /* Check if clicking again on the same color piece */ fromP = boards[currentMove][fromY][fromX]; toP = boards[currentMove][y][x]; - frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess; + frc = appData.fischerCastling || gameInfo.variant == VariantSChess; if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect! ((WhitePawn <= fromP && fromP <= WhiteKing && WhitePawn <= toP && toP <= WhiteKing && @@ -8053,6 +8089,7 @@ Adjudicate (ChessProgramState *cps) case MT_NONE: default: break; + case MT_STEALMATE: case MT_STALEMATE: case MT_STAINMATE: reason = "Xboard adjudication: Stalemate"; @@ -8624,7 +8661,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h GameEnds(machineWhite ? BlackWins : WhiteWins, buf1, GE_XBOARD); return; - } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom) + } else if(!appData.fischerCastling) /* [HGM] Kludge to handle engines that send FRC-style castling when they shouldn't (like TSCP-Gothic) */ switch(moveType) { @@ -8668,7 +8705,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */ - if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) { + if( gameMode == TwoMachinesPlay && appData.adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) { int count = 0; while( count < adjudicateLossPlies ) { @@ -8677,8 +8714,8 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if( count & 1 ) { score = -score; /* Flip score for winning side */ } - - if( score > adjudicateLossThreshold ) { +printf("score=%d count=%d\n",score,count); + if( score > appData.adjudicateLossThreshold ) { break; } @@ -8722,7 +8759,6 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.), programStats.movelist); SendToICS(buf); -if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes); } } #endif @@ -9817,11 +9853,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } piece = board[toY][toX] = (ChessSquare) fromX; } else { - ChessSquare victim; +// ChessSquare victim; int i; if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something - victim = board[killY][killX], +// victim = board[killY][killX], board[killY][killX] = EmptySquare, board[EP_STATUS] = EP_CAPTURE; @@ -11351,8 +11387,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) ExitAnalyzeMode(); DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &first); - DoSleep( appData.delayAfterQuit ); - DestroyChildProcess(first.pr, first.useSigterm); + DestroyChildProcess(first.pr, 4 + first.useSigterm); first.reload = TRUE; } first.pr = NoProc; @@ -11377,8 +11412,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) if (second.pr != NoProc) { DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &second); - DoSleep( appData.delayAfterQuit ); - DestroyChildProcess(second.pr, second.useSigterm); + DestroyChildProcess(second.pr, 4 + second.useSigterm); second.reload = TRUE; } second.pr = NoProc; @@ -12195,22 +12229,40 @@ void PackMove (int fromX, int fromY, int toX, int toY, ChessSquare promoPiece) { int sq = fromX + (fromY<<4); - int piece = quickBoard[sq]; + int piece = quickBoard[sq], rook; quickBoard[sq] = 0; moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4); - if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) { + if(piece == pieceList[1] && fromY == toY) { + if((toX > 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((rook = quickBoard[sq]) && pieceType[rook] == WhiteRook) { // FRC castling + quickBoard[sq] = 0; // remove Rook + moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2); // King to-square + moveDatabase[movePtr++].piece = Q_WCASTL; + quickBoard[sq] = pieceList[1]; // put King + piece = rook; + moveDatabase[movePtr].to = pieceList[rook] = 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) { + if(piece == pieceList[2] && fromY == toY) { + if((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((rook = quickBoard[sq]) && pieceType[rook] == BlackRook) { // FRC castling + quickBoard[sq] = 0; // remove Rook + moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2); + moveDatabase[movePtr++].piece = Q_BCASTL; + quickBoard[sq] = pieceList[2]; // put King + piece = rook; + moveDatabase[movePtr].to = pieceList[rook] = 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; @@ -13930,6 +13982,7 @@ ExitEvent (int status) return; } + if (appData.icsActive) printf("\n"); // [HGM] end on new line after closing XBoard if (appData.icsActive && appData.colorize) Colorize(ColorNone, FALSE); if (telnetISR != NULL) { @@ -13956,14 +14009,12 @@ ExitEvent (int status) DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &first); - DoSleep( appData.delayAfterQuit ); - DestroyChildProcess(first.pr, 10 /* [AS] first.useSigterm */ ); + DestroyChildProcess(first.pr, 4 + first.useSigterm /* [AS] first.useSigterm */ ); } if (second.pr != NoProc) { DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &second); - DoSleep( appData.delayAfterQuit ); - DestroyChildProcess(second.pr, 10 /* [AS] second.useSigterm */ ); + DestroyChildProcess(second.pr, 4 + second.useSigterm /* [AS] second.useSigterm */ ); } if (first.isr != NULL) { RemoveInputSource(first.isr); @@ -14194,7 +14245,10 @@ AnalyzeModeEvent () first.maybeThinking = FALSE; /* avoid killing GNU Chess */ EngineOutputPopUp(); } - if (!appData.icsEngineAnalyze) gameMode = AnalyzeMode; + if (!appData.icsEngineAnalyze) { + gameMode = AnalyzeMode; + ClearEngineOutputPane(0); // [TK] exclude: to print exclusion/multipv header + } pausing = FALSE; ModeHighlight(); SetGameInfo(); @@ -17626,7 +17680,7 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) } else { if(nrCastlingRights) { q = p; - if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) { + if(appData.fischerCastling) { /* [HGM] write directly from rights */ if(boards[move][CASTLING][2] != NoRights && boards[move][CASTLING][0] != NoRights ) @@ -17734,7 +17788,7 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) Boolean ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) { - int i, j, k, w=0; + int i, j, k, w=0, subst=0, shuffle=0; char *p, c; int emptycount, virgin[BOARD_FILES]; ChessSquare piece; @@ -17773,6 +17827,16 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) if (j + emptycount > gameInfo.boardWidth) return FALSE; while (emptycount--) board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare; + } else if (*p == '<') { + if(i == BOARD_HEIGHT-1) shuffle = 1; + else if (i != 0 || !shuffle) return FALSE; + p++; + } else if (shuffle && *p == '>') { + p++; // for now ignore closing shuffle range, and assume rank-end + } else if (*p == '?') { + if (j >= gameInfo.boardWidth) return FALSE; + if (i != 0 && i != BOARD_HEIGHT-1) return FALSE; // only on back-rank + board[i][(j++)+gameInfo.holdingsWidth] = ClearBoard; p++; subst++; // placeHolder } else if (*p == '+' || isalpha(*p)) { if (j >= gameInfo.boardWidth) return FALSE; if(*p=='+') { @@ -17811,7 +17875,9 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) /* [HGM] look for Crazyhouse holdings here */ while(*p==' ') p++; if( gameInfo.holdingsWidth && p[-1] == '/' || *p == '[') { + int swap=0, wcnt=0, bcnt=0; if(*p == '[') p++; + if(*p == '<') swap++, p++; if(*p == '-' ) p++; /* empty holdings */ else { if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */ /* if we would allow FEN reading to set board size, we would */ @@ -17824,18 +17890,46 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) if( i >= gameInfo.holdingsSize ) return FALSE; board[BOARD_HEIGHT-1-i][0] = piece; /* black holdings */ board[BOARD_HEIGHT-1-i][1]++; /* black counts */ + bcnt++; } else { i = (int)piece - (int)WhitePawn; i = PieceToNumber((ChessSquare)i); if( i >= gameInfo.holdingsSize ) return FALSE; board[i][BOARD_WIDTH-1] = piece; /* white holdings */ board[i][BOARD_WIDTH-2]++; /* black holdings */ + wcnt++; } } + if(subst) { // substitute back-rank question marks by holdings pieces + for(j=BOARD_LEFT; j= bcnt) n = rand() % bcnt; // use same randomization for black and white if possible + for(k=0, m=n; k= 'A' && *p <= 'Z' || *p >= 'a' && *p <= 'z' || *p=='-') { /* castling indicator present, so default becomes no castlings */ @@ -17884,7 +17979,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) } } while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-' || - (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess) && + (appData.fischerCastling || gameInfo.variant == VariantSChess) && ( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) || ( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) { int c = *p++, whiteKingFile=NoRights, blackKingFile=NoRights; @@ -17906,6 +18001,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) board[CASTLING][2] = whiteKingFile; if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W; if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W; + if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1; break; case'Q': for(i=BOARD_LEFT; i>1|| i != BOARD_LEFT) fischer = 1; break; case'k': for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--); @@ -17920,6 +18017,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) board[CASTLING][5] = blackKingFile; if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B; if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B; + if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1; break; case'q': for(i=BOARD_LEFT; i>1|| i != BOARD_LEFT) fischer = 1; case '-': break; default: /* FRC castlings */ @@ -17960,7 +18059,9 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) } for(i=0; i