extern int tinyLayout, smallLayout;
ChessProgramStats programStats;
+char lastPV[2][2*MSG_SIZ]; /* [HGM] pv: last PV in thinking output of each engine */
+int endPV = -1;
static int exiting = 0; /* [HGM] moved to top */
static int setboardSpoiledMachineBlack = 0 /*, errorExitFlag = 0*/;
int startedFromPositionFile = FALSE; Board filePosition; /* [HGM] loadPos */
char chatPartner[MAX_CHAT][MSG_SIZ]; /* [HGM] chat: list of chatting partners */
extern int chatCount;
int chattingPartner;
+char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
/* States for ics_getting_history */
#define H_FALSE 0
ChessMove savedResult[MAX_VARIATIONS];
void PushTail P((int firstMove, int lastMove));
-Boolean PopTail P((void));
+Boolean PopTail P((Boolean annotate));
void CleanupTail P((void));
ChessSquare FIDEArray[2][BOARD_FILES] = {
/* [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;
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
if (appData.testLegality) {
return (*moveType != IllegalMove);
} else {
- return !(fromX == fromY && toX == toY);
+ return !(*fromX == *toX && *fromY == *toY) && boards[moveNum][*fromY][*fromX] != EmptySquare &&
+ WhiteOnMove(moveNum) == (boards[moveNum][*fromY][*fromX] < BlackPawn);
}
case WhiteDrop:
}
}
+
+void
+ParsePV(char *pv)
+{ // Parse a string of PV moves, and append to current game, behind forwardMostMove
+ int fromX, fromY, toX, toY; char promoChar;
+ ChessMove moveType;
+ Boolean valid;
+ int nr = 0;
+
+ endPV = forwardMostMove;
+ do {
+ while(*pv == ' ') pv++;
+ if(*pv == '(') pv++; // first (ponder) move can be in parentheses
+ valid = ParseOneMove(pv, endPV, &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
+if(appData.debugMode){
+fprintf(debugFP,"parsePV: %d %c%c%c%c '%s'\n", valid, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, pv);
+}
+ if(!valid && nr == 0 &&
+ ParseOneMove(pv, endPV-1, &moveType, &fromX, &fromY, &toX, &toY, &promoChar)){
+ nr++; moveType = Comment; // First move has been played; kludge to make sure we continue
+ }
+ while(*pv && *pv++ != ' '); // skip what we parsed; assume space separators
+ if(moveType == Comment) { valid++; continue; } // allow comments in PV
+ nr++;
+ if(endPV+1 > framePtr) break; // no space, truncate
+ if(!valid) break;
+ endPV++;
+ CopyBoard(boards[endPV], boards[endPV-1]);
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[endPV]);
+ moveList[endPV-1][0] = fromX + AAA;
+ moveList[endPV-1][1] = fromY + ONE;
+ moveList[endPV-1][2] = toX + AAA;
+ moveList[endPV-1][3] = toY + ONE;
+ parseList[endPV-1][0] = NULLCHAR;
+ } while(valid);
+ currentMove = endPV;
+ if(currentMove == forwardMostMove) ClearPremoveHighlights(); else
+ SetPremoveHighlights(moveList[currentMove-1][0]-AAA, moveList[currentMove-1][1]-ONE,
+ moveList[currentMove-1][2]-AAA, moveList[currentMove-1][3]-ONE);
+ DrawPosition(TRUE, boards[currentMove]);
+}
+
+static int lastX, lastY;
+
+Boolean
+LoadMultiPV(int x, int y, char *buf, int index, int *start, int *end)
+{
+ int startPV;
+
+ if(index < 0 || index >= strlen(buf)) return FALSE; // sanity
+ lastX = x; lastY = y;
+ while(index > 0 && buf[index-1] != '\n') index--; // beginning of line
+ startPV = index;
+ while(buf[index] != '\n') if(buf[index++] == '\t') startPV = index;
+ index = startPV;
+ while(buf[index] && buf[index] != '\n') index++;
+ buf[index] = 0;
+ ParsePV(buf+startPV);
+ *start = startPV; *end = index-1;
+ return TRUE;
+}
+
+Boolean
+LoadPV(int x, int y)
+{ // called on right mouse click to load PV
+ int which = gameMode == TwoMachinesPlay && (WhiteOnMove(forwardMostMove) == (second.twoMachinesColor[0] == 'w'));
+ lastX = x; lastY = y;
+ ParsePV(lastPV[which]); // load the PV of the thinking engine in the boards array.
+ return TRUE;
+}
+
+void
+UnLoadPV()
+{
+ if(endPV < 0) return;
+ endPV = -1;
+ currentMove = forwardMostMove;
+ ClearPremoveHighlights();
+ DrawPosition(TRUE, boards[currentMove]);
+}
+
+void
+MovePV(int x, int y, int h)
+{ // step through PV based on mouse coordinates (called on mouse move)
+ int margin = h>>3, step = 0;
+
+ if(endPV < 0) return;
+ // we must somehow check if right button is still down (might be released off board!)
+ if(y < margin && (abs(x - lastX) > 6 || abs(y - lastY) > 6)) step = 1; else
+ if(y > h - margin && (abs(x - lastX) > 6 || abs(y - lastY) > 6)) step = -1; else
+ if( y > lastY + 6 ) step = -1; else if(y < lastY - 6) step = 1;
+ if(!step) return;
+ lastX = x; lastY = y;
+ if(currentMove + step > endPV || currentMove + step < forwardMostMove) step = 0;
+ currentMove += step;
+ if(currentMove == forwardMostMove) ClearPremoveHighlights(); else
+ SetPremoveHighlights(moveList[currentMove-1][0]-AAA, moveList[currentMove-1][1]-ONE,
+ moveList[currentMove-1][2]-AAA, moveList[currentMove-1][3]-ONE);
+ DrawPosition(FALSE, boards[currentMove]);
+}
+
+
// [HGM] shuffle: a general way to suffle opening setups, applicable to arbitrary variants.
// All positions will have equal probability, but the current method will not provide a unique
// numbering scheme for arrays that contain 3 or more pieces of the same kind.
// Last King gets castling rights
while(piecesLeft[(int)WhiteUnicorn]) {
i = put(board, WhiteUnicorn, 0, piecesLeft[(int)WhiteRook]/2, ANY);
- initialRights[2] = initialRights[5] = boards[0][CASTLING][2] = boards[0][CASTLING][5] = i;
+ initialRights[2] = initialRights[5] = board[CASTLING][2] = board[CASTLING][5] = i;
}
while(piecesLeft[(int)WhiteKing]) {
i = put(board, WhiteKing, 0, piecesLeft[(int)WhiteRook]/2, ANY);
- initialRights[2] = initialRights[5] = boards[0][CASTLING][2] = boards[0][CASTLING][5] = i;
+ initialRights[2] = initialRights[5] = board[CASTLING][2] = board[CASTLING][5] = i;
}
if(PosFlags(0) & F_FRC_TYPE_CASTLING) { // first and last Rook get FRC castling rights
if(first) {
first=0;
- initialRights[1] = initialRights[4] = boards[0][CASTLING][1] = boards[0][CASTLING][4] = i;
+ initialRights[1] = initialRights[4] = board[CASTLING][1] = board[CASTLING][4] = i;
}
- initialRights[0] = initialRights[3] = boards[0][CASTLING][0] = boards[0][CASTLING][3] = i;
+ initialRights[0] = initialRights[3] = board[CASTLING][0] = board[CASTLING][3] = i;
}
}
for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // copy black from white
return AmbiguousMove;
} else if (toX >= 0 && toY >= 0) {
boards[0][toY][toX] = boards[0][fromY][fromX];
+ if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings
+ if(boards[0][fromY][0] != EmptySquare) {
+ if(boards[0][fromY][1]) boards[0][fromY][1]--;
+ if(boards[0][fromY][1] == 0) boards[0][fromY][0] = EmptySquare;
+ }
+ } else
+ if(fromX == BOARD_RGHT+1) {
+ if(boards[0][fromY][BOARD_WIDTH-1] != EmptySquare) {
+ if(boards[0][fromY][BOARD_WIDTH-2]) boards[0][fromY][BOARD_WIDTH-2]--;
+ if(boards[0][fromY][BOARD_WIDTH-2] == 0) boards[0][fromY][BOARD_WIDTH-1] = EmptySquare;
+ }
+ } else
boards[0][fromY][fromX] = EmptySquare;
return AmbiguousMove;
}
moveType = PromoCharToMoveType(WhiteOnMove(currentMove), 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]);
FinishMove(moveType, fromX, fromY, toX, toY, promoChar);
}
+void
+Mark(board, flags, kind, rf, ff, rt, ft, closure)
+ Board board;
+ int flags;
+ ChessMove kind;
+ int rf, ff, rt, ft;
+ VOIDSTAR closure;
+{
+ typedef char Markers[BOARD_RANKS][BOARD_FILES];
+ Markers *m = (Markers *) closure;
+ if(rf == fromY && ff == fromX)
+ (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare
+ || kind == WhiteCapturesEnPassant
+ || kind == BlackCapturesEnPassant);
+ else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3;
+}
+
+void
+MarkTargetSquares(int clear)
+{
+ int x, y;
+ if(!appData.markers || !appData.highlightDragging ||
+ !appData.testLegality || gameMode == EditPosition) return;
+ if(clear) {
+ for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) marker[y][x] = 0;
+ } else {
+ int capt = 0;
+ GenLegal(boards[currentMove], PosFlags(currentMove), Mark, (void*) marker);
+ if(PosFlags(0) & F_MANDATORY_CAPTURE) {
+ for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x]>1) capt++;
+ if(capt)
+ for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x] == 1) marker[y][x] = 0;
+ }
+ }
+ DrawPosition(TRUE, NULL);
+}
+
void LeftClick(ClickType clickType, int xPix, int yPix)
{
int x, y;
char promoChoice = NULLCHAR;
if (clickType == Press) ErrorPopDown();
+ MarkTargetSquares(1);
x = EventToSquare(xPix, BOARD_WIDTH);
y = EventToSquare(yPix, BOARD_HEIGHT);
fromX = x;
fromY = y;
second = 0;
+ MarkTargetSquares(0);
DragPieceBegin(xPix, yPix);
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
if (OKToStartUserMove(x, y)) {
fromX = x;
fromY = y;
+ MarkTargetSquares(0);
DragPieceBegin(xPix, yPix);
}
return;
appData.animate = FALSE;
}
- // moves into holding are invalid for now (later perhaps allow in EditPosition)
+ // moves into holding are invalid for now (except in EditPosition, adapting to-square)
if(x >= 0 && x < BOARD_LEFT || x >= BOARD_RGHT) {
+ ChessSquare piece = boards[currentMove][fromY][fromX];
+ if(gameMode == EditPosition && piece != EmptySquare &&
+ fromX >= BOARD_LEFT && fromX < BOARD_RGHT) {
+ int n;
+
+ if(x == BOARD_LEFT-2 && piece >= BlackPawn) {
+ n = PieceToNumber(piece - (int)BlackPawn);
+ if(n > gameInfo.holdingsSize) { n = 0; piece = BlackPawn; }
+ boards[currentMove][BOARD_HEIGHT-1 - n][0] = piece;
+ boards[currentMove][BOARD_HEIGHT-1 - n][1]++;
+ } else
+ if(x == BOARD_RGHT+1 && piece < BlackPawn) {
+ n = PieceToNumber(piece);
+ if(n > gameInfo.holdingsSize) { n = 0; piece = WhitePawn; }
+ boards[currentMove][n][BOARD_WIDTH-1] = piece;
+ boards[currentMove][n][BOARD_WIDTH-2]++;
+ }
+ boards[currentMove][fromY][fromX] = EmptySquare;
+ }
ClearHighlights();
fromX = fromY = -1;
- DrawPosition(TRUE, NULL);
+ DrawPosition(TRUE, boards[currentMove]);
return;
}
stats.an_move_count = cpstats->nr_moves;
}
+ if(stats.pv && stats.pv[0]) strcpy(lastPV[stats.which], stats.pv); // [HGM] pv: remember last PV of each
+
SetProgramStats( &stats );
}
int machineWhite;
char *bookHit;
+ cps->userError = 0;
+
FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book hit
/*
* Kludge to ignore BEL characters
return;
}
if (!strncmp(message, "tellusererror ", 14)) {
+ cps->userError = 1;
DisplayError(message + 14, 0);
return;
}
/* [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;
}
0, 1);
return;
}
+ UnLoadPV(); // [HGM] pv: if we are looking at a PV, abort this
if (commentList[forwardMostMove+1] != NULL) {
free(commentList[forwardMostMove+1]);
commentList[forwardMostMove+1] = NULL;
/* Print comments preceding this move */
if (commentList[i] != NULL) {
if (linelen > 0) fprintf(f, "\n");
- fprintf(f, "%s\n", commentList[i]);
+ fprintf(f, "%s", commentList[i]);
linelen = 0;
newblock = TRUE;
}
/* [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 {
time_t tm;
char *fen;
+ if (gameMode == EditPosition) EditPositionDone(TRUE);
if (appData.oldSaveStyle) {
tm = time((time_t *) NULL);
case EmptySquare:
if (gameMode == IcsExamining) {
+ if (x < BOARD_LEFT || x >= BOARD_RGHT) break; // [HGM] holdings
sprintf(buf, "%sx@%c%c\n", ics_prefix, AAA + x, ONE + y);
SendToICS(buf);
} else {
+ if(x < BOARD_LEFT || x >= BOARD_RGHT) {
+ if(x == BOARD_LEFT-2) {
+ if(y < BOARD_HEIGHT-1-gameInfo.holdingsSize) break;
+ boards[0][y][1] = 0;
+ } else
+ if(x == BOARD_RGHT+1) {
+ if(y >= gameInfo.holdingsSize) break;
+ boards[0][y][BOARD_WIDTH-2] = 0;
+ } else break;
+ }
boards[0][y][x] = EmptySquare;
DrawPosition(FALSE, boards[0]);
}
default:
defaultlabel:
if (gameMode == IcsExamining) {
+ if (x < BOARD_LEFT || x >= BOARD_RGHT) break; // [HGM] holdings
sprintf(buf, "%s%c@%c%c\n", ics_prefix,
PieceToChar(selection), AAA + x, ONE + y);
SendToICS(buf);
} else {
+ if(x < BOARD_LEFT || x >= BOARD_RGHT) {
+ int n;
+ if(x == BOARD_LEFT-2 && selection >= BlackPawn) {
+ n = PieceToNumber(selection - BlackPawn);
+ if(n > gameInfo.holdingsSize) { n = 0; selection = BlackPawn; }
+ boards[0][BOARD_HEIGHT-1-n][0] = selection;
+ boards[0][BOARD_HEIGHT-1-n][1]++;
+ } else
+ if(x == BOARD_RGHT+1 && selection < BlackPawn) {
+ n = PieceToNumber(selection);
+ if(n > gameInfo.holdingsSize) { n = 0; selection = WhitePawn; }
+ boards[0][n][BOARD_WIDTH-1] = selection;
+ boards[0][n][BOARD_WIDTH-2]++;
+ }
+ } else
boards[0][y][x] = selection;
- DrawPosition(FALSE, boards[0]);
+ DrawPosition(TRUE, boards[0]);
}
break;
}
void
RevertEvent()
{
- if(PopTail()) { // [HGM] vari: restore old game tail
+ if(PopTail(TRUE)) { // [HGM] vari: restore old game tail
return;
}
if (gameMode != IcsExamining) {
{
/* This routine is used only for certain modes */
VariantClass v = gameInfo.variant;
+ ChessMove r = GameUnfinished;
+ char *p = NULL;
+
+ if(gameMode == EditGame) { // [HGM] vari: do not erase result on EditGame
+ r = gameInfo.result;
+ p = gameInfo.resultDetails;
+ gameInfo.resultDetails = NULL;
+ }
ClearGameInfo(&gameInfo);
gameInfo.variant = v;
gameInfo.round = StrSave("-");
gameInfo.white = StrSave("-");
gameInfo.black = StrSave("-");
+ gameInfo.result = r;
+ gameInfo.resultDetails = p;
break;
case EditPosition:
commentList[index] = NULL;
return;
}
- if(*text == '{' || *text == '(' || *text == '[') {
+ if( *text == '{' && strchr(text, '}') || // [HGM] braces: if certainy malformed, put braces
+ *text == '[' && strchr(text, ']') || // otherwise hope the user knows what he is doing
+ *text == '(' && strchr(text, ')')) { // (perhaps check if this parses as comment-only?)
commentList[index] = (char *) malloc(len + 2);
strncpy(commentList[index], text, len);
commentList[index][len] = '\n';
char *p;
commentList[index] = (char *) malloc(len + 6);
strcpy(commentList[index], "{\n");
- strcat(commentList[index], text);
+ strncpy(commentList[index]+2, text, len);
+ commentList[index][len+2] = NULLCHAR;
while(p = strchr(commentList[index], '}')) *p = ')'; // kill all } to make it one comment
- strcat(commentList[index], "\n}");
+ strcat(commentList[index], "\n}\n");
}
}
if (commentList[index] != NULL) {
old = commentList[index];
oldlen = strlen(old);
- commentList[index] = (char *) malloc(oldlen + len + 4); // might waste 2
+ while(commentList[index][oldlen-1] == '\n')
+ commentList[index][--oldlen] = NULLCHAR;
+ commentList[index] = (char *) malloc(oldlen + len + 6); // might waste 4
strcpy(commentList[index], old);
free(old);
- // [HGM] braces: join "{A\n}" + "{B}" as "{A\nB\n}"
+ // [HGM] braces: join "{A\n}\n" + "{\nB}" as "{A\nB\n}"
if(commentList[index][oldlen-1] == '}' && (text[0] == '{' || addBraces)) {
if(addBraces) addBraces = FALSE; else { text++; len--; }
while (*text == '\n') { text++; len--; }
- commentList[index][oldlen-1] = NULLCHAR;
- oldlen--;
+ commentList[index][--oldlen] = NULLCHAR;
}
- strncpy(&commentList[index][oldlen], text, len);
- if(addBraces) strcpy(&commentList[index][oldlen + len], "\n}");
- else strcpy(&commentList[index][oldlen + len], "\n");
+ if(addBraces) strcat(commentList[index], "\n{\n");
+ else strcat(commentList[index], "\n");
+ strcat(commentList[index], text);
+ if(addBraces) strcat(commentList[index], "\n}\n");
+ else strcat(commentList[index], "\n");
} else {
- commentList[index] = (char *) malloc(len + 4); // perhaps wastes 2...
- if(addBraces) commentList[index][0] = '{';
- strcpy(commentList[index] + addBraces, text);
+ commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4...
+ if(addBraces)
+ strcpy(commentList[index], "{\n");
+ else commentList[index][0] = NULLCHAR;
+ strcat(commentList[index], text);
strcat(commentList[index], "\n");
- if(addBraces) strcat(commentList[index], "}");
+ if(addBraces) strcat(commentList[index], "}\n");
}
}
} else {
gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins;
}
- gameInfo.resultDetails = buf;
+ gameInfo.resultDetails = StrSave(buf);
}
- DisplayFatalError(buf, error, 1);
+ if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, error, 1); else errorExitStatus = 1;
}
}
} else {
gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins;
}
- gameInfo.resultDetails = buf;
+ gameInfo.resultDetails = StrSave(buf);
}
RemoveInputSource(cps->isr);
- DisplayFatalError(buf, 0, 1);
+ if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, 0, 1); else errorExitStatus = 1;
} else {
sprintf(buf,
_("Error reading from %s chess program (%s)"),
cps->pr = NoProc;
}
- DisplayFatalError(buf, error, 1);
+ if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, error, 1); else errorExitStatus = 1;
}
return;
}
/* [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;
if(whiteNPS >= 0) lastTickLength = 0;
timeRemaining = whiteTimeRemaining -= lastTickLength;
DisplayWhiteClock(whiteTimeRemaining - fudge,
- WhiteOnMove(currentMove));
+ WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove));
} else {
if(blackNPS >= 0) lastTickLength = 0;
timeRemaining = blackTimeRemaining -= lastTickLength;
DisplayBlackClock(blackTimeRemaining - fudge,
- !WhiteOnMove(currentMove));
+ !WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove));
}
if (CheckFlags()) return;
*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;
board[CASTLING][i] =
gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom ? NoRights : initialRights[i];
} /* assume possible unless obviously impossible */
- if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights;
- if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights;
- if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights;
- if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) board[CASTLING][3] = NoRights;
- if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) board[CASTLING][4] = NoRights;
- if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
+ if(initialRights[0]!=NoRights && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights;
+ if(initialRights[1]!=NoRights && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights;
+ if(initialRights[2]!=NoRights && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights;
+ if(initialRights[3]!=NoRights && board[castlingRank[3]][initialRights[3]] != BlackRook) board[CASTLING][3] = NoRights;
+ if(initialRights[4]!=NoRights && board[castlingRank[4]][initialRights[4]] != BlackRook) board[CASTLING][4] = NoRights;
+ if(initialRights[5]!=NoRights && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
FENrulePlies = 0;
while(*p==' ') p++;
if(storedGames == 1) GreyRevert(FALSE);
}
-Boolean
-PopTail()
+Boolean
+PopTail(Boolean annotate)
{
int i, j, nrMoves;
+ char buf[8000], moveBuf[20];
if(appData.icsActive) return FALSE; // only in local mode
if(!storedGames) return FALSE; // sanity
storedGames--;
ToNrEvent(savedFirst[storedGames]); // sets currentMove
nrMoves = savedLast[storedGames] - currentMove;
+ if(annotate) {
+ int cnt = 10;
+ if(!WhiteOnMove(currentMove)) sprintf(buf, "(%d...", currentMove+2>>1);
+ else strcpy(buf, "(");
+ for(i=currentMove; i<forwardMostMove; i++) {
+ if(WhiteOnMove(i))
+ sprintf(moveBuf, " %d. %s", i+2>>1, SavePart(parseList[i]));
+ else sprintf(moveBuf, " %s", SavePart(parseList[i]));
+ strcat(buf, moveBuf);
+ if(!--cnt) { strcat(buf, "\n"); cnt = 10; }
+ }
+ strcat(buf, ")");
+ }
for(i=1; i<nrMoves; i++) { // copy last variation back
CopyBoard(boards[currentMove+i], boards[framePtr+i]);
for(j=0; j<MOVE_LEN; j++)
commentList[currentMove+i] = commentList[framePtr+i];
commentList[framePtr+i] = NULL;
}
+ if(annotate) AppendComment(currentMove+1, buf, FALSE);
framePtr = savedFramePtr[storedGames];
gameInfo.result = savedResult[storedGames];
if(gameInfo.resultDetails != NULL) {