Boolean
ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
{
- int i, j, k, w=0;
+ int i, j, k, w=0, subst=0, shuffle=0;
char *p, c;
int emptycount, virgin[BOARD_FILES];
ChessSquare piece;
if (j + emptycount > gameInfo.boardWidth) return FALSE;
while (emptycount--)
board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;
+ } else if (*p == '<') {
+ if(i == BOARD_HEIGHT-1) shuffle = 1;
+ else if (i != 0 || !shuffle) return FALSE;
+ p++;
+ } else if (shuffle && *p == '>') {
+ p++; // for now ignore closing shuffle range, and assume rank-end
+ } else if (*p == '?') {
+ if (j >= gameInfo.boardWidth) return FALSE;
+ 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)) {
if (j >= gameInfo.boardWidth) return FALSE;
if(*p=='+') {
/* [HGM] look for Crazyhouse holdings here */
while(*p==' ') p++;
if( gameInfo.holdingsWidth && p[-1] == '/' || *p == '[') {
+ int swap=0, wcnt=0, bcnt=0;
if(*p == '[') p++;
+ if(*p == '<') swap++, p++;
if(*p == '-' ) p++; /* empty holdings */ else {
if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */
/* if we would allow FEN reading to set board size, we would */
if( i >= gameInfo.holdingsSize ) return FALSE;
board[BOARD_HEIGHT-1-i][0] = piece; /* black holdings */
board[BOARD_HEIGHT-1-i][1]++; /* black counts */
+ bcnt++;
} else {
i = (int)piece - (int)WhitePawn;
i = PieceToNumber((ChessSquare)i);
if( i >= gameInfo.holdingsSize ) return FALSE;
board[i][BOARD_WIDTH-1] = piece; /* white holdings */
board[i][BOARD_WIDTH-2]++; /* black holdings */
+ wcnt++;
+ }
+ }
+ if(subst) { // substitute back-rank question marks by holdings pieces
+ for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
+ int k, m, n = bcnt + 1;
+ if(board[0][j] == ClearBoard) {
+ if(!wcnt) return FALSE;
+ n = rand() % wcnt;
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((m -= board[k][BOARD_WIDTH-2]) < 0) {
+ board[0][j] = board[k][BOARD_WIDTH-1]; wcnt--;
+ if(--board[k][BOARD_WIDTH-2] == 0) board[k][BOARD_WIDTH-1] = EmptySquare;
+ break;
+ }
+ }
+ if(board[BOARD_HEIGHT-1][j] == ClearBoard) {
+ if(!bcnt) return FALSE;
+ if(n >= bcnt) n = rand() % bcnt; // use same randomization for black and white if possible
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[BOARD_HEIGHT-1-k][1]) < 0) {
+ board[BOARD_HEIGHT-1][j] = board[BOARD_HEIGHT-1-k][0]; bcnt--;
+ if(--board[BOARD_HEIGHT-1-k][1] == 0) board[BOARD_HEIGHT-1-k][0] = EmptySquare;
+ break;
+ }
+ }
}
+ subst = 0;
}
}
if(*p == ']') p++;
}
+ if(subst) return FALSE; // substitution requested, but no holdings
+
while(*p == ' ') p++;
/* Active color */
while(*p==' ') p++;
if(nrCastlingRights) {
+ int fischer = 0;
if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) virgin[i] = 0;
if(*p >= 'A' && *p <= 'Z' || *p >= 'a' && *p <= 'z' || *p=='-') {
/* castling indicator present, so default becomes no castlings */
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= 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++);
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][1] != NoRights) virgin[board[CASTLING][1]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= 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--);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= 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++);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][4] != NoRights) virgin[board[CASTLING][4]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
+ if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
case '-':
break;
default: /* FRC castlings */
}
for(i=0; i<nrCastlingRights; i++)
if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
- if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = virgin[i];
+ if(gameInfo.variant == VariantSChess)
+ for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = shuffle ? VIRGIN_W | VIRGIN_B : virgin[i]; // when shuffling assume all virgin
+ if(fischer && shuffle) appData.fischerCastling = TRUE;
if (appData.debugMode) {
fprintf(debugFP, "FEN castling rights:");
for(i=0; i<nrCastlingRights; i++)
while(*p==' ') p++;
}
+ if(shuffle) SetUpShuffle(board, appData.defaultFrcPosition);
+
/* read e.p. field in games that know e.p. capture */
if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&
gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&