int promoDefaultAltered;
int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */
static int initPing = -1;
-static Boolean pieceDefs;
+int border; /* [HGM] width of board rim, needed to size seek graph */
/* States for ics_getting_history */
#define H_FALSE 0
if(cps->tidy == NULL) cps->tidy = (char*) malloc(MSG_SIZ);
TidyProgramName(cps->program, cps->host, cps->tidy);
cps->matchWins = 0;
- ASSIGN(cps->variants, appData.variant);
+ ASSIGN(cps->variants, appData.noChessProgram ? "" : appData.variant);
cps->analysisSupport = 2; /* detect */
cps->analyzing = FALSE;
cps->initDone = FALSE;
DisplayFatalError(buf, 0, 2);
return;
+ case VariantNormal: /* definitely works! */
+ if(strcmp(appData.variant, "normal") && !appData.noChessProgram) { // [HGM] hope this is an engine-defined variant
+ safeStrCpy(engineVariant, appData.variant, MSG_SIZ);
+ return;
+ }
case VariantXiangqi: /* [HGM] repetition rules not implemented */
case VariantFairy: /* [HGM] TestLegality definitely off! */
case VariantGothic: /* [HGM] should work */
case VariantFalcon: /* [HGM] untested */
case VariantCrazyhouse: /* holdings not shown, ([HGM] fixed that!)
offboard interposition not understood */
- case VariantNormal: /* definitely works! */
case VariantWildCastle: /* pieces not automatically shuffled */
case VariantNoCastle: /* pieces not automatically shuffled */
case VariantFischeRandom: /* [HGM] works and shuffles pieces */
int wnum = -1;
VariantClass v = VariantNormal;
int i, found = FALSE;
- char buf[MSG_SIZ];
+ char buf[MSG_SIZ], c;
int len;
if (!e) return v;
/* [HGM] skip over optional board-size prefixes */
- if( sscanf(e, "%dx%d_", &i, &i) == 2 ||
- sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) {
+ if( sscanf(e, "%dx%d_%c", &i, &i, &c) == 3 ||
+ sscanf(e, "%dx%d+%d_%c", &i, &i, &i, &c) == 4 ) {
while( *e++ != '_');
}
} else
for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {
if (p = StrCaseStr(e, variantNames[i])) {
- if(p && i >= VariantShogi && isalpha(p[strlen(variantNames[i])])) continue;
+ if(p && i >= VariantShogi && (p != e || isalpha(p[strlen(variantNames[i])]))) continue;
v = (VariantClass) i;
found = TRUE;
break;
{
int i;
if(!seekGraphUp) return FALSE;
- h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
- w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
+ h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap + 2*border;
+ w = BOARD_WIDTH * (squareSize + lineGap) + lineGap + 2*border;
DrawSeekBackground(0, 0, w, h);
DrawSeekAxis(hMargin, h-1-vMargin, w-5, h-1-vMargin);
}
int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove
+int legNr = 1;
void
CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7])
case VariantFalcon:
pieces = FalconArray;
gameInfo.boardWidth = 10;
- SetCharTable(pieceToChar, "PNBRQ.............FKpnbrq.............fk");
+ SetCharTable(pieceToChar, "PNBRQ............FKpnbrq............fk");
break;
case VariantXiangqi:
pieces = XiangqiArray;
// 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
- while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++;
+ while(PieceToChar(fromX) == '.' || PieceToChar(fromX) == '+' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++;
fromY = DROP_RANK;
}
{
typedef char Markers[BOARD_RANKS][BOARD_FILES];
Markers *m = (Markers *) closure;
- if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2))
+ if(rf == fromY && ff == fromX && (killX < 0 ? !(rt == rf && ft == ff) && legNr & 1 : rt == killY && ft == killX || legNr & 2))
(*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare
|| kind == WhiteCapturesEnPassant
|| kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 1;
s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
ASSIGN(appData.pieceToCharTable, buf);
}
- if(startedFromSetupPosition) return;
dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName);
if(dummy >= 3) {
while(message[s] && message[s++] != ' ');
if(dummy == 4) gameInfo.variant = StringToVariant(varName); // parent variant
InitPosition(1); // calls InitDrawingSizes to let new parameters take effect
if(*buf) SetCharTable(pieceToChar, buf); // do again, for it was spoiled by InitPosition
+ startedFromSetupPosition = FALSE;
}
}
+ if(startedFromSetupPosition) return;
ParseFEN(boards[0], &dummy, message+s, FALSE);
DrawPosition(TRUE, boards[0]);
+ CopyBoard(initialPosition, boards[0]);
startedFromSetupPosition = TRUE;
return;
}
if(sscanf(message, "piece %s %s", buf2, buf1) == 2) {
ChessSquare piece = WhitePawn;
char *p=buf2;
- if(cps != &first || appData.testLegality) return;
if(*p == '+') piece = CHUPROMOTED WhitePawn, p++;
piece += CharToPiece(*p) - WhitePawn;
+ if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR
+ /* always accept definition of */ && piece != WhiteFalcon && piece != BlackFalcon
+ /* wild-card pieces. */ && piece != WhiteCobra && piece != BlackCobra
+ /* For variants we don't have */ && gameInfo.variant != VariantBerolina
+ /* correct rules for, we cannot */ && gameInfo.variant != VariantCylinder
+ /* enforce legality on our own! */ && gameInfo.variant != VariantUnknown
+ && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantFairy ) return;
if(piece < EmptySquare) {
pieceDefs = TRUE;
ASSIGN(pieceDesc[piece], buf1);
/* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */
if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook ||
board[fromY][fromX] == WhiteRook && board[toY][toX] == WhiteKing) {
+ board[EP_STATUS] = EP_NONE; // capture was fake!
board[fromY][fromX] = EmptySquare;
board[toY][toX] = EmptySquare;
if((toX > fromX) != (piece == WhiteRook)) {
}
} else if (board[fromY][fromX] == BlackKing && board[toY][toX] == BlackRook ||
board[fromY][fromX] == BlackRook && board[toY][toX] == BlackKing) {
+ board[EP_STATUS] = EP_NONE;
board[fromY][fromX] = EmptySquare;
board[toY][toX] = EmptySquare;
if((toX > fromX) != (piece == BlackRook)) {
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
} else if ((fromY >= BOARD_HEIGHT>>1)
- && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality)
+ && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4)
&& (toX != fromX)
&& gameInfo.variant != VariantXiangqi
&& gameInfo.variant != VariantBerolina
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
} else if ((fromY < BOARD_HEIGHT>>1)
- && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality)
+ && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4)
&& (toX != fromX)
&& gameInfo.variant != VariantXiangqi
&& gameInfo.variant != VariantBerolina
p = (int) captured;
if (p >= (int) BlackPawn) {
p -= (int)BlackPawn;
- if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) {
- /* in Shogi restore piece to its original first */
+ if(DEMOTED p >= 0 && PieceToChar(p) == '+') {
+ /* Restore shogi-promoted piece to its original first */
captured = (ChessSquare) (DEMOTED captured);
p = DEMOTED p;
}
board[p][BOARD_WIDTH-1] = BLACK_TO_WHITE captured;
} else {
p -= (int)WhitePawn;
- if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) {
+ if(DEMOTED p >= 0 && PieceToChar(p) == '+') {
captured = (ChessSquare) (DEMOTED captured);
p = DEMOTED p;
}
b = SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth,
gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, cps->tidy);
if (b == NULL) {
- DisplayFatalError(variantError, 0, 1);
+ VariantClass v;
+ char c, *q = cps->variants, *p = strchr(q, ',');
+ if(p) *p = NULLCHAR;
+ v = StringToVariant(q);
+ DisplayError(variantError, 0);
+ if(v != VariantUnknown && cps == &first) {
+ int w, h, s;
+ if(sscanf(q, "%dx%d+%d_%c", &w, &h, &s, &c) == 4) // get size overrides the engine needs with it (if any)
+ appData.NrFiles = w, appData.NrRanks = h, appData.holdingsSize = s, q = strchr(q, '_') + 1;
+ ASSIGN(appData.variant, q);
+ Reset(TRUE, FALSE);
+ }
+ if(p) *p = ',';
return;
}
if (!err) numPGNTags++;
/* [HGM] PGNvariant: automatically switch to variant given in PGN tag */
- if(gameInfo.variant != oldVariant) {
+ if(gameInfo.variant != oldVariant && (gameInfo.variant != VariantNormal || gameInfo.variantName == NULL || *gameInfo.variantName == NULLCHAR)) {
startedFromPositionFile = FALSE; /* [HGM] loadPos: variant switch likely makes position invalid */
ResetFrontEnd(); // [HGM] might need other bitmaps. Cannot use Reset() because it clears gameInfo :-(
InitPosition(TRUE);
return FALSE;
}
CopyBoard(boards[0], initial_position);
+ if(*engineVariant) // [HGM] for now, assume FEN in engine-defined variant game is default initial position
+ CopyBoard(initialPosition, initial_position);
if (blackPlaysFirst) {
currentMove = forwardMostMove = backwardMostMove = 1;
CopyBoard(boards[1], initial_position);
if(!SupportedVariant(second.variants, gameInfo.variant, gameInfo.boardWidth,
gameInfo.boardHeight, gameInfo.holdingsSize, second.protocolVersion, second.tidy)) {
- startingEngine = FALSE;
+ startingEngine = matchMode = FALSE;
DisplayError("second engine does not play this", 0);
+ gameMode = TwoMachinesPlay; ModeHighlight(); // Needed to make sure menu item is unchecked
+ EditGameEvent(); // switch back to EditGame mode
return;
}
switch (selection) {
case ClearBoard:
+ fromX = fromY = killX = killY = -1; // [HGM] abort any move entry in progress
+ MarkTargetSquares(1);
CopyBoard(currentBoard, boards[0]);
CopyBoard(menuBoard, initialPosition);
if (gameMode == IcsExamining && ics_type == ICS_FICS) {
seekGraphUp = FALSE;
MarkTargetSquares(1);
+ fromX = fromY = killX = killY = -1; // [HGM] abort any move entry in progress
if (gameMode == PlayFromGameFile && !pausing)
PauseEvent();
if (gameMode == EditPosition) return;
seekGraphUp = FALSE;
MarkTargetSquares(1);
+ fromX = fromY = killX = killY = -1; // [HGM] abort any move entry in progress
if (currentMove <= backwardMostMove) {
ClearHighlights();
DrawPosition(full_redraw, boards[currentMove]);
while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; else --p;
} else {
if(nrCastlingRights) {
+ int handW=0, handB=0;
+ if(gameInfo.variant == VariantSChess) { // for S-Chess, all virgin backrank pieces must be listed
+ for(i=0; i<BOARD_HEIGHT; i++) handW += boards[move][i][BOARD_RGHT]; // count white held pieces
+ for(i=0; i<BOARD_HEIGHT; i++) handB += boards[move][i][BOARD_LEFT-1]; // count black held pieces
+ }
q = p;
if(appData.fischerCastling) {
+ if(handW) { // in shuffle S-Chess simply dump all virgin pieces
+ for(i=BOARD_RGHT-1; i>=BOARD_LEFT; i--)
+ if(boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a';
+ } else {
/* [HGM] write directly from rights */
if(boards[move][CASTLING][2] != NoRights &&
boards[move][CASTLING][0] != NoRights )
if(boards[move][CASTLING][2] != NoRights &&
boards[move][CASTLING][1] != NoRights )
*p++ = boards[move][CASTLING][1] + AAA + 'A' - 'a';
+ }
+ if(handB) {
+ for(i=BOARD_RGHT-1; i>=BOARD_LEFT; i--)
+ if(boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA;
+ } else {
if(boards[move][CASTLING][5] != NoRights &&
boards[move][CASTLING][3] != NoRights )
*p++ = boards[move][CASTLING][3] + AAA;
if(boards[move][CASTLING][5] != NoRights &&
boards[move][CASTLING][4] != NoRights )
*p++ = boards[move][CASTLING][4] + AAA;
+ }
} else {
/* [HGM] write true castling rights */
boards[move][CASTLING][2] != NoRights ) k = 1, *p++ = 'K';
q = (boards[move][CASTLING][1] == BOARD_LEFT &&
boards[move][CASTLING][2] != NoRights );
- if(gameInfo.variant == VariantSChess) { // for S-Chess, indicate all vrgin backrank pieces
- for(i=j=0; i<BOARD_HEIGHT; i++) j += boards[move][i][BOARD_RGHT]; // count white held pieces
- for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--)
+ if(handW) { // for S-Chess with pieces in hand, list virgin pieces between K and Q
+ for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--)
if((boards[move][0][i] != WhiteKing || k+q == 0) &&
boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a';
}
boards[move][CASTLING][5] != NoRights ) k = 1, *p++ = 'k';
q = (boards[move][CASTLING][4] == BOARD_LEFT &&
boards[move][CASTLING][5] != NoRights );
- if(gameInfo.variant == VariantSChess) {
- for(i=j=0; i<BOARD_HEIGHT; i++) j += boards[move][i][BOARD_LEFT-1]; // count black held pieces
- for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--)
+ if(handB) {
+ for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--)
if((boards[move][BOARD_HEIGHT-1][i] != BlackKing || k+q == 0) &&
boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA;
}