if(step && !(toggleFlag && Partner(&promoSweep))) promoSweep -= step;
if(promoSweep == EmptySquare) promoSweep = BlackPawn; // wrap
else if((int)promoSweep == -1) promoSweep = WhiteKing;
- else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn;
- else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing;
+ else if(promoSweep == BlackPawn && step < 0 && !toggleFlag) promoSweep = WhitePawn;
+ else if(promoSweep == WhiteKing && step > 0 && !toggleFlag) promoSweep = BlackKing;
if(!step) step = -1;
} while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
!toggleFlag && PieceToChar(promoSweep) == '+' || // skip promoted versions of other
case BlackASideCastleFR:
/* End of code added by Tord */
case IllegalMove: /* bug or odd chess variant */
- if(currentMoveString[1] == '@') goto drop; // illegal drop
+ if(currentMoveString[1] == '@') { // illegal drop
+ *fromX = WhiteOnMove(moveNum) ?
+ (int) CharToPiece(ToUpper(currentMoveString[0])) :
+ (int) CharToPiece(ToLower(currentMoveString[0]));
+ goto drop;
+ }
*fromX = currentMoveString[0] - AAA;
*fromY = currentMoveString[1] - ONE;
*toX = currentMoveString[2] - AAA;
case WhiteDrop:
case BlackDrop:
- drop:
*fromX = *moveType == WhiteDrop ?
(int) CharToPiece(ToUpper(currentMoveString[0])) :
(int) CharToPiece(ToLower(currentMoveString[0]));
+ drop:
*fromY = DROP_RANK;
*toX = currentMoveString[2] - AAA;
*toY = currentMoveString[3] - ONE;
}
int
-SetCharTable (char *table, const char * map)
+ptclen (const char *s, char *escapes)
+{
+ int n = 0;
+ if(!*escapes) return strlen(s);
+ while(*s) n += (*s != ':' && !strchr(escapes, *s)), s++;
+ return n;
+}
+
+int
+SetCharTableEsc (unsigned char *table, const char * map, char * escapes)
/* [HGM] moved here from winboard.c because of its general usefulness */
/* Basically a safe strcpy that uses the last character as King */
{
int result = FALSE; int NrPieces;
- if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare
+ if( map != NULL && (NrPieces=ptclen(map, escapes)) <= (int) EmptySquare
&& NrPieces >= 12 && !(NrPieces&1)) {
- int i; /* [HGM] Accept even length from 12 to 34 */
+ int i, j = 0; /* [HGM] Accept even length from 12 to 88 */
for( i=0; i<(int) EmptySquare; i++ ) table[i] = '.';
for( i=0; i<NrPieces/2-1; i++ ) {
- table[i] = map[i];
- table[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];
+ char *p;
+ if(map[j] == ':' && *escapes) i = CHUPROMOTED WhitePawn, j++;
+ table[i] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[i] += 64*(p - escapes + 1);
+ }
+ table[(int) WhiteKing] = map[j++];
+ for( i=0; i<NrPieces/2-1; i++ ) {
+ char *p;
+ if(map[j] == ':' && *escapes) i = CHUPROMOTED WhitePawn, j++;
+ table[WHITE_TO_BLACK i] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[WHITE_TO_BLACK i] += 64*(p - escapes + 1);
}
- table[(int) WhiteKing] = map[NrPieces/2-1];
- table[(int) BlackKing] = map[NrPieces-1];
+ table[(int) BlackKing] = map[j++];
result = TRUE;
}
return result;
}
+int
+SetCharTable (unsigned char *table, const char * map)
+{
+ return SetCharTableEsc(table, map, "");
+}
+
void
Prelude (Board board)
{ // [HGM] superchess: random selection of exo-pieces
gameInfo.boardWidth = 12;
gameInfo.boardHeight = 12;
nrCastlingRights = 0;
- SetCharTable(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN+.++.++++++++++.+++++K"
- "p.brqsexogcathd.vmlifn+.++.++++++++++.+++++k");
+ SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN:+.++.++++++++++.+++++K"
+ "p.brqsexogcathd.vmlifn:+.++.++++++++++.+++++k", SUFFIXES);
break;
case VariantCourier:
pieces = CourierArray;
/* User pieceToChar list overrules defaults */
if(appData.pieceToCharTable != NULL)
- SetCharTable(pieceToChar, appData.pieceToCharTable);
+ SetCharTableEsc(pieceToChar, appData.pieceToCharTable, SUFFIXES);
for( j=0; j<BOARD_WIDTH; j++ ) { ChessSquare s = EmptySquare;
promotionZoneSize = BOARD_HEIGHT/3;
highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion;
} else if(gameInfo.variant == VariantShogi) {
- promotionZoneSize = BOARD_HEIGHT/3;
+ promotionZoneSize = BOARD_HEIGHT/3 +(BOARD_HEIGHT == 8);
highestPromotingPiece = (int)WhiteAlfil;
} else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
promotionZoneSize = 3;
toP = boards[currentMove][y][x];
frc = appData.fischerCastling || gameInfo.variant == VariantSChess;
if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect!
- legal[y][x] == 0 && // if engine told we can move to here, do it even if own piece
+ marker[y][x] == 0 && // if engine told we can move to here, do it even if own piece
((WhitePawn <= fromP && fromP <= WhiteKing &&
WhitePawn <= toP && toP <= WhiteKing &&
!(fromP == WhiteKing && toP == WhiteRook && frc) &&
else gatingPiece = doubleClick ? fromP : EmptySquare;
fromX = x;
fromY = y; dragging = 1;
- ReportClick("lift", x, y);
+ if(!second) ReportClick("lift", x, y);
MarkTargetSquares(0);
DragPieceBegin(xPix, yPix, FALSE);
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
return;
}
- if (clickType == Release && x == fromX && y == fromY && killX < 0) {
+ if (clickType == Release && x == fromX && y == fromY && killX < 0 && !sweepSelecting) {
DragPieceEnd(xPix, yPix); dragging = 0;
if(clearFlag) {
// a deferred attempt to click-click move an empty square on top of a piece
/* Undo animation damage if any */
DrawPosition(FALSE, NULL);
}
- if (second || sweepSelecting) {
+ if (second) {
/* Second up/down in same square; just abort move */
- if(sweepSelecting) DrawPosition(FALSE, boards[currentMove]);
- second = sweepSelecting = 0;
+ second = 0;
fromX = fromY = -1;
gatingPiece = EmptySquare;
MarkTargetSquares(1);
if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece));
- if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
+ if(legal[toY][toX] == 2) promoChoice = ToLower(PieceToChar(defaultPromoChoice)); // highlight-induced promotion
+
+ if (legal[toY][toX] == 2 && !appData.sweepSelect || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
SetHighlights(fromX, fromY, toX, toY);
MarkTargetSquares(1);
if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) {
if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
*buf = NULLCHAR;
if(sscanf(message, "setup (%s", buf) == 1) {
- s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
+ s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTableEsc(pieceToChar, buf, SUFFIXES);
ASSIGN(appData.pieceToCharTable, buf);
}
dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName);
appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand;
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
+ if(*buf) SetCharTableEsc(pieceToChar, buf, SUFFIXES); // do again, for it was spoiled by InitPosition
startedFromSetupPosition = FALSE;
}
}
}
if(sscanf(message, "piece %s %s", buf2, buf1) == 2) {
ChessSquare piece = WhitePawn;
- char *p=buf2;
- if(*p == '+') piece = CHUPROMOTED WhitePawn, p++;
- piece += CharToPiece(*p) - WhitePawn;
+ char *p=buf2, *q, *s = SUFFIXES, ID = *p;
+ if(*p == '+') piece = CHUPROMOTED WhitePawn, ID = *++p;
+ if(q = strchr(s, p[1])) ID += 64*(q - s + 1), p++;
+ piece += CharToPiece(ID) - WhitePawn;
if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR
/* always accept definition of */ && piece != WhiteFalcon && piece != BlackFalcon
/* wild-card pieces. */ && piece != WhiteCobra && piece != BlackCobra
return;
}
if(!strncmp(message, "highlight ", 10)) {
- if(appData.testLegality && appData.markers) return;
+ if((appData.testLegality || *engineVariant) && appData.markers) return;
MarkByFEN(message+10); // [HGM] alien: allow engine to mark board squares
return;
}
if (appData.debugMode)
fprintf(debugFP, "Parsed %s into IllegalMove %s\n",
yy_text, currentMoveString);
- fromX = currentMoveString[0] - AAA;
- fromY = currentMoveString[1] - ONE;
+ if(currentMoveString[1] == '@') {
+ fromX = CharToPiece(WhiteOnMove(currentMove) ? ToUpper(currentMoveString[0]) : ToLower(currentMoveString[0]));
+ fromY = DROP_RANK;
+ } else {
+ fromX = currentMoveString[0] - AAA;
+ fromY = currentMoveString[1] - ONE;
+ }
toX = currentMoveString[2] - AAA;
toY = currentMoveString[3] - ONE;
promoChar = currentMoveString[4];
int numPGNTags = 0;
int err, pos = -1;
GameMode oldGameMode;
- VariantClass oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
+ VariantClass v, oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
+ char oldName[MSG_SIZ];
+
+ safeStrCpy(oldName, engineVariant, MSG_SIZ); v = oldVariant;
if (appData.debugMode)
fprintf(debugFP, "LoadGame(): on entry, gameMode %d\n", gameMode);
StartChessProgram(&first);
}
InitChessProgram(&first, FALSE);
+ if(gameInfo.variant == VariantUnknown && *oldName) {
+ safeStrCpy(engineVariant, oldName, MSG_SIZ);
+ gameInfo.variant = v;
+ }
SendToProgram("force\n", &first);
if (startedFromSetupPosition) {
SendBoard(&first, forwardMostMove);
DisplayError(_("Position not found in file"), 0);
return FALSE;
}
- // [HGM] FEN can begin with digit, any piece letter valid in this variant, or a + for Shogi promoted pieces
- fenMode = line[0] >= '0' && line[0] <= '9' || line[0] == '+' || CharToPiece(line[0]) != EmptySquare;
+ // [HGM] FEN can begin with digit, any piece letter valid in this variant, or a + for Shogi promoted pieces (or * for blackout)
+ fenMode = line[0] >= '0' && line[0] <= '9' || line[0] == '+' || line[0] == '*' || CharToPiece(line[0]) != EmptySquare;
if (pn >= 2) {
if (fenMode || line[0] == '#') pn--;
piece = (ChessSquare)(CHUDEMOTED piece);
}
*p++ = (piece == DarkSquare ? '*' : PieceToChar(piece));
+ if(*p = PieceSuffix(piece)) p++;
if(p[-1] == '~') {
/* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */
p[-1] = PieceToChar((ChessSquare)(CHUDEMOTED piece));
Boolean
ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
{
- int i, j, k, w=0, subst=0, shuffle=0;
+ int i, j, k, w=0, subst=0, shuffle=0, wKingRank = -1, bKingRank = -1;
char *p, c;
int emptycount, virgin[BOARD_FILES];
ChessSquare piece;
if (i != 0 && i != BOARD_HEIGHT-1) return FALSE; // only on back-rank
board[i][(j++)+gameInfo.holdingsWidth] = ClearBoard; p++; subst++; // placeHolder
} else if (*p == '+' || isalpha(*p)) {
+ char *q, *s = SUFFIXES;
if (j >= gameInfo.boardWidth) return FALSE;
if(*p=='+') {
- piece = CharToPiece(*++p);
+ char c = *++p;
+ if(q = strchr(s, p[1])) p++;
+ piece = CharToPiece(c + (q ? 64*(q - s + 1) : 0));
if(piece == EmptySquare) return FALSE; /* unknown piece */
piece = (ChessSquare) (CHUPROMOTED piece ); p++;
if(PieceToChar(piece) != '+') return FALSE; /* unpromotable piece */
- } else piece = CharToPiece(*p++);
+ } else {
+ char c = *p++;
+ if(q = strchr(s, *p)) p++;
+ piece = CharToPiece(c + (q ? 64*(q - s + 1) : 0));
+ }
if(piece==EmptySquare) return FALSE; /* unknown piece */
if(*p == '~') { /* [HGM] make it a promoted piece for Crazyhouse */
p++;
}
board[i][(j++)+gameInfo.holdingsWidth] = piece;
+ if(piece == WhiteKing) wKingRank = i;
+ if(piece == BlackKing) bKingRank = i;
} else {
return FALSE;
}
/* [HGM] We NO LONGER ignore the rest of the FEN notation */
/* return the extra info in global variiables */
+ while(*p==' ') p++;
+
+ if(!isdigit(*p) && *p != '-') { // we seem to have castling rights. Make sure they are on the rank the King actually is.
+ if(wKingRank >= 0) for(i=0; i<3; i++) castlingRank[i] = wKingRank;
+ if(bKingRank >= 0) for(i=3; i<6; i++) castlingRank[i] = bKingRank;
+ }
+
/* set defaults in case FEN is incomplete */
board[EP_STATUS] = EP_UNKNOWN;
for(i=0; i<nrCastlingRights; i++ ) {
&& board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
FENrulePlies = 0;
- while(*p==' ') p++;
if(nrCastlingRights) {
int fischer = 0;
if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) virgin[i] = 0;
int c = *p++, 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(board[castlingRank[5]][i] == BlackKing) blackKingFile = i;
+ if(board[castlingRank[2]][i] == WhiteKing) whiteKingFile = i;
}
if(gameInfo.variant == VariantTwoKings || gameInfo.variant == VariantKnightmate)
whiteKingFile = blackKingFile = BOARD_WIDTH >> 1; // for these variant scanning fails
&& board[BOARD_HEIGHT-1][blackKingFile] != BlackKing) blackKingFile = NoRights;
switch(c) {
case'K':
- for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--);
+ for(i=BOARD_RGHT-1; board[castlingRank[2]][i]!=WhiteRook && i>whiteKingFile; i--);
board[CASTLING][0] = i != whiteKingFile ? i : NoRights;
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W;
if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'Q':
- for(i=BOARD_LEFT; i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
+ for(i=BOARD_LEFT; i<BOARD_RGHT && board[castlingRank[2]][i]!=WhiteRook && i<whiteKingFile; i++);
board[CASTLING][1] = i != whiteKingFile ? i : NoRights;
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][1] != NoRights) virgin[board[CASTLING][1]] |= VIRGIN_W;
if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
break;
case'k':
- for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--);
+ for(i=BOARD_RGHT-1; board[castlingRank[5]][i]!=BlackRook && i>blackKingFile; i--);
board[CASTLING][3] = i != blackKingFile ? i : NoRights;
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B;
if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'q':
- for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
+ for(i=BOARD_LEFT; i<BOARD_RGHT && board[castlingRank[5]][i]!=BlackRook && i<blackKingFile; i++);
board[CASTLING][4] = i != blackKingFile ? i : NoRights;
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][4] != NoRights) virgin[board[CASTLING][4]] |= VIRGIN_B;