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
case VariantNoCastle:
case VariantShatranj:
case VariantCourier:
+ case VariantMakruk:
flags &= ~F_ALL_CASTLE_OK;
break;
default:
};
ChessSquare fairyArray[2][BOARD_FILES] = { /* [HGM] Queen side differs from King side */
- { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen,
+ { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,
WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },
- { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen,
- BlackKing, BlackBishop, BlackKnight, BlackRook }
+ { BlackLance, BlackAlfil, BlackMarshall, BlackAngel,
+ BlackKing, BlackMarshall, BlackAlfil, BlackLance }
};
ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */
BlackFerz, BlackAlfil, BlackKnight, BlackRook }
};
+ChessSquare makrukArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */
+ { WhiteRook, WhiteKnight, WhiteMan, WhiteKing,
+ WhiteFerz, WhiteMan, WhiteKnight, WhiteRook },
+ { BlackRook, BlackKnight, BlackMan, BlackFerz,
+ BlackKing, BlackMan, BlackKnight, BlackRook }
+};
+
#if (BOARD_FILES>=10)
ChessSquare ShogiArray[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;
case VariantAtomic: /* should work except for win condition */
case Variant3Check: /* should work except for win condition */
case VariantShatranj: /* should work except for all win conditions */
+ case VariantMakruk: /* should work except for daw countdown */
case VariantBerolina: /* might work if TestLegality is off */
case VariantCapaRandom: /* should work */
case VariantJanus: /* should work */
void
InitBackEnd3 P((void))
{
- GameMode initialMode;
- char buf[MSG_SIZ];
- int err;
-
- InitChessProgram(&first, startedFromSetupPosition);
-
-
- if (appData.icsActive) {
-#ifdef WIN32
- /* [DM] Make a console window if needed [HGM] merged ifs */
- ConsoleCreate();
-#endif
- err = establish();
- if (err != 0) {
- if (*appData.icsCommPort != NULLCHAR) {
- sprintf(buf, _("Could not open comm port %s"),
- appData.icsCommPort);
- } else {
- snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
- appData.icsHost, appData.icsPort);
+ GameMode initialMode;
+ char buf[MSG_SIZ];
+ int err;
+
+ InitChessProgram(&first, startedFromSetupPosition);
+
+
+ if (appData.icsActive)
+ {
+ err = establish();
+ if (err != 0)
+ {
+ if (*appData.icsCommPort != NULLCHAR)
+ {
+ sprintf(buf, _("Could not open comm port %s"),
+ appData.icsCommPort);
}
- DisplayFatalError(buf, err, 1);
- return;
+ else
+ {
+ snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
+ appData.icsHost, appData.icsPort);
+ }
+ DisplayFatalError(buf, err, 1);
+ return;
}
- SetICSMode();
- telnetISR =
- AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
- fromUserISR =
- AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
- } else if (appData.noChessProgram) {
- SetNCPMode();
- } else {
- SetGNUMode();
+ SetICSMode();
+ telnetISR =
+ AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
+ fromUserISR =
+ AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
}
-
- if (*appData.cmailGameName != NULLCHAR) {
- SetCmailMode();
- OpenLoopback(&cmailPR);
- cmailISR =
- AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+ else if (appData.noChessProgram)
+ {
+ SetNCPMode();
+ }
+ else
+ {
+ SetGNUMode();
}
-
- ThawUI();
- DisplayMessage("", "");
- if (StrCaseCmp(appData.initialMode, "") == 0) {
+
+ if (*appData.cmailGameName != NULLCHAR)
+ {
+ SetCmailMode();
+ OpenLoopback(&cmailPR);
+ cmailISR =
+ AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+ }
+
+ ThawUI();
+ DisplayMessage("", "");
+ if (StrCaseCmp(appData.initialMode, "") == 0)
+ {
initialMode = BeginningOfGame;
- } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0)
+ {
initialMode = TwoMachinesPlay;
- } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0)
+ {
initialMode = AnalyzeFile;
- } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "Analysis") == 0)
+ {
initialMode = AnalyzeMode;
- } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0)
+ {
initialMode = MachinePlaysWhite;
- } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0)
+ {
initialMode = MachinePlaysBlack;
- } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "EditGame") == 0)
+ {
initialMode = EditGame;
- } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0)
+ {
initialMode = EditPosition;
- } else if (StrCaseCmp(appData.initialMode, "Training") == 0) {
+ }
+ else if (StrCaseCmp(appData.initialMode, "Training") == 0)
+ {
initialMode = Training;
- } else {
+ }
+ else
+ {
sprintf(buf, _("Unknown initialMode %s"), appData.initialMode);
DisplayFatalError(buf, 0, 2);
return;
}
-
- if (appData.matchMode) {
- /* Set up machine vs. machine match */
- if (appData.noChessProgram) {
- DisplayFatalError(_("Can't have a match with no chess programs"),
- 0, 2);
- return;
+
+ if (appData.matchMode)
+ {
+ /* Set up machine vs. machine match */
+ if (appData.noChessProgram)
+ {
+ DisplayFatalError(_("Can't have a match with no chess programs"),
+ 0, 2);
+ return;
}
- matchMode = TRUE;
- matchGame = 1;
- if (*appData.loadGameFile != NULLCHAR) {
- int index = appData.loadGameIndex; // [HGM] autoinc
- if(index<0) lastIndex = index = 1;
- if (!LoadGameFromFile(appData.loadGameFile,
- index,
- appData.loadGameFile, FALSE)) {
- DisplayFatalError(_("Bad game file"), 0, 1);
- return;
+ matchMode = TRUE;
+ matchGame = 1;
+ if (*appData.loadGameFile != NULLCHAR)
+ {
+ int index = appData.loadGameIndex; // [HGM] autoinc
+ if(index<0) lastIndex = index = 1;
+ if (!LoadGameFromFile(appData.loadGameFile,
+ index,
+ appData.loadGameFile, FALSE))
+ {
+ DisplayFatalError(_("Bad game file"), 0, 1);
+ return;
}
- } else if (*appData.loadPositionFile != NULLCHAR) {
- int index = appData.loadPositionIndex; // [HGM] autoinc
- if(index<0) lastIndex = index = 1;
- if (!LoadPositionFromFile(appData.loadPositionFile,
- index,
- appData.loadPositionFile)) {
- DisplayFatalError(_("Bad position file"), 0, 1);
- return;
+ }
+ else if (*appData.loadPositionFile != NULLCHAR)
+ {
+ int index = appData.loadPositionIndex; // [HGM] autoinc
+ if(index<0) lastIndex = index = 1;
+ if (!LoadPositionFromFile(appData.loadPositionFile,
+ index,
+ appData.loadPositionFile))
+ {
+ DisplayFatalError(_("Bad position file"), 0, 1);
+ return;
}
}
- TwoMachinesEvent();
- } else if (*appData.cmailGameName != NULLCHAR) {
- /* Set up cmail mode */
- ReloadCmailMsgEvent(TRUE);
- } else {
- /* Set up other modes */
- if (initialMode == AnalyzeFile) {
- if (*appData.loadGameFile == NULLCHAR) {
- DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
- return;
- }
+ TwoMachinesEvent();
+ }
+ else if (*appData.cmailGameName != NULLCHAR)
+ {
+ /* Set up cmail mode */
+ ReloadCmailMsgEvent(TRUE);
+ }
+ else
+ {
+ /* Set up other modes */
+ if (initialMode == AnalyzeFile)
+ {
+ if (*appData.loadGameFile == NULLCHAR)
+ {
+ DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
+ return;
+ }
}
- if (*appData.loadGameFile != NULLCHAR) {
- (void) LoadGameFromFile(appData.loadGameFile,
- appData.loadGameIndex,
- appData.loadGameFile, TRUE);
- } else if (*appData.loadPositionFile != NULLCHAR) {
- (void) LoadPositionFromFile(appData.loadPositionFile,
- appData.loadPositionIndex,
- appData.loadPositionFile);
- /* [HGM] try to make self-starting even after FEN load */
- /* to allow automatic setup of fairy variants with wtm */
- if(initialMode == BeginningOfGame && !blackPlaysFirst) {
- gameMode = BeginningOfGame;
- setboardSpoiledMachineBlack = 1;
- }
- /* [HGM] loadPos: make that every new game uses the setup */
- /* from file as long as we do not switch variant */
- if(!blackPlaysFirst) {
- startedFromPositionFile = TRUE;
- CopyBoard(filePosition, boards[0]);
+ if (*appData.loadGameFile != NULLCHAR)
+ {
+ (void) LoadGameFromFile(appData.loadGameFile,
+ appData.loadGameIndex,
+ appData.loadGameFile, TRUE);
+ }
+ else if (*appData.loadPositionFile != NULLCHAR)
+ {
+ (void) LoadPositionFromFile(appData.loadPositionFile,
+ appData.loadPositionIndex,
+ appData.loadPositionFile);
+ /* [HGM] try to make self-starting even after FEN load */
+ /* to allow automatic setup of fairy variants with wtm */
+ if(initialMode == BeginningOfGame && !blackPlaysFirst)
+ {
+ gameMode = BeginningOfGame;
+ setboardSpoiledMachineBlack = 1;
}
+ /* [HGM] loadPos: make that every new game uses the setup */
+ /* from file as long as we do not switch variant */
+ if(!blackPlaysFirst)
+ {
+ startedFromPositionFile = TRUE;
+ CopyBoard(filePosition, boards[0]);
+ }
}
- if (initialMode == AnalyzeMode) {
- if (appData.noChessProgram) {
- DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
- return;
- }
- if (appData.icsActive) {
- DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
- return;
- }
+ if (initialMode == AnalyzeMode)
+ {
+ if (appData.noChessProgram)
+ {
+ DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
+ return;
+ }
+ if (appData.icsActive)
+ {
+ DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
+ return;
+ }
AnalyzeModeEvent();
- } else if (initialMode == AnalyzeFile) {
+ }
+ else if (initialMode == AnalyzeFile)
+ {
appData.showThinking = TRUE; // [HGM] thinking: moved out of ShowThinkingEvent
ShowThinkingEvent();
AnalyzeFileEvent();
AnalysisPeriodicEvent(1);
- } else if (initialMode == MachinePlaysWhite) {
- if (appData.noChessProgram) {
- DisplayFatalError(_("MachineWhite mode requires a chess engine"),
- 0, 2);
- return;
- }
- if (appData.icsActive) {
- DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
- 0, 2);
- return;
- }
+ }
+ else if (initialMode == MachinePlaysWhite)
+ {
+ if (appData.noChessProgram)
+ {
+ DisplayFatalError(_("MachineWhite mode requires a chess engine"),
+ 0, 2);
+ return;
+ }
+ if (appData.icsActive)
+ {
+ DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
+ 0, 2);
+ return;
+ }
MachineWhiteEvent();
- } else if (initialMode == MachinePlaysBlack) {
- if (appData.noChessProgram) {
- DisplayFatalError(_("MachineBlack mode requires a chess engine"),
- 0, 2);
- return;
- }
- if (appData.icsActive) {
- DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
- 0, 2);
- return;
- }
+ }
+ else if (initialMode == MachinePlaysBlack)
+ {
+ if (appData.noChessProgram)
+ {
+ DisplayFatalError(_("MachineBlack mode requires a chess engine"),
+ 0, 2);
+ return;
+ }
+ if (appData.icsActive)
+ {
+ DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
+ 0, 2);
+ return;
+ }
MachineBlackEvent();
- } else if (initialMode == TwoMachinesPlay) {
- if (appData.noChessProgram) {
- DisplayFatalError(_("TwoMachines mode requires a chess engine"),
- 0, 2);
- return;
- }
- if (appData.icsActive) {
- DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
- 0, 2);
- return;
- }
+ }
+ else if (initialMode == TwoMachinesPlay)
+ {
+ if (appData.noChessProgram)
+ {
+ DisplayFatalError(_("TwoMachines mode requires a chess engine"),
+ 0, 2);
+ return;
+ }
+ if (appData.icsActive)
+ {
+ DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
+ 0, 2);
+ return;
+ }
TwoMachinesEvent();
- } else if (initialMode == EditGame) {
+ }
+ else if (initialMode == EditGame)
+ {
EditGameEvent();
- } else if (initialMode == EditPosition) {
+ }
+ else if (initialMode == EditPosition)
+ {
EditPositionEvent();
- } else if (initialMode == Training) {
- if (*appData.loadGameFile == NULLCHAR) {
- DisplayFatalError(_("Training mode requires a game file"), 0, 2);
- return;
- }
+ }
+ else if (initialMode == Training)
+ {
+ if (*appData.loadGameFile == NULLCHAR)
+ {
+ DisplayFatalError(_("Training mode requires a game file"), 0, 2);
+ return;
+ }
TrainingEvent();
}
}
+
+ return;
}
/*
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
}
buf[buf_len] = NULLCHAR;
- next_out = leftover_len;
+// next_out = leftover_len; // [HGM] should we set this to 0, and not print it in advance?
+ next_out = 0;
leftover_start = 0;
i = 0;
if(!suppressKibitz) // [HGM] kibitz
AppendComment(forwardMostMove, StripHighlight(parse), TRUE);
else { // [HGM kibitz: divert memorized engine kibitz to engine-output window
- int nrDigit = 0, nrAlph = 0, i;
+ int nrDigit = 0, nrAlph = 0, j;
if(parse_pos > MSG_SIZ - 30) // defuse unreasonably long input
{ parse_pos = MSG_SIZ-30; parse[parse_pos - 1] = '\n'; }
parse[parse_pos] = NULLCHAR;
// try to be smart: if it does not look like search info, it should go to
// ICS interaction window after all, not to engine-output window.
- for(i=0; i<parse_pos; i++) { // count letters and digits
- nrDigit += (parse[i] >= '0' && parse[i] <= '9');
- nrAlph += (parse[i] >= 'a' && parse[i] <= 'z');
- nrAlph += (parse[i] >= 'A' && parse[i] <= 'Z');
+ for(j=0; j<parse_pos; j++) { // count letters and digits
+ nrDigit += (parse[j] >= '0' && parse[j] <= '9');
+ nrAlph += (parse[j] >= 'a' && parse[j] <= 'z');
+ nrAlph += (parse[j] >= 'A' && parse[j] <= 'Z');
}
if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info
int depth=0; float score;
pvInfoList[forwardMostMove-1].score = 100*score;
}
OutputKibitz(suppressKibitz, parse);
+ next_out = i+1; // [HGM] suppress printing in ICS window
} else {
char tmp[MSG_SIZ];
sprintf(tmp, _("your opponent kibitzes: %s"), parse);
}
started = STARTED_NONE;
} else {
- /* Don't match patterns against characters in chatter */
+ /* Don't match patterns against characters in comment */
i++;
continue;
}
}
continue;
} else
- if(looking_at(buf, &i, "kibitzed to")) { // suppress the acknowledgements of our own autoKibitz
- started = STARTED_CHATTER;
- suppressKibitz = TRUE;
+ if(looking_at(buf, &i, "kibitzed to *\n") && atoi(star_match[0])) {
+ // suppress the acknowledgements of our own autoKibitz
+ SendToPlayer(star_match[0], strlen(star_match[0]));
+ looking_at(buf, &i, "*% "); // eat prompt
+ next_out = i;
}
} // [HGM] kibitz: end of patch
if (looking_at(buf, &i, "% ") ||
((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE)
&& looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book
+ if(suppressKibitz) next_out = i;
savingComment = FALSE;
+ suppressKibitz = 0;
switch (started) {
case STARTED_MOVES:
case STARTED_MOVES_NOHIDE:
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);
while(looking_at(buf, &i, "\n")); // [HGM] skip empty lines
if (looking_at(buf, &i, "*% ")) {
savingComment = FALSE;
+ suppressKibitz = 0;
}
}
next_out = i;
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;
+ suppressKibitz = 0;
}
next_out = i;
}
i++; /* skip unparsed character and loop back */
}
-
- if (started != STARTED_MOVES && started != STARTED_BOARD && !suppressKibitz && // [HGM] kibitz suppress printing in ICS interaction window
- started != STARTED_HOLDINGS && i > next_out) {
- SendToPlayer(&buf[next_out], i - next_out);
+
+ if (started != STARTED_MOVES && started != STARTED_BOARD && !suppressKibitz && // [HGM] kibitz
+// started != STARTED_HOLDINGS && i > next_out) { // [HGM] should we compare to leftover_start in stead of i?
+// SendToPlayer(&buf[next_out], i - next_out);
+ started != STARTED_HOLDINGS && leftover_start > next_out) {
+ SendToPlayer(&buf[next_out], leftover_start - next_out);
next_out = i;
}
- suppressKibitz = FALSE; // [HGM] kibitz: has done its duty in if-statement above
leftover_len = buf_len - leftover_start;
/* if buffer ends with something we couldn't parse,
if(moveNum == 0 || gameInfo.variant != VariantFischeRandom)
{ int i, j; ChessSquare wKing = WhiteKing, bKing = BlackKing;
- for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)
+ for(i=BOARD_LEFT, j=NoRights; i<BOARD_RGHT; i++)
if(board[0][i] == WhiteRook) j = i;
initialRights[0] = boards[moveNum][CASTLING][0] = (castle_ws == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
- for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)
+ for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--)
if(board[0][i] == WhiteRook) j = i;
initialRights[1] = boards[moveNum][CASTLING][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
- for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)
+ for(i=BOARD_LEFT, j=NoRights; i<BOARD_RGHT; i++)
if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;
initialRights[3] = boards[moveNum][CASTLING][3] = (castle_bs == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
- for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)
+ for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--)
if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;
initialRights[4] = boards[moveNum][CASTLING][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
for(k=BOARD_LEFT; k<BOARD_RGHT; k++)
if(board[BOARD_HEIGHT-1][k] == bKing)
initialRights[5] = boards[moveNum][CASTLING][5] = k;
+ if(gameInfo.variant == VariantTwoKings) {
+ // In TwoKings looking for a King does not work, so always give castling rights to a King on e1/e8
+ if(board[0][4] == wKing) initialRights[2] = boards[moveNum][CASTLING][2] = 4;
+ if(board[BOARD_HEIGHT-1][4] == bKing) initialRights[5] = boards[moveNum][CASTLING][5] = 4;
+ }
} else { int r;
r = boards[moveNum][CASTLING][0] = initialRights[0];
if(board[0][r] != WhiteRook) boards[moveNum][CASTLING][0] = NoRights;
case BlackPromotionChancellor:
case WhitePromotionArchbishop:
case BlackPromotionArchbishop:
- if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
sprintf(user_move, "%c%c%c%c=%c\n",
AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,
PieceToChar(WhiteFerz));
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
nrCastlingRights = 0;
SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k");
break;
+ case VariantMakruk:
+ pieces = makrukArray;
+ nrCastlingRights = 0;
+ startedFromSetupPosition = TRUE;
+ SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk");
+ break;
case VariantTwoKings:
pieces = twoKingsArray;
break;
break;
case VariantFairy:
pieces = fairyArray;
- SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
+ SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk");
break;
case VariantGreat:
pieces = GreatArray;
pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
if(pawnRow < 1) pawnRow = 1;
+ if(gameInfo.variant == VariantMakruk) pawnRow = 2;
/* User pieceToChar list overrules defaults */
if(appData.pieceToCharTable != NULL)
if(gameInfo.variant == VariantShogi) {
promotionZoneSize = 3;
highestPromotingPiece = (int)WhiteFerz;
+ } else if(gameInfo.variant == VariantMakruk) {
+ promotionZoneSize = 3;
}
// next weed out all moves that do not touch the promotion zone at all
}
// we either have a choice what to promote to, or (in Shogi) whether to promote
- if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier) {
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) {
*promoChoice = PieceToChar(BlackFerz); // no choice
return FALSE;
}
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;
}
}
ModeHighlight();
}
- ModeHighlight();
- }
/* Relay move to ICS or chess engine */
if (appData.icsActive)
switch (gameMode)
{
case EditGame:
- switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) {
- case MT_NONE:
- case MT_CHECK:
- break;
-
+ switch (MateTest(boards[currentMove], PosFlags(currentMove)) )
+ {
+ case MT_NONE:
+ case MT_CHECK:
+ break;
+ case MT_CHECKMATE:
+ case MT_STAINMATE:
+ if (WhiteOnMove(currentMove)) {
+ GameEnds(BlackWins, "Black mates", GE_PLAYER);
+ } else {
+ GameEnds(WhiteWins, "White mates", GE_PLAYER);
+ }
+ break;
+ case MT_STALEMATE:
+ GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
+ break;
+ }
+ break;
+
case MachinePlaysBlack:
case MachinePlaysWhite:
/* disable certain menu options while machine is thinking */
SetMachineThinkingEnables();
break;
-
+
default:
break;
}
-
+
if(bookHit)
{ // [HGM] book: simulate book reply
static char bookMove[MSG_SIZ]; // a bit generous?
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')) )
+ if( cps->scoreIsAbsolute &&
+ ( 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;
}
Board board;
{
ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
+ int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1;
/* [HGM] compute & store e.p. status and castling rights for new position */
/* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */
}
/* [HGM] In Shatranj and Courier all promotions are to Ferz */
- if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier)
+ if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier || gameInfo.variant == VariantMakruk)
&& promoChar != 0) promoChar = PieceToChar(WhiteFerz);
if (fromX == toX && fromY == toY) return;
board[toY][toX+1] = board[fromY][BOARD_LEFT];
board[fromY][BOARD_LEFT] = EmptySquare;
} else if (board[fromY][fromX] == WhitePawn
- && toY == BOARD_HEIGHT-1
+ && toY >= BOARD_HEIGHT-promoRank
&& gameInfo.variant != VariantXiangqi
) {
/* white pawn promotion */
board[fromY][0] = EmptySquare;
board[toY][2] = BlackRook;
} else if (board[fromY][fromX] == BlackPawn
- && toY == 0
+ && toY < promoRank
&& gameInfo.variant != VariantXiangqi
) {
/* black pawn promotion */
- board[0][toX] = CharToPiece(ToLower(promoChar));
- if (board[0][toX] == EmptySquare) {
- board[0][toX] = BlackQueen;
+ board[toY][toX] = CharToPiece(ToLower(promoChar));
+ if (board[toY][toX] == EmptySquare) {
+ board[toY][toX] = BlackQueen;
}
if(gameInfo.variant==VariantBughouse ||
gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */
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;
void
MachineBlackEvent()
{
- char buf[MSG_SIZ];
- char *bookHit = NULL;
-
- if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
- return;
-
-
- if (gameMode == PlayFromGameFile ||
- gameMode == TwoMachinesPlay ||
- gameMode == Training ||
- gameMode == AnalyzeMode ||
- gameMode == EndOfGame)
- EditGameEvent();
-
- if (gameMode == EditPosition)
- EditPositionDone(TRUE);
-
- if (WhiteOnMove(currentMove)) {
- DisplayError(_("It is not Black's turn"), 0);
- return;
+ char buf[MSG_SIZ];
+ char *bookHit = NULL;
+
+ if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
+ return;
+
+
+ if (gameMode == PlayFromGameFile
+ || gameMode == TwoMachinesPlay
+ || gameMode == Training
+ || gameMode == AnalyzeMode
+ || gameMode == EndOfGame)
+ EditGameEvent();
+
+ if (gameMode == EditPosition)
+ EditPositionDone(TRUE);
+
+ if (WhiteOnMove(currentMove))
+ {
+ DisplayError(_("It is not Black's turn"), 0);
+ return;
}
-
- if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
- ExitAnalyzeMode();
-
- if (gameMode == EditGame || gameMode == AnalyzeMode ||
- gameMode == AnalyzeFile)
- TruncateGame();
-
- ResurrectChessProgram(); /* in case it isn't running */
- gameMode = MachinePlaysBlack;
- pausing = FALSE;
- ModeHighlight();
- SetGameInfo();
- sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
- DisplayTitle(buf);
- if (first.sendName) {
+
+ if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
+ ExitAnalyzeMode();
+
+ if (gameMode == EditGame || gameMode == AnalyzeMode
+ || gameMode == AnalyzeFile)
+ TruncateGame();
+
+ ResurrectChessProgram(); /* in case it isn't running */
+ gameMode = MachinePlaysBlack;
+ pausing = FALSE;
+ ModeHighlight();
+ SetGameInfo();
+ sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
+ DisplayTitle(buf);
+ if (first.sendName)
+ {
sprintf(buf, "name %s\n", gameInfo.white);
SendToProgram(buf, &first);
}
- if (first.sendTime) {
- if (first.useColors) {
- SendToProgram("white\n", &first); /*gnu kludge*/
- }
+ if (first.sendTime)
+ {
+ if (first.useColors)
+ {
+ SendToProgram("white\n", &first); /*gnu kludge*/
+ }
SendTimeRemaining(&first, FALSE);
}
- if (first.useColors) {
+ if (first.useColors)
+ {
SendToProgram("black\n", &first); // [HGM] book: 'go' sent separately
}
- bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
- SetMachineThinkingEnables();
- first.maybeThinking = TRUE;
- StartClocks();
-
- if (appData.autoFlipView && flipView) {
+ bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
+ SetMachineThinkingEnables();
+ first.maybeThinking = TRUE;
+ StartClocks();
+
+ if (appData.autoFlipView && flipView)
+ {
flipView = !flipView;
DrawPosition(FALSE, NULL);
DisplayBothClocks(); // [HGM] logo: clocks might have to be exchanged;
}
- if(bookHit) { // [HGM] book: simulate book reply
- static char bookMove[MSG_SIZ]; // a bit generous?
-
- programStats.nodes = programStats.depth = programStats.time =
- programStats.score = programStats.got_only_move = 0;
- sprintf(programStats.movelist, "%s (xbook)", bookHit);
-
- strcpy(bookMove, "move ");
- strcat(bookMove, bookHit);
- HandleMachineMove(bookMove, &first);
+ if(bookHit)
+ { // [HGM] book: simulate book reply
+ static char bookMove[MSG_SIZ]; // a bit generous?
+
+ programStats.nodes = programStats.depth = programStats.time
+ = programStats.score = programStats.got_only_move = 0;
+ sprintf(programStats.movelist, "%s (xbook)", bookHit);
+
+ strcpy(bookMove, "move ");
+ strcat(bookMove, bookHit);
+ HandleMachineMove(bookMove, &first);
}
+ return;
}
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]);
}
case BlackQueen:
if(gameInfo.variant == VariantShatranj ||
gameInfo.variant == VariantXiangqi ||
- gameInfo.variant == VariantCourier )
+ gameInfo.variant == VariantCourier ||
+ gameInfo.variant == VariantMakruk )
selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);
goto defaultlabel;
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;
}
}
gameInfo.resultDetails = StrSave(buf);
}
- DisplayFatalError(buf, error, 1);
+ if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, error, 1); else errorExitStatus = 1;
}
}
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;
}
if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&
- gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) {
+ gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
/* En passant target square */
if (move > backwardMostMove) {
fromX = moveList[move - 1][0] - AAA;
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]] != WhiteUnicorn
+ && 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]] != BlackUnicorn
+ && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
FENrulePlies = 0;
while(*p==' ') p++;
(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&
( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||
( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) {
- char c = *p++; int whiteKingFile=-1, blackKingFile=-1;
+ char c = *p++; int whiteKingFile=NoRights, blackKingFile=NoRights;
for(i=BOARD_LEFT; i<BOARD_RGHT; i++) {
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; // for these variant scanning fails
+ if(whiteKingFile == NoRights || board[0][whiteKingFile] != WhiteUnicorn
+ && board[0][whiteKingFile] != WhiteKing) whiteKingFile = NoRights;
+ if(blackKingFile == NoRights || board[BOARD_HEIGHT-1][blackKingFile] != BlackUnicorn
+ && board[BOARD_HEIGHT-1][blackKingFile] != BlackKing) blackKingFile = NoRights;
switch(c) {
case'K':
for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--);
board[CASTLING][2] = whiteKingFile;
break;
case'Q':
- for(i=BOARD_LEFT; board[0][i]!=WhiteRook && i<whiteKingFile; i++);
+ for(i=BOARD_LEFT; i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
board[CASTLING][1] = i != whiteKingFile ? i : NoRights;
board[CASTLING][2] = whiteKingFile;
break;
board[CASTLING][5] = blackKingFile;
break;
case'q':
- for(i=BOARD_LEFT; board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
+ for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
board[CASTLING][4] = i != blackKingFile ? i : NoRights;
board[CASTLING][5] = blackKingFile;
case '-':
}
}
}
+ for(i=0; i<nrCastlingRights; i++)
+ if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
if (appData.debugMode) {
fprintf(debugFP, "FEN castling rights:");
for(i=0; i<nrCastlingRights; i++)
/* read e.p. field in games that know e.p. capture */
if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&
- gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) {
+ gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
if(*p=='-') {
p++; board[EP_STATUS] = EP_NONE;
} else {