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
else SendToProgram("O-O-O\n", cps);
}
else SendToProgram(moveList[moveNum], cps);
+ } else
+ if(BOARD_HEIGHT > 10) { // [HGM] big: convert ranks to double-digit where needed
+ if(moveList[moveNum][1] == '@' && (BOARD_HEIGHT < 16 || moveList[moveNum][0] <= 'Z')) { // drop move
+ snprintf(buf, MSG_SIZ, "%c@%c%d%s", moveList[moveNum][0],
+ moveList[moveNum][2], moveList[moveNum][3] - '0', moveList[moveNum]+4);
+ } else
+ snprintf(buf, MSG_SIZ, "%c%d%c%d%s", moveList[moveNum][0], moveList[moveNum][1] - '0',
+ moveList[moveNum][2], moveList[moveNum][3] - '0', moveList[moveNum]+4);
+ SendToProgram(buf, cps);
}
else SendToProgram(moveList[moveNum], cps);
/* End of additions by Tord */
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 ) {
static int autoQueen; // [HGM] oneclick
int
-HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
+HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice, int sweepSelect)
{
/* [HGM] rewritten IsPromotion to only flag promotions that offer a choice */
/* [HGM] add Shogi promotions */
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;
}
}
// give caller the default choice even if we will not make it
*promoChoice = ToLower(PieceToChar(defaultPromoChoice));
- if(gameInfo.variant == VariantShogi) *promoChoice = '+';
- if(appData.sweepSelect && gameInfo.variant != VariantGreat
- && gameInfo.variant != VariantShogi
+ if(gameInfo.variant == VariantShogi) *promoChoice = (defaultPromoChoice == piece ? '=' : '+');
+ if( sweepSelect && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantGrand
&& gameInfo.variant != VariantSuper) return FALSE;
if(autoQueen) return FALSE; // predetermined
Boolean
OnlyMove(int *x, int *y, Boolean captures) {
DisambiguateClosure cl;
- if (appData.zippyPlay) return FALSE;
+ if (appData.zippyPlay || !appData.testLegality) return FALSE;
switch(gameMode) {
case MachinePlaysBlack:
case IcsPlayingWhite:
{
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;
MarkTargetSquares(int clear)
{
int x, y;
- if(!appData.markers || !appData.highlightDragging ||
+ if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
!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;
}
if (clickType == Press) ErrorPopDown();
- MarkTargetSquares(1);
x = EventToSquare(xPix, BOARD_WIDTH);
y = EventToSquare(yPix, BOARD_HEIGHT);
defaultPromoChoice = promoSweep;
promoSweep = EmptySquare; // terminate sweep
promoDefaultAltered = TRUE;
- if(!selectFlag) x = fromX, y = fromY; // and fake up-click on same square if we were still selecting
+ if(!selectFlag && (x != toX || y != toY)) x = fromX, y = fromY; // and fake up-click on same square if we were still selecting
}
if(promotionChoice) { // we are waiting for a click to indicate promotion piece
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;
}
}
return;
}
- fromX = x; fromY = y;
+ fromX = x; fromY = y; toX = toY = -1;
if(!appData.oneClick || !OnlyMove(&x, &y, FALSE) ||
// even if only move, we treat as normal when this would trigger a promotion popup, to allow sweep selection
appData.sweepSelect && CanPromote(boards[currentMove][fromY][fromX], fromY) && originalY != y) {
if (OKToStartUserMove(fromX, fromY)) {
second = 0;
MarkTargetSquares(0);
- DragPieceBegin(xPix, yPix); dragging = 1;
+ DragPieceBegin(xPix, yPix, FALSE); dragging = 1;
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][fromY][fromX], fromY)) {
promoSweep = defaultPromoChoice;
selectFlag = 0; lastX = xPix; lastY = yPix;
/* Clicked again on same color piece -- changed his mind */
second = (x == fromX && y == fromY);
promoDefaultAltered = FALSE;
+ MarkTargetSquares(1);
if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) {
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
fromX = x;
fromY = y; dragging = 1;
MarkTargetSquares(0);
- DragPieceBegin(xPix, yPix);
+ DragPieceBegin(xPix, yPix, FALSE);
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
promoSweep = defaultPromoChoice;
selectFlag = 0; lastX = xPix; lastY = yPix;
toX = x;
toY = y;
saveAnimate = appData.animate;
+ MarkTargetSquares(1);
if (clickType == Press) {
if(gameMode == EditPosition && boards[currentMove][fromY][fromX] == EmptySquare) {
// must be Edit Position mode with empty-square selected
- fromX = x; fromY = y; DragPieceBegin(xPix, yPix); dragging = 1; // consider this a new attempt to drag
+ fromX = x; fromY = y; DragPieceBegin(xPix, yPix, FALSE); dragging = 1; // consider this a new attempt to drag
if(x >= BOARD_LEFT && x < BOARD_RGHT) clearFlag = 1; // and defer click-click move of empty-square to up-click
return;
}
+ if(appData.sweepSelect && HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
+ ChessSquare piece = boards[currentMove][fromY][fromX];
+ DragPieceBegin(xPix, yPix, TRUE); dragging = 1;
+ promoSweep = defaultPromoChoice;
+ if(PieceToChar(PROMOTED piece) == '+') promoSweep = PROMOTED piece;
+ selectFlag = 0; lastX = xPix; lastY = yPix;
+ Sweep(0); // Pawn that is going to promote: preview promotion piece
+ DisplayMessage("", _("Pull pawn backwards to under-promote"));
+ DrawPosition(FALSE, boards[currentMove]);
+ return;
+ }
/* Finish clickclick move */
if (appData.animate || appData.highlightLastMove) {
SetHighlights(fromX, fromY, toX, toY);
if(gatingPiece != EmptySquare) promoChoice = ToLower(PieceToChar(gatingPiece));
- if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice)) {
+ if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
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;
toX = xSqr; toY = ySqr; lastX = x, lastY = y;
if(flipView) toX = BOARD_WIDTH - 1 - toX; else toY = BOARD_HEIGHT - 1 - toY;
NextPiece(0);
- return -2;
+ return 2; // grab
case IcsObserving:
if(!appData.icsEngineAnalyze) return -1;
case IcsPlayingWhite:
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,
fprintf(f, "-loadPositionIndex %d\n", appData.loadPositionIndex);
fprintf(f, "-rewindIndex %d\n", appData.rewindIndex);
if(searchTime > 0)
- fprintf(f, "-searchTime \"%s\"\n", appData.searchTime);
+ fprintf(f, "-searchTime \"%d:%02d\"\n", searchTime/60, searchTime%60);
else {
fprintf(f, "-mps %d\n", appData.movesPerSession);
fprintf(f, "-tc %s\n", appData.timeControl);
// 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)
char *text;
{
char title[MSG_SIZ];
- char buf[8000]; // comment can be long!
- int score, depth;
if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) {
safeStrCpy(title, "Comment", sizeof(title)/sizeof(title[0]));
WhiteOnMove(moveNumber) ? " " : ".. ",
parseList[moveNumber]);
}
- // [HGM] PV info: display PV info together with (or as) comment
- if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) {
- if(text == NULL) text = "";
- score = pvInfoList[moveNumber].score;
- snprintf(buf,sizeof(buf)/sizeof(buf[0]), "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100.,
- depth, (pvInfoList[moveNumber].time+50)/100, text);
- text = buf;
- }
if (text != NULL && (appData.autoDisplayComment || commentUp))
CommentPopUp(title, text);
}
{
int i, j, fromX, fromY, toX, toY;
int whiteToPlay;
- char buf[128];
+ char buf[MSG_SIZ];
char *p, *q;
int emptycount;
ChessSquare piece;
/* Piece placement data */
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
+ if(MSG_SIZ - (p - buf) < BOARD_RGHT - BOARD_LEFT + 20) { *p = 0; return StrSave(buf); }
emptycount = 0;
for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {
if (boards[move][i][j] == EmptySquare) {