X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=da8ef9b3208bf3b7788d2186ed06fc14e34fe07a;hb=566205d159a20e4f86b54f5f2398b401df73d2e8;hp=4582baadb387d354e61a82b3aabe998c451be1ee;hpb=4f1c0dc1aa35c8e1c00a868d29a9ce9d84f64411;p=xboard.git diff --git a/backend.c b/backend.c old mode 100755 new mode 100644 index 4582baa..da8ef9b --- 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 * @@ -168,7 +168,7 @@ int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, void BackwardInner P((int target)); void ForwardInner P((int target)); void GameEnds P((ChessMove result, char *resultDetails, int whosays)); -void EditPositionDone P((void)); +void EditPositionDone P((Boolean fakeRights)); void PrintOpponents P((FILE *fp)); void PrintPosition P((FILE *fp, int move)); void StartChessProgram P((ChessProgramState *cps)); @@ -187,6 +187,7 @@ void DisplayMove P((int moveNumber)); void ParseGameHistory P((char *game)); void ParseBoard12 P((char *string)); +void KeepAlive P((void)); void StartClocks P((void)); void SwitchClocks P((void)); void StopClocks P((void)); @@ -242,6 +243,7 @@ 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 */ int lastIndex = 0; /* [HGM] autoinc: last game/position used in match mode */ +Boolean connectionAlive;/* [HGM] alive: ICS connection status from probing */ int opponentKibitzes; int lastSavedGame; /* [HGM] save: ID of game */ char chatPartner[MAX_CHAT][MSG_SIZ]; /* [HGM] chat: list of chatting partners */ @@ -743,7 +745,7 @@ InitBackEnd1() /* [HGM] time odds: set factor for each machine */ first.timeOdds = appData.firstTimeOdds; second.timeOdds = appData.secondTimeOdds; - { int norm = 1; + { float norm = 1; if(appData.timeOddsMode) { norm = first.timeOdds; if(norm > second.timeOdds) norm = second.timeOdds; @@ -1097,6 +1099,8 @@ InitBackEnd3 P((void)) AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR); fromUserISR = AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR); + if(appData.keepAlive) // [HGM] alive: schedule sending of dummy 'date' command + ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000); } else if (appData.noChessProgram) { SetNCPMode(); } else { @@ -1417,6 +1421,8 @@ read_from_player(isr, closure, message, count, error) void KeepAlive() { // [HGM] alive: periodically send dummy (date) command to ICS to prevent time-out + if(!connectionAlive) DisplayFatalError("No response from ICS", 0, 1); + connectionAlive = FALSE; // only sticks if no response to 'date' command. SendToICS("date\n"); if(appData.keepAlive) ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000); } @@ -1941,6 +1947,7 @@ void VariantSwitch(Board board, VariantClass newVariant) { int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j; + Board oldBoard; startedFromPositionFile = FALSE; if(gameInfo.variant == newVariant) return; @@ -2012,9 +2019,10 @@ VariantSwitch(Board board, VariantClass newVariant) gameInfo.holdingsWidth = newHoldingsWidth; gameInfo.variant = newVariant; InitDrawingSizes(-2, 0); + } else gameInfo.variant = newVariant; + CopyBoard(oldBoard, board); // remember correctly formatted board InitPosition(FALSE); /* this sets up board[0], but also other stuff */ - } else { gameInfo.variant = newVariant; InitPosition(FALSE); } - DrawPosition(TRUE, boards[currentMove]); + DrawPosition(TRUE, currentMove ? boards[currentMove] : oldBoard); } static int loggedOn = FALSE; @@ -2040,7 +2048,7 @@ read_from_ics(isr, closure, data, count, error) int count; int error; { -#define BUF_SIZE 8192 +#define BUF_SIZE (16*1024) /* overflowed at 8K with "inchannel 1" on FICS? */ #define STARTED_NONE 0 #define STARTED_MOVES 1 #define STARTED_BOARD 2 @@ -2069,6 +2077,8 @@ read_from_ics(isr, closure, data, count, error) char talker[MSG_SIZ]; // [HGM] chat int channel; + connectionAlive = TRUE; // [HGM] alive: I think, therefore I am... + if (appData.debugMode) { if (!error) { fprintf(debugFP, " 0 && newGameMode != IcsIdle && - appData.getMoveList) { + } else if ((moveNum > 0 || newGameMode == IcsObserving) && newGameMode != IcsIdle && + appData.getMoveList && !reqFlag) { /* Need to get game history */ ics_getting_history = H_REQUESTED; sprintf(str, "%smoves %d\n", ics_prefix, gamenum); @@ -3575,7 +3588,7 @@ ParseBoard12(string) timeIncrement = increment * 1000; movesPerSession = 0; gameInfo.timeControl = TimeControlTagValue(); - VariantSwitch(board, StringToVariant(gameInfo.event) ); + VariantSwitch(boards[currentMove], StringToVariant(gameInfo.event) ); if (appData.debugMode) { fprintf(debugFP, "ParseBoard says variant = '%s'\n", gameInfo.event); fprintf(debugFP, "recognized as %s\n", VariantName(gameInfo.variant)); @@ -3695,6 +3708,11 @@ ParseBoard12(string) for(k=BOARD_LEFT; k in stead of calling FinishMove directly, this function is made into one that returns an OK move type if FinishMove @@ -5324,7 +5342,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar) /*char*/int promoChar; { char *bookHit = 0; -if(appData.debugMode) fprintf(debugFP, "moveType 5 = %d, promochar = %x\n", moveType, promoChar); + if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR) { // [HGM] superchess: suppress promotions to non-available piece int k = PieceToNumber(CharToPiece(ToUpper(promoChar))); @@ -5339,13 +5357,12 @@ if(appData.debugMode) fprintf(debugFP, "moveType 5 = %d, promochar = %x\n", move move type in caller when we know the move is a legal promotion */ if(moveType == NormalMove && promoChar) moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar); -if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", moveType, promoChar); + /* [HGM] convert drag-and-drop piece drops to standard form */ - if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { + if( (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && fromY != DROP_RANK ){ moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop; if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]); -// fromX = boards[currentMove][fromY][fromX]; // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings @@ -5354,7 +5371,7 @@ if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", move } /* [HGM] The following if has been moved here from - UserMoveEvent(). Because it seemed to belon here (why not allow + UserMoveEvent(). Because it seemed to belong here (why not allow piece drops in training games?), and because it can only be performed after it is known to what we promote. */ if (gameMode == Training) { @@ -5428,7 +5445,7 @@ if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", move } ModeHighlight(); } -if(appData.debugMode) fprintf(debugFP, "moveType 2 = %d, promochar = %x\n", moveType, promoChar); + /* Relay move to ICS or chess engine */ if (appData.icsActive) { if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || @@ -5670,6 +5687,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix) if(x >= 0 && x < BOARD_LEFT || x >= BOARD_RGHT) { ClearHighlights(); fromX = fromY = -1; + DrawPosition(TRUE, NULL); return; } @@ -6219,15 +6237,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } else moveCount = 6; } } - - if (appData.debugMode) { int i; - fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n", - forwardMostMove, backwardMostMove, epStatus[backwardMostMove], - appData.drawRepeats); - for( i=forwardMostMove; i>=backwardMostMove; i-- ) - fprintf(debugFP, "%d ep=%d\n", i, epStatus[i]); - - } /* Check for rep-draws */ count = 0; @@ -6928,7 +6937,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. /* [AS] Negate score if machine is playing black and reporting absolute scores */ if( cps->scoreIsAbsolute && - ((gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b')) ) + ( gameMode == MachinePlaysBlack || + gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b' || + gameMode == IcsPlayingBlack || // [HGM] also add other situations where engine should report black POV + (gameMode == AnalyzeMode || gameMode == AnalyzeFile || gameMode == IcsObserving && appData.icsEngineAnalyze) && + !WhiteOnMove(currentMove) + ) ) { curscore = -curscore; } @@ -6958,8 +6972,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if (strlen(buf1) >= sizeof(programStats.movelist) && appData.debugMode) { fprintf(debugFP, - "PV is too long; using the first %d bytes.\n", - sizeof(programStats.movelist) - 1); + "PV is too long; using the first %u bytes.\n", + (unsigned) sizeof(programStats.movelist) - 1); } safeStrCpy( programStats.movelist, buf1, sizeof(programStats.movelist) ); @@ -9945,17 +9959,9 @@ SaveGamePGN(f) /* [AS] Add PV info if present */ if( i >= 0 && appData.saveExtendedInfoInPGN && pvInfoList[i].depth > 0 ) { /* [HGM] add time */ - char buf[MSG_SIZ]; int seconds = 0; + char buf[MSG_SIZ]; int seconds; - if(i >= backwardMostMove) { - if(WhiteOnMove(i)) - seconds = timeRemaining[0][i] - timeRemaining[0][i+1] - + GetTimeQuota(i/2) / (1000*WhitePlayer()->timeOdds); - else - seconds = timeRemaining[1][i] - timeRemaining[1][i+1] - + GetTimeQuota(i/2) / (1000*WhitePlayer()->other->timeOdds); - } - seconds = (seconds+50)/100; // deci-seconds, rounded to nearest + seconds = (pvInfoList[i].time+5)/10; // deci-seconds, rounded to nearest if( seconds <= 0) buf[0] = 0; else if( seconds < 30 ) sprintf(buf, " %3.1f%c", seconds/10., 0); else { @@ -10084,7 +10090,7 @@ SaveGame(f, dummy, dummy2) int dummy; char *dummy2; { - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); lastSavedGame = GameCheckSum(); // [HGM] save: remember ID of last saved game to prevent double saving if (appData.oldSaveStyle) return SaveGameOldStyle(f); @@ -10124,7 +10130,8 @@ SavePosition(f, dummy, dummy2) { time_t tm; char *fen; - + + if (gameMode == EditPosition) EditPositionDone(TRUE); if (appData.oldSaveStyle) { tm = time((time_t *) NULL); @@ -10702,7 +10709,7 @@ MachineWhiteEvent() EditGameEvent(); if (gameMode == EditPosition) - EditPositionDone(); + EditPositionDone(TRUE); if (!WhiteOnMove(currentMove)) { DisplayError(_("It is not White's turn"), 0); @@ -10783,7 +10790,7 @@ MachineBlackEvent() EditGameEvent(); if (gameMode == EditPosition) - EditPositionDone(); + EditPositionDone(TRUE); if (WhiteOnMove(currentMove)) { DisplayError(_("It is not Black's turn"), 0); @@ -10890,7 +10897,7 @@ TwoMachinesEvent P((void)) if (gameMode != EditGame) return; break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: case AnalyzeFile: @@ -11028,7 +11035,7 @@ IcsClientEvent() break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: @@ -11069,7 +11076,7 @@ EditGameEvent() } break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: case AnalyzeFile: @@ -11176,21 +11183,30 @@ ExitAnalyzeMode() } void -EditPositionDone() +EditPositionDone(Boolean fakeRights) { int king = gameInfo.variant == VariantKnightmate ? WhiteUnicorn : WhiteKing; startedFromSetupPosition = TRUE; InitChessProgram(&first, FALSE); - castlingRights[0][2] = castlingRights[0][5] = BOARD_WIDTH>>1; - if(boards[0][0][BOARD_WIDTH>>1] == king) { - castlingRights[0][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? 0 : -1; - castlingRights[0][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : -1; - } else castlingRights[0][2] = -1; - if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) { - castlingRights[0][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? 0 : -1; - castlingRights[0][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : -1; - } else castlingRights[0][5] = -1; + if(fakeRights) + { /* don't do this if we just pasted FEN */ + castlingRights[0][2] = castlingRights[0][5] = BOARD_WIDTH>>1; + if(boards[0][0][BOARD_WIDTH>>1] == king) + { + castlingRights[0][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? 0 : -1; + castlingRights[0][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : -1; + } + else + castlingRights[0][2] = -1; + if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) + { + castlingRights[0][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? 0 : -1; + castlingRights[0][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : -1; + } + else + castlingRights[0][5] = -1; + } SendToProgram("force\n", &first); if (blackPlaysFirst) { strcpy(moveList[0], ""); @@ -11827,7 +11843,7 @@ void ToStartEvent() { if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { - /* to optimze, we temporarily turn off analysis mode while we undo + /* to optimize, we temporarily turn off analysis mode while we undo * all the moves. Otherwise we get analysis output after each undo. */ if (first.analysisSupport) { @@ -12022,7 +12038,7 @@ BookEvent() } break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case TwoMachinesPlay: return; @@ -12407,7 +12423,7 @@ SendToProgram(message, cps) } else { gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins; } - gameInfo.resultDetails = buf; + gameInfo.resultDetails = StrSave(buf); } DisplayFatalError(buf, error, 1); } @@ -12438,7 +12454,7 @@ ReceiveFromProgram(isr, closure, message, count, error) } else { gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins; } - gameInfo.resultDetails = buf; + gameInfo.resultDetails = StrSave(buf); } RemoveInputSource(cps->isr); DisplayFatalError(buf, 0, 1); @@ -12599,7 +12615,7 @@ SendTimeRemaining(cps, machineWhite) /* [HGM] translate opponent's time by time-odds factor */ otime = (otime * cps->other->timeOdds) / cps->timeOdds; if (appData.debugMode) { - fprintf(debugFP, "time odds: %d %d \n", cps->timeOdds, cps->other->timeOdds); + fprintf(debugFP, "time odds: %f %f \n", cps->timeOdds, cps->other->timeOdds); } if (time <= 0) time = 1; @@ -12845,7 +12861,7 @@ ParseFeatures(args, cps) /* unknown feature: complain and skip */ q = p; while (*q && *q != '=') q++; - sprintf(buf, "rejected %.*s\n", q-p, p); + sprintf(buf, "rejected %.*s\n", (int)(q-p), p); SendToProgram(buf, cps); p = q; if (*p == '=') { @@ -12886,7 +12902,7 @@ PonderNextMoveEvent(newState) int newState; { if (newState == appData.ponderNextMove) return; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); if (newState) { SendToProgram("hard\n", &first); if (gameMode == TwoMachinesPlay) { @@ -12909,7 +12925,7 @@ NewSettingEvent(option, command, value) { char buf[MSG_SIZ]; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); sprintf(buf, "%s%s %d\n", (option ? "option ": ""), command, value); SendToProgram(buf, &first); if (gameMode == TwoMachinesPlay) { @@ -12928,7 +12944,7 @@ ShowThinkingEvent() if (oldState == newState) return; oldState = newState; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); if (oldState) { SendToProgram("post\n", &first); if (gameMode == TwoMachinesPlay) { @@ -13019,26 +13035,23 @@ DisplayComment(moveNumber, text) char title[MSG_SIZ]; char buf[8000]; // comment can be long! int score, depth; - - if( appData.autoDisplayComment ) { - if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) { - strcpy(title, "Comment"); - } else { - sprintf(title, "Comment on %d.%s%s", moveNumber / 2 + 1, - WhiteOnMove(moveNumber) ? " " : ".. ", - parseList[moveNumber]); - } - // [HGM] PV info: display PV info together with (or as) comment - if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) { - if(text == NULL) text = ""; - score = pvInfoList[moveNumber].score; - sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100., - depth, (pvInfoList[moveNumber].time+50)/100, text); - text = buf; - } - } else title[0] = 0; - - if (text != NULL) + + if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) { + strcpy(title, "Comment"); + } else { + sprintf(title, "Comment on %d.%s%s", moveNumber / 2 + 1, + WhiteOnMove(moveNumber) ? " " : ".. ", + parseList[moveNumber]); + } + // [HGM] PV info: display PV info together with (or as) comment + if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) { + if(text == NULL) text = ""; + score = pvInfoList[moveNumber].score; + sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100., + depth, (pvInfoList[moveNumber].time+50)/100, text); + text = buf; + } + if (text != NULL && (appData.autoDisplayComment || commentUp)) CommentPopUp(title, text); } @@ -13683,7 +13696,7 @@ PositionToFEN(move, overrideCastling) *p++ = ' '; if(q = overrideCastling) { // [HGM] FRC: override castling & e.p fields for non-compliant engines - while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; + while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; else --p; } else { if(nrCastlingRights) { q = p; @@ -13895,10 +13908,12 @@ ParseFEN(board, blackPlaysFirst, fen) } /* assume possible unless obviously impossible */ if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1; if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1; - if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1; + if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteUnicorn + && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1; if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) FENcastlingRights[3] = -1; if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) FENcastlingRights[4] = -1; - if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1; + if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackUnicorn + && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1; FENrulePlies = 0; while(*p==' ') p++; @@ -13919,9 +13934,15 @@ ParseFEN(board, blackPlaysFirst, fen) if(board[BOARD_HEIGHT-1][i] == BlackKing) blackKingFile = i; if(board[0 ][i] == WhiteKing) whiteKingFile = i; } + if(gameInfo.variant == VariantTwoKings || gameInfo.variant == VariantKnightmate) + whiteKingFile = blackKingFile = BOARD_WIDTH >> 1; // scanning fails in these variants + if(whiteKingFile<0 || board[0][whiteKingFile]!=WhiteUnicorn + && board[0][whiteKingFile]!=WhiteKing) whiteKingFile = -1; + if(blackKingFile<0 || board[BOARD_HEIGHT-1][blackKingFile]!=BlackUnicorn + && board[BOARD_HEIGHT-1][blackKingFile]!=BlackKing) blackKingFile = -1; switch(c) { case'K': - for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--); + for(i=BOARD_RGHT-1; i>whiteKingFile && board[0][i]!=WhiteRook; i--); FENcastlingRights[0] = i != whiteKingFile ? i : -1; FENcastlingRights[2] = whiteKingFile; break; @@ -13931,7 +13952,7 @@ ParseFEN(board, blackPlaysFirst, fen) FENcastlingRights[2] = whiteKingFile; break; case'k': - for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--); + for(i=BOARD_RGHT-1; i>blackKingFile && board[BOARD_HEIGHT-1][i]!=BlackRook; i--); FENcastlingRights[3] = i != blackKingFile ? i : -1; FENcastlingRights[5] = blackKingFile; break; @@ -13968,6 +13989,8 @@ ParseFEN(board, blackPlaysFirst, fen) } } } + for(i=0; i= 0) initialRights[i] = FENcastlingRights[i]; if (appData.debugMode) { fprintf(debugFP, "FEN castling rights:"); for(i=0; i