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));
ChessSquare piece;
if(gameInfo.holdingsWidth < 2) return;
+ if(gameInfo.variant != VariantBughouse && board[BOARD_SIZE-1][BOARD_SIZE-2])
+ return; // prevent overwriting by pre-board holdings
if( (int)lowestPiece >= BlackPawn ) {
holdingsColumn = 0;
board[holdingsStartRow+j*direction][holdingsColumn] = piece;
board[holdingsStartRow+j*direction][countsColumn]++;
}
-
}
VariantSwitch(Board board, VariantClass newVariant)
{
int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;
+ Board oldBoard;
startedFromPositionFile = FALSE;
if(gameInfo.variant == newVariant) return;
gameInfo.holdingsWidth = newHoldingsWidth;
gameInfo.variant = newVariant;
InitDrawingSizes(-2, 0);
- InitPosition(TRUE); /* this sets up board[0], but also other stuff */
- } else { gameInfo.variant = newVariant; InitPosition(TRUE); }
+ } else gameInfo.variant = newVariant;
+ CopyBoard(oldBoard, board); // remember correctly formatted board
+ InitPosition(FALSE); /* this sets up board[0], but also other stuff */
+ DrawPosition(TRUE, currentMove ? boards[currentMove] : oldBoard);
}
static int loggedOn = FALSE;
moves and soak them up so user can step
through them and/or save them.
*/
- Reset(TRUE, TRUE);
+ Reset(FALSE, TRUE);
gameMode = IcsObserving;
ModeHighlight();
ics_gamenum = -1;
currentMove = forwardMostMove;
ClearHighlights();/*!!could figure this out*/
flipView = appData.flipView;
- DrawPosition(FALSE, boards[currentMove]);
+ DrawPosition(TRUE, boards[currentMove]);
DisplayBothClocks();
sprintf(str, "%s vs. %s",
gameInfo.white, gameInfo.black);
strncmp(why, "Continuing ", 11) == 0) {
gs_gamenum = gamenum;
strcpy(gs_kind, strchr(why, ' ') + 1);
+ VariantSwitch(boards[currentMove], StringToVariant(gs_kind)); // [HGM] variantswitch: even before we get first board
#if ZIPPY
if (appData.zippyPlay) {
ZippyGameStart(whitename, blackname);
/* Usually suppress following prompt */
if (!(forwardMostMove == 0 && gameMode == IcsExamining)) {
+ while(looking_at(buf, &i, "\n")); // [HGM] skip empty lines
if (looking_at(buf, &i, "*% ")) {
savingComment = FALSE;
}
/* [HGM] copy holdings to board holdings area */
CopyHoldings(boards[forwardMostMove], white_holding, WhitePawn);
CopyHoldings(boards[forwardMostMove], black_holding, BlackPawn);
+ boards[forwardMostMove][BOARD_SIZE-1][BOARD_SIZE-2] = 1; // flag holdings as set
#if ZIPPY
if (appData.zippyPlay && first.initDone) {
ZippyHoldings(white_holding, black_holding,
}
/* Suppress following prompt */
if (looking_at(buf, &i, "*% ")) {
+ if(strchr(star_match[0], 7)) SendToPlayer("\007", 1); // Bell(); // FICS fuses bell for next board with prompt in zh captures
savingComment = FALSE;
}
next_out = i;
char promoChar;
int ranks=1, files=0; /* [HGM] ICS80: allow variable board size */
char *bookHit = NULL; // [HGM] book
- Boolean weird = FALSE;
+ Boolean weird = FALSE, reqFlag = FALSE;
fromX = fromY = toX = toY = -1;
&moveNum, str, elapsed_time, move_str, &ics_flip,
&ticking);
- if (gameInfo.boardHeight != ranks || gameInfo.boardWidth != files ||
- weird && (int)gameInfo.variant <= (int)VariantShogi) {
- /* [HGM] We seem to switch variant during a game!
- * Try to guess new variant from board size
- */
- VariantClass newVariant = VariantFairy; // if 8x8, but fairies present
- if(ranks == 8 && files == 10) newVariant = VariantCapablanca; else
- if(ranks == 10 && files == 9) newVariant = VariantXiangqi; else
- if(ranks == 8 && files == 12) newVariant = VariantCourier; else
- if(ranks == 9 && files == 9) newVariant = VariantShogi; else
- if(!weird) newVariant = VariantNormal;
- VariantSwitch(boards[currentMove], newVariant); /* temp guess */
- /* Get a move list just to see the header, which
- will tell us whether this is really bug or zh */
- if (ics_getting_history == H_FALSE) {
- ics_getting_history = H_REQUESTED;
- sprintf(str, "%smoves %d\n", ics_prefix, gamenum);
- SendToICS(str);
- }
- }
-
if (n < 21) {
snprintf(str, sizeof(str), _("Failed to parse board string:\n\"%s\""), string);
DisplayError(str, 0);
ics_getting_history = H_FALSE;
return;
}
+
+ if (gameInfo.boardHeight != ranks || gameInfo.boardWidth != files ||
+ weird && (int)gameInfo.variant <= (int)VariantShogi) {
+ /* [HGM] We seem to have switched variant unexpectedly
+ * Try to guess new variant from board size
+ */
+ VariantClass newVariant = VariantFairy; // if 8x8, but fairies present
+ if(ranks == 8 && files == 10) newVariant = VariantCapablanca; else
+ if(ranks == 10 && files == 9) newVariant = VariantXiangqi; else
+ if(ranks == 8 && files == 12) newVariant = VariantCourier; else
+ if(ranks == 9 && files == 9) newVariant = VariantShogi; else
+ if(!weird) newVariant = VariantNormal;
+ VariantSwitch(boards[currentMove], newVariant); /* temp guess */
+ /* Get a move list just to see the header, which
+ will tell us whether this is really bug or zh */
+ if (ics_getting_history == H_FALSE) {
+ ics_getting_history = H_REQUESTED; reqFlag = TRUE;
+ sprintf(str, "%smoves %d\n", ics_prefix, gamenum);
+ SendToICS(str);
+ }
+ }
/* Take action if this is the first board of a new game, or of a
different game than is currently being displayed. */
prevMove = -3;
if (gamenum == -1) {
newGameMode = IcsIdle;
- } else if (moveNum > 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);
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));
}
}
CopyBoard(boards[moveNum], board);
+ boards[moveNum][BOARD_SIZE-1][BOARD_SIZE-2] = 0; // [HGM] indicate holdings not set
if (moveNum == 0) {
startedFromSetupPosition =
!CompareBoards(board, initialPosition);
return ImpossibleMove;
}
}
-if(appData.debugMode) fprintf(debugFP, "moveType 3 = %d, promochar = %x\n", moveType, promoChar);
+
return moveType;
/* [HGM] <popupFix> in stead of calling FinishMove directly, this
function is made into one that returns an OK move type if FinishMove
/*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)));
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
}
/* [HGM] <popupFix> 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) {
}
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 ||
if(x >= 0 && x < BOARD_LEFT || x >= BOARD_RGHT) {
ClearHighlights();
fromX = fromY = -1;
+ DrawPosition(TRUE, NULL);
return;
}
} 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;
/* [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;
}
if(cps->nps == 0) ticklen = 10*time; // use engine reported time
else ticklen = (1000. * u64ToDouble(nodes)) / cps->nps; // convert node count to time
- if(WhiteOnMove(forwardMostMove))
+ if(WhiteOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite ||
+ gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'w'))
whiteTimeRemaining = timeRemaining[0][forwardMostMove] - ticklen;
- else blackTimeRemaining = timeRemaining[1][forwardMostMove] - ticklen;
+ if(!WhiteOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack ||
+ gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b'))
+ blackTimeRemaining = timeRemaining[1][forwardMostMove] - ticklen;
}
/* Buffer overflow protection */
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) );
/* [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 {
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);
{
time_t tm;
char *fen;
-
+
+ if (gameMode == EditPosition) EditPositionDone(TRUE);
if (appData.oldSaveStyle) {
tm = time((time_t *) NULL);
EditGameEvent();
if (gameMode == EditPosition)
- EditPositionDone();
+ EditPositionDone(TRUE);
if (!WhiteOnMove(currentMove)) {
DisplayError(_("It is not White's turn"), 0);
EditGameEvent();
if (gameMode == EditPosition)
- EditPositionDone();
+ EditPositionDone(TRUE);
if (WhiteOnMove(currentMove)) {
DisplayError(_("It is not Black's turn"), 0);
if (gameMode != EditGame) return;
break;
case EditPosition:
- EditPositionDone();
+ EditPositionDone(TRUE);
break;
case AnalyzeMode:
case AnalyzeFile:
break;
case EditPosition:
- EditPositionDone();
+ EditPositionDone(TRUE);
break;
case AnalyzeMode:
}
break;
case EditPosition:
- EditPositionDone();
+ EditPositionDone(TRUE);
break;
case AnalyzeMode:
case AnalyzeFile:
}
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], "");
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) {
}
break;
case EditPosition:
- EditPositionDone();
+ EditPositionDone(TRUE);
break;
case TwoMachinesPlay:
return;
} else {
gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins;
}
- gameInfo.resultDetails = buf;
+ gameInfo.resultDetails = StrSave(buf);
}
DisplayFatalError(buf, error, 1);
}
} else {
gameInfo.result = cps->twoMachinesColor[0]=='w' ? BlackWins : WhiteWins;
}
- gameInfo.resultDetails = buf;
+ gameInfo.resultDetails = StrSave(buf);
}
RemoveInputSource(cps->isr);
DisplayFatalError(buf, 0, 1);
/* 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 == '=') {
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) {
{
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) {
if (oldState == newState) return;
oldState = newState;
- if (gameMode == EditPosition) EditPositionDone();
+ if (gameMode == EditPosition) EditPositionDone(TRUE);
if (oldState) {
SendToProgram("post\n", &first);
if (gameMode == TwoMachinesPlay) {
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);
}
*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;
for( i=0; i<nrCastlingRights; i++ )
castlingRights[0][i] = FENcastlingRights[i];
}
- EditPositionDone();
+ EditPositionDone(FALSE);
DisplayBothClocks();
DrawPosition(FALSE, boards[currentMove]);
}
if (ret)
strcpy(cseq, new_seq);
else if (appData.debugMode)
- fprintf(debugFP, "Invalid continuation sequence \"%s\" (maximum length is: %d)\n", new_seq, sizeof(cseq)-1);
+ fprintf(debugFP, "Invalid continuation sequence \"%s\" (maximum length is: %u)\n", new_seq, (unsigned) sizeof(cseq)-1);
return ret;
}