case VariantShatranj:
case VariantCourier:
case VariantMakruk:
+ case VariantGrand:
flags &= ~F_ALL_CASTLE_OK;
break;
default:
BlackQueen, BlackBishop, BlackKnight, BlackAngel, BlackRook }
};
+ChessSquare GrandArray[2][BOARD_FILES] = {
+ { EmptySquare, WhiteKnight, WhiteBishop, WhiteQueen, WhiteKing,
+ WhiteMarshall, WhiteAngel, WhiteBishop, WhiteKnight, EmptySquare },
+ { EmptySquare, BlackKnight, BlackBishop, BlackQueen, BlackKing,
+ BlackMarshall, BlackAngel, BlackBishop, BlackKnight, EmptySquare }
+};
+
#ifdef GOTHIC
ChessSquare GothicArray[2][BOARD_FILES] = {
{ WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall,
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 VariantMakruk: /* should work except for draw countdown */
case VariantBerolina: /* might work if TestLegality is off */
case VariantCapaRandom: /* should work */
case VariantJanus: /* should work */
case VariantSuper: /* experimental */
case VariantGreat: /* experimental, requires legality testing to be off */
case VariantSChess: /* S-Chess, should work */
+ case VariantGrand: /* should work */
case VariantSpartan: /* should work */
break;
}
safeStrCpy(moveList[moveNum - 1], currentMoveString, sizeof(moveList[moveNum - 1])/sizeof(moveList[moveNum - 1][0]));
strcat(moveList[moveNum - 1], "\n");
- if(gameInfo.holdingsWidth && !appData.disguise && gameInfo.variant != VariantSuper
- && gameInfo.variant != VariantGreat) // inherit info that ICS does not give from previous board
+ if(gameInfo.holdingsWidth && !appData.disguise && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantGrand) // inherit info that ICS does not give from previous board
for(k=0; k<ranks; k++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
ChessSquare old, new = boards[moveNum][k][j];
if(fromY == DROP_RANK && k==toY && j==toX) continue; // dropped pieces always stand for themselves
case VariantTwoKings:
pieces = twoKingsArray;
break;
+ case VariantGrand:
+ pieces = GrandArray;
+ nrCastlingRights = 0;
+ SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
+ gameInfo.boardWidth = 10;
+ gameInfo.boardHeight = 10;
+ gameInfo.holdingsSize = 7;
+ break;
case VariantCapaRandom:
shuffleOpenings = TRUE;
case VariantCapablanca:
pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
if(pawnRow < 1) pawnRow = 1;
- if(gameInfo.variant == VariantMakruk) pawnRow = 2;
+ if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) pawnRow = 2;
/* User pieceToChar list overrules defaults */
if(appData.pieceToCharTable != NULL)
initialPosition[i][j] = s;
if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue;
- initialPosition[0][j] = pieces[0][j-gameInfo.holdingsWidth];
+ initialPosition[gameInfo.variant == VariantGrand][j] = pieces[0][j-gameInfo.holdingsWidth];
initialPosition[pawnRow][j] = WhitePawn;
initialPosition[BOARD_HEIGHT-pawnRow-1][j] = gameInfo.variant == VariantSpartan ? BlackLance : BlackPawn;
if(gameInfo.variant == VariantXiangqi) {
}
}
}
- initialPosition[BOARD_HEIGHT-1][j] = pieces[1][j-gameInfo.holdingsWidth];
+ if(gameInfo.variant == VariantGrand) {
+ if(j==BOARD_LEFT || j>=BOARD_RGHT-1) {
+ initialPosition[0][j] = WhiteRook;
+ initialPosition[BOARD_HEIGHT-1][j] = BlackRook;
+ }
+ }
+ initialPosition[BOARD_HEIGHT-1-(gameInfo.variant == VariantGrand)][j] = pieces[1][j-gameInfo.holdingsWidth];
}
if( (gameInfo.variant == VariantShogi) && !overrule ) {
if(gameInfo.variant == VariantShogi) {
promotionZoneSize = BOARD_HEIGHT/3;
highestPromotingPiece = (int)WhiteFerz;
- } else if(gameInfo.variant == VariantMakruk) {
+ } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) {
promotionZoneSize = 3;
}
{
char *bookHit = 0;
- if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR) {
- // [HGM] superchess: suppress promotions to non-available piece
+ if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) && promoChar != NULLCHAR) {
+ // [HGM] superchess: suppress promotions to non-available piece (but P always allowed)
int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));
if(WhiteOnMove(currentMove)) {
if(!boards[currentMove][k][BOARD_WIDTH-2]) return 0;
if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
if(gameInfo.holdingsWidth &&
(WhiteOnMove(currentMove)
- ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
- : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
+ ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y >= 0
+ : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT) ) {
// click in right holdings, for determining promotion piece
ChessSquare p = boards[currentMove][y][x];
if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
- if(p != EmptySquare) {
- FinishMove(NormalMove, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
+ if(p == WhitePawn || p == BlackPawn) p = EmptySquare; // [HGM] Pawns could be valid as deferral
+ if(p != EmptySquare || gameInfo.variant == VariantGrand && toY != 0 && toY != BOARD_HEIGHT-1) { // [HGM] grand: empty square means defer
+ FinishMove(NormalMove, fromX, fromY, toX, toY, p==EmptySquare ? NULLCHAR : ToLower(PieceToChar(p)));
fromX = fromY = -1;
return;
}
if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice)) {
SetHighlights(fromX, fromY, toX, toY);
- if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
+ if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) {
// [HGM] super: promotion to captured piece selected from holdings
ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
promotionChoice = TRUE;
Board board;
{
ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
- int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1;
+ int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 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 */
board[fromY][BOARD_LEFT] = EmptySquare;
} else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi ||
board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
- && toY >= BOARD_HEIGHT-promoRank
+ && toY >= BOARD_HEIGHT-promoRank && promoChar // defaulting to Q is done elsewhere
) {
/* white pawn promotion */
board[toY][toX] = CharToPiece(ToUpper(promoChar));
- if (board[toY][toX] == EmptySquare) {
- board[toY][toX] = WhiteQueen;
- }
if(gameInfo.variant==VariantBughouse ||
gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
- } else if ((fromY == BOARD_HEIGHT-4)
+ } else if ((fromY >= BOARD_HEIGHT>>1)
&& (toX != fromX)
&& gameInfo.variant != VariantXiangqi
&& gameInfo.variant != VariantBerolina
board[toY][2] = BlackRook;
} else if ((board[fromY][fromX] == BlackPawn && gameInfo.variant != VariantXiangqi ||
board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
- && toY < promoRank
+ && toY < promoRank && promoChar
) {
/* black pawn promotion */
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 */
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
- } else if ((fromY == 3)
+ } else if ((fromY < BOARD_HEIGHT>>1)
&& (toX != fromX)
&& gameInfo.variant != VariantXiangqi
&& gameInfo.variant != VariantBerolina
if (captured != EmptySquare && gameInfo.holdingsSize > 0
&& gameInfo.variant != VariantBughouse && gameInfo.variant != VariantSChess ) {
/* [HGM] holdings: Add to holdings, if holdings exist */
- if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
+ if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) {
// [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip
captured = (int) captured >= (int) BlackPawn ? BLACK_TO_WHITE captured : WHITE_TO_BLACK captured;
}
} else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar
board[toY][toX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar));
}
- if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
- && promoChar != NULLCHAR && gameInfo.holdingsSize) {
+ if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand)
+ && promoChar != NULLCHAR && gameInfo.holdingsSize) {
// [HGM] superchess: take promotion piece out of holdings
int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));
if((int)piece < (int)BlackPawn) { // determine stm from piece color
overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
if( gameInfo.variant == VariantSChess )
overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 7;
+ if( gameInfo.variant == VariantGrand )
+ overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 7;
if(overruled) {
snprintf(b, MSG_SIZ, "%dx%d+%d_%s", gameInfo.boardWidth, gameInfo.boardHeight,
// now verify win claims, but not in drop games, as we don't understand those yet
if( (gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper
- || gameInfo.variant == VariantGreat) &&
+ || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) &&
(result == WhiteWins && claimer == 'w' ||
result == BlackWins && claimer == 'b' ) ) { // case to verify: engine claims own win
if (appData.debugMode) {
/* (Claiming a loss is accepted no questions asked!) */
}
/* [HGM] bare: don't allow bare King to win */
- if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
+ if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper
+ || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand)
&& gameInfo.variant != VariantLosers && gameInfo.variant != VariantGiveaway
&& gameInfo.variant != VariantSuicide // [HGM] losers: except in losers, of course...
&& result != GameIsDrawn)
int rf, ff;
int i, j, d, s, fs, rs, rt, ft, m;
int epfile = (signed char)board[EP_STATUS]; // [HGM] gamestate: extract ep status from board
- int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1;
+ int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
for (rf = 0; rf < BOARD_HEIGHT; rf++)
for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
rf, ff, rf + 1, ff, closure);
}
- if (rf == 1 && board[2][ff] == EmptySquare &&
+ if (rf <= (BOARD_HEIGHT>>1)-3 && board[rf+1][ff] == EmptySquare && // [HGM] grand: also on 3rd rank on 10-board
gameInfo.variant != VariantShatranj && /* [HGM] */
gameInfo.variant != VariantCourier && /* [HGM] */
- board[3][ff] == EmptySquare ) {
+ board[rf+2][ff] == EmptySquare ) {
callback(board, flags, NormalMove,
- rf, ff, 3, ff, closure);
+ rf, ff, rf+2, ff, closure);
}
for (s = -1; s <= 1; s += 2) {
if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
rf, ff, rf + 1, ff + s, closure);
}
- if (rf == BOARD_HEIGHT-4) {
+ if (rf >= BOARD_HEIGHT+1>>1) {// [HGM] grand: 4th & 5th rank on 10-board
if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
- (epfile == ff + s || epfile == EP_UNKNOWN) &&
- board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&
- board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {
+ (epfile == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 &&
+ board[rf][ff + s] == BlackPawn &&
+ board[rf+1][ff + s] == EmptySquare) {
callback(board, flags, WhiteCapturesEnPassant,
- rf, ff, 5, ff + s, closure);
+ rf, ff, rf+1, ff + s, closure);
}
}
}
rf <= promoRank ? BlackPromotion : NormalMove,
rf, ff, rf - 1, ff, closure);
}
- if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
+ if (rf >= (BOARD_HEIGHT+1>>1)+2 && board[rf-1][ff] == EmptySquare && // [HGM] grand
gameInfo.variant != VariantShatranj && /* [HGM] */
gameInfo.variant != VariantCourier && /* [HGM] */
- board[BOARD_HEIGHT-4][ff] == EmptySquare) {
+ board[rf-2][ff] == EmptySquare) {
callback(board, flags, NormalMove,
- rf, ff, BOARD_HEIGHT-4, ff, closure);
+ rf, ff, rf-2, ff, closure);
}
for (s = -1; s <= 1; s += 2) {
if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
rf <= promoRank ? BlackPromotion : NormalMove,
rf, ff, rf - 1, ff + s, closure);
}
- if (rf == 3) {
+ if (rf < BOARD_HEIGHT>>1) {
if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
- (epfile == ff + s || epfile == EP_UNKNOWN) &&
- board[3][ff + s] == WhitePawn &&
- board[2][ff + s] == EmptySquare) {
+ (epfile == ff + s || epfile == EP_UNKNOWN) && rf > 2 &&
+ board[rf][ff + s] == WhitePawn &&
+ board[rf-1][ff + s] == EmptySquare) {
callback(board, flags, BlackCapturesEnPassant,
- rf, ff, 2, ff + s, closure);
+ rf, ff, rf-1, ff + s, closure);
}
}
}
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) kings += (board[r][f] == BlackKing);
if(kings == 2) cl.kind = IllegalMove;
}
- } else if(piece == WhitePawn || piece == BlackPawn) cl.kind = IllegalMove; // cannot stay Pawn in any variant
+ } else if(piece == WhitePawn && rt == BOARD_HEIGHT-1 ||
+ piece == BlackPawn && rt == 0) cl.kind = IllegalMove; // cannot stay Pawn on last rank in any variant
else if((piece == WhiteUnicorn || piece == BlackUnicorn) && gameInfo.variant == VariantKnightmate)
cl.kind = IllegalMove; // promotion to Royal Knight not allowed
else if((piece == WhiteKing || piece == BlackKing) && gameInfo.variant != VariantSuicide && gameInfo.variant != VariantGiveaway)
if (cl.count > 0) {
return inCheck ? MT_CHECK : MT_NONE;
} else {
- if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat) { // drop game
+ if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantGrand) { // drop game
int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0;
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) if(board[r][f] == EmptySquare) // all empty squares
for(n=0; n<BOARD_HEIGHT; n++) // all pieces in hand
c = PieceToChar(BlackFerz);
else if(gameInfo.variant == VariantGreat)
c = PieceToChar(BlackMan);
+ else if(gameInfo.variant == VariantGrand)
+ closure->kind = closure->rt != 0 && closure->rt != BOARD_HEIGHT-1 ? NormalMove : AmbiguousMove; // no default in Grand Chess
else
c = PieceToChar(BlackQueen);
} else if(c == '=') closure->kind = IllegalMove; // no deferral outside Shogi
{ VariantSuicide, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("suicide")},
{ VariantCapaRandom, 1, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("CRC (10x8)")},
{ VariantGiveaway, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("give-away")},
-{ VariantSpartan, 1, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
+{ VariantGrand, 1, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("grand (10x10)")},
{ VariantLosers, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("losers")},
+{ VariantSpartan, 1, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size ( -1 = default for selected variant):")},
{ 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.NrRanks, "", NULL, Spin, N_("Number of Board Ranks:") },
{ 0, -1, BOARD_FILES, NULL, (void*) &appData.NrFiles, "", NULL, Spin, N_("Number of Board Files:") },