{ WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,\r
WhiteKing, WhiteKing, WhiteKnight, WhiteRook },\r
{ BlackRook, BlackKnight, BlackBishop, BlackQueen,\r
- BlackKing, BlackKing, BlackKnight, BlackRook }\r
+ BlackKing, BlackKing, BlackKnight, BlackRook }\r
};\r
\r
#ifdef FAIRY\r
+ChessSquare KnightmateArray[2][BOARD_SIZE] = {\r
+ { WhiteRook, WhiteMan, WhiteBishop, WhiteQueen,\r
+ WhiteUnicorn, WhiteBishop, WhiteMan, WhiteRook },\r
+ { BlackRook, BlackMan, BlackBishop, BlackQueen,\r
+ BlackUnicorn, BlackBishop, BlackMan, BlackRook }\r
+};\r
+\r
ChessSquare fairyArray[2][BOARD_SIZE] = { /* [HGM] Queen side differs from King side */\r
- { WhiteFairyRook, WhiteFairyKnight, WhiteFairyBishop, WhiteQueen,\r
+ { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen,\r
WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },\r
- { BlackFairyRook, BlackFairyKnight, BlackFairyBishop, BlackQueen,\r
+ { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen,\r
BlackKing, BlackBishop, BlackKnight, BlackRook }\r
};\r
\r
ChessSquare ShatranjArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatranj Q and P) */\r
- { WhiteRook, WhiteKnight, WhiteFairyBishop, WhiteFairyPawn,\r
- WhiteKing, WhiteFairyBishop, WhiteKnight, WhiteRook },\r
- { BlackRook, BlackKnight, BlackFairyBishop, BlackFairyPawn,\r
- BlackKing, BlackFairyBishop, BlackKnight, BlackRook }\r
+ { WhiteRook, WhiteKnight, WhiteAlfil, WhiteFerz,\r
+ WhiteKing, WhiteAlfil, WhiteKnight, WhiteRook },\r
+ { BlackRook, BlackKnight, BlackAlfil, BlackFerz,\r
+ BlackKing, BlackAlfil, BlackKnight, BlackRook }\r
+};\r
+\r
+\r
+#if (BOARD_SIZE>=10)\r
+ChessSquare ShogiArray[2][BOARD_SIZE] = {\r
+ { WhiteQueen, WhiteKnight, WhiteFerz, WhiteWazir,\r
+ WhiteKing, WhiteWazir, WhiteFerz, WhiteKnight, WhiteQueen },\r
+ { BlackQueen, BlackKnight, BlackFerz, BlackWazir,\r
+ BlackKing, BlackWazir, BlackFerz, BlackKnight, BlackQueen }\r
};\r
\r
-#if (BOARD_SIZE>=9)\r
ChessSquare XiangqiArray[2][BOARD_SIZE] = {\r
- { WhiteRook, WhiteKnight, WhiteFairyBishop, WhiteFairyPawn,\r
- WhiteKing, WhiteFairyPawn, WhiteFairyBishop, WhiteKnight, WhiteRook },\r
- { BlackRook, BlackKnight, BlackFairyBishop, BlackFairyPawn,\r
- BlackKing, BlackFairyPawn, BlackFairyBishop, BlackKnight, BlackRook }\r
+ { WhiteRook, WhiteKnight, WhiteAlfil, WhiteFerz,\r
+ WhiteWazir, WhiteFerz, WhiteAlfil, WhiteKnight, WhiteRook },\r
+ { BlackRook, BlackKnight, BlackAlfil, BlackFerz,\r
+ BlackWazir, BlackFerz, BlackAlfil, BlackKnight, BlackRook }\r
};\r
-#else\r
-#define XiangqiPosition FIDEPosition\r
-#endif\r
\r
-#if (BOARD_SIZE>=10)\r
ChessSquare CapablancaArray[2][BOARD_SIZE] = {\r
{ WhiteRook, WhiteKnight, WhiteCardinal, WhiteBishop, WhiteQueen, \r
WhiteKing, WhiteBishop, WhiteMarshall, WhiteKnight, WhiteRook },\r
#endif // !GOTHIC\r
\r
#else // !(BOARD_SIZE>=10)\r
+#define XiangqiPosition FIDEArray\r
#define CapablancaArray FIDEArray\r
#define GothicArray FIDEArray\r
#endif // !(BOARD_SIZE>=10)\r
\r
#if (BOARD_SIZE>=12)\r
ChessSquare CourierArray[2][BOARD_SIZE] = {\r
- { WhiteRook, WhiteKnight, WhiteFairyBishop, WhiteBishop, WhiteFairyKing, WhiteKing,\r
- WhiteFairyPawn, WhiteFairyRook, WhiteBishop, WhiteFairyBishop, WhiteKnight, WhiteRook },\r
- { BlackRook, BlackKnight, BlackFairyBishop, BlackBishop, BlackFairyKing, BlackKing,\r
- BlackFairyPawn, BlackFairyRook, BlackBishop, BlackFairyBishop, BlackKnight, BlackRook }\r
+ { WhiteRook, WhiteKnight, WhiteAlfil, WhiteBishop, WhiteMan, WhiteKing,\r
+ WhiteFerz, WhiteWazir, WhiteBishop, WhiteAlfil, WhiteKnight, WhiteRook },\r
+ { BlackRook, BlackKnight, BlackAlfil, BlackBishop, BlackMan, BlackKing,\r
+ BlackFerz, BlackWazir, BlackBishop, BlackAlfil, BlackKnight, BlackRook }\r
};\r
#else // !(BOARD_SIZE>=12)\r
#define CourierArray CapablancaArray\r
case VariantLoadable:\r
case Variant29:\r
case Variant30:\r
-#ifndef FAIRY\r
case Variant31:\r
case Variant32:\r
case Variant33:\r
case Variant34:\r
case Variant35:\r
case Variant36:\r
-#endif\r
default:\r
sprintf(buf, "Unknown variant name %s", appData.variant);\r
DisplayFatalError(buf, 0, 2);\r
return;\r
\r
+ case VariantXiangqi: /* [HGM] repetition rules not implemented */\r
+ case VariantFairy: /* [HGM] TestLegality definitely off! */\r
+ case VariantGothic: /* [HGM] should work */\r
+ case VariantCapablanca: /* [HGM] should work */\r
+ case VariantCourier: /* [HGM] initial forced moves not implemented */\r
+ case VariantShogi: /* [HGM] drops not tested for legality */\r
+ case VariantShowgi: /* [HGM] not a valid variant */\r
+ case VariantKnightmate: /* [HGM] should work */\r
+ case VariantCrazyhouse: /* holdings not shown, ([HGM] fixed that!)\r
+ offboard interposition not understood */\r
case VariantNormal: /* definitely works! */\r
case VariantWildCastle: /* pieces not automatically shuffled */\r
case VariantNoCastle: /* pieces not automatically shuffled */\r
case VariantFischeRandom: /* Fabien: pieces not automatically shuffled */\r
- case VariantCrazyhouse: /* holdings not shown,\r
- offboard interposition not understood */\r
case VariantLosers: /* should work except for win condition,\r
and doesn't know captures are mandatory */\r
case VariantSuicide: /* should work except for win condition,\r
case VariantAtomic: /* should work except for win condition */\r
case Variant3Check: /* should work except for win condition */\r
case VariantShatranj: /* might work if TestLegality is off */\r
-#ifdef FAIRY\r
- case VariantShogi:\r
- case VariantXiangqi:\r
- case VariantFairy: /* [HGM] TestLegality definitely off! */\r
- case VariantGothic:\r
- case VariantCapablanca:\r
- case VariantCourier:\r
-#endif\r
break;\r
}\r
}\r
char buf[MSG_SIZ];\r
\r
if (!e) return v;\r
- \r
+\r
+ /* [HGM] skip over optional board-size prefixes */\r
+ if( sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) {\r
+ while( *e++ != '_');\r
+ } else if( sscanf(e, "%dx%d_", &i, &i) == 2 ) {\r
+ while( *e++ != '_');\r
+ }\r
+\r
for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {\r
if (StrCaseStr(e, variantNames[i])) {\r
v = (VariantClass) i;\r
v = Variant30;\r
break;\r
case 31:\r
-#ifdef FAIRY\r
- v = VariantShogi;\r
-#else\r
v = Variant31;\r
-#endif\r
break;\r
case 32:\r
-#ifdef FAIRY\r
- v = VariantXiangqi;\r
-#else\r
v = Variant32;\r
-#endif\r
break;\r
case 33:\r
-#ifdef FAIRY\r
- v = VariantCourier;\r
-#else\r
v = Variant33;\r
-#endif\r
break;\r
case 34:\r
-#ifdef FAIRY\r
- v = VariantGothic;\r
-#else\r
v = Variant34;\r
-#endif\r
break;\r
case 35:\r
-#ifdef FAIRY\r
- v = VariantCapablanca;\r
-#else\r
v = Variant35;\r
-#endif\r
break;\r
case 36:\r
-#ifdef FAIRY\r
- v = VariantFairy;\r
-#else\r
v = Variant36;\r
-#endif\r
+ break;\r
+ case 37:\r
+ v = VariantShogi;\r
+ break;\r
+ case 38:\r
+ v = VariantXiangqi;\r
+ break;\r
+ case 39:\r
+ v = VariantCourier;\r
+ break;\r
+ case 40:\r
+ v = VariantGothic;\r
+ break;\r
+ case 41:\r
+ v = VariantCapablanca;\r
+ break;\r
+ case 42:\r
+ v = VariantKnightmate;\r
+ break;\r
+ case 43:\r
+ v = VariantFairy;\r
+ break;\r
+ case 44:\r
+ v = VariantShowgi;\r
break;\r
\r
case -1:\r
TelnetRequest(TN_DONT, TN_ECHO);\r
}\r
\r
+void\r
+CopyHoldings(Board board, char *holdings, ChessSquare lowestPiece)\r
+{\r
+ /* put the holdings sent to us by the server on the board holdings area */\r
+ int i, j, holdingsColumn, holdingsStartRow, direction, countsColumn;\r
+ char p;\r
+ ChessSquare piece;\r
+\r
+ if(gameInfo.holdingsWidth < 1) return;\r
+\r
+ if( (int)lowestPiece >= BlackPawn ) {\r
+ holdingsColumn = 0;\r
+ countsColumn = 1;\r
+ holdingsStartRow = BOARD_HEIGHT-1;\r
+ direction = 1;\r
+ } else {\r
+ holdingsColumn = BOARD_WIDTH-1;\r
+ countsColumn = BOARD_WIDTH-2;\r
+ holdingsStartRow = 0;\r
+ direction = 1;\r
+ }\r
+\r
+ for(i=0; i<BOARD_HEIGHT; i++) { /* clear holdings */\r
+ board[i][holdingsColumn] = EmptySquare;\r
+ board[i][countsColumn] = (ChessSquare) 0;\r
+ }\r
+ while( (p=*holdings++) != NULLCHAR ) {\r
+ piece = CharToPiece( ToUpper(p) );\r
+ if(piece == EmptySquare) continue;\r
+ j = (int) piece - (int) WhitePawn;\r
+ if(j >= gameInfo.holdingsSize) continue; /* ignore pieces that do not fit */\r
+ if(j < 0) continue; /* should not happen */\r
+ piece = (ChessSquare) ( (int)piece + (int)lowestPiece );\r
+ board[holdingsStartRow+i*direction][holdingsColumn] = piece;\r
+ board[holdingsStartRow+i*direction][countsColumn]++;\r
+ }\r
+\r
+}\r
+\r
static int loggedOn = FALSE;\r
\r
/*-- Game start info cache: --*/\r
ClearPremoveHighlights();\r
if (appData.debugMode)\r
fprintf(debugFP, "Sending premove:\n");\r
- UserMoveEvent(premoveFromX, premoveFromY, \r
+ UserMoveEvent(premoveFromX, premoveFromY, \r
premoveToX, premoveToY, \r
- premovePromoChar);\r
+ premovePromoChar);\r
}\r
}\r
\r
gameInfo.white, white_holding,\r
gameInfo.black, black_holding);\r
}\r
+\r
+ /* [HGM] copy holdings to board holdings area */\r
+ CopyHoldings(boards[currentMove], white_holding, WhitePawn);\r
+ CopyHoldings(boards[currentMove], black_holding, BlackPawn);\r
DrawPosition(FALSE, NULL);\r
DisplayTitle(str);\r
}\r
movesPerSession = 0;\r
gameInfo.timeControl = TimeControlTagValue();\r
gameInfo.variant = StringToVariant(gameInfo.event);\r
+ gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */\r
+ switch(gameInfo.variant) {\r
+ case VariantShogi:\r
+ case VariantShowgi:\r
+ gameInfo.boardWidth = gameInfo.boardHeight = 9;\r
+ gameInfo.holdingsSize += 2;\r
+ case VariantBughouse:\r
+ case VariantCrazyhouse:\r
+ gameInfo.boardWidth = gameInfo.boardHeight = 8;\r
+ gameInfo.holdingsWidth = 2; break;\r
+ default:\r
+ gameInfo.boardWidth = gameInfo.boardHeight = 8;\r
+ gameInfo.holdingsWidth = 0;\r
+ }\r
gameInfo.outOfBook = NULL;\r
\r
/* Do we have the ratings? */\r
* the engine. It would be nice to have a better way to identify castle \r
* moves here. */\r
if(gameInfo.variant == VariantFischeRandom && cps->useOOCastle) {\r
- int fromX = moveList[moveNum][0] - 'a'; \r
+ int fromX = moveList[moveNum][0] - AAA; \r
int fromY = moveList[moveNum][1] - ONE;\r
- int toX = moveList[moveNum][2] - 'a'; \r
+ int toX = moveList[moveNum][2] - AAA; \r
int toY = moveList[moveNum][3] - ONE;\r
if((boards[currentMove][fromY][fromX] == WhiteKing \r
&& boards[currentMove][toY][toX] == WhiteRook)\r
case BlackPromotionArchbishop:\r
#endif\r
sprintf(user_move, "%c%c%c%c=%c\n",\r
- 'a' + fromX, ONE + fromY, 'a' + toX, ONE + toY,\r
+ AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,\r
PieceToChar(PromoPiece(moveType)));\r
break;\r
case WhiteDrop:\r
case BlackDrop:\r
sprintf(user_move, "%c@%c%c\n",\r
ToUpper(PieceToChar((ChessSquare) fromX)),\r
- 'a' + toX, ONE + toY);\r
+ AAA + toX, ONE + toY);\r
break;\r
case NormalMove:\r
case WhiteCapturesEnPassant:\r
case BlackCapturesEnPassant:\r
case IllegalMove: /* could be a variant we don't quite understand */\r
sprintf(user_move, "%c%c%c%c\n",\r
- 'a' + fromX, ONE + fromY, 'a' + toX, ONE + toY);\r
+ AAA + fromX, ONE + fromY, AAA + toX, ONE + toY);\r
break;\r
}\r
SendToICS(user_move);\r
{\r
if (rf == DROP_RANK) {\r
sprintf(move, "%c@%c%c\n",\r
- ToUpper(PieceToChar((ChessSquare) ff)), 'a' + ft, ONE + rt);\r
+ ToUpper(PieceToChar((ChessSquare) ff)), AAA + ft, ONE + rt);\r
} else {\r
if (promoChar == 'x' || promoChar == NULLCHAR) {\r
sprintf(move, "%c%c%c%c\n",\r
- 'a' + ff, ONE + rf, 'a' + ft, ONE + rt);\r
+ AAA + ff, ONE + rf, AAA + ft, ONE + rt);\r
} else {\r
sprintf(move, "%c%c%c%c%c\n",\r
- 'a' + ff, ONE + rf, 'a' + ft, ONE + rt, promoChar);\r
+ AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar);\r
}\r
}\r
+ AlphaRank(move, 4);\r
}\r
\r
void\r
}\r
\r
\r
+/* [HGM] Shogi move preprocessor: swap digits for letters, vice versa */\r
+void\r
+AlphaRank(char *move, int n)\r
+{\r
+ char *p = move, c;\r
+\r
+ if( !appData.alphaRank ) return;\r
+\r
+ while(c = *p) {\r
+ if(c>='0' && c<='9') *p += 'a'-'0'; else\r
+ if(c>='a' && c<='z') *p -= 'a'-'0';\r
+ p++;\r
+ if(--n < 1) break;\r
+ }\r
+}\r
+\r
/* Parser for moves from gnuchess, ICS, or user typein box */\r
Boolean\r
ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)\r
int *fromX, *fromY, *toX, *toY;\r
char *promoChar;\r
{ \r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "move to parse: %s\n", move);\r
+ }\r
+ AlphaRank(move, 10);\r
*moveType = yylexstr(moveNum, move);\r
\r
switch (*moveType) {\r
case BlackASideCastleFR:\r
/* End of code added by Tord */\r
case IllegalMove: /* bug or odd chess variant */\r
- *fromX = currentMoveString[0] - 'a';\r
+ *fromX = currentMoveString[0] - AAA;\r
*fromY = currentMoveString[1] - ONE;\r
- *toX = currentMoveString[2] - 'a';\r
+ *toX = currentMoveString[2] - AAA;\r
*toY = currentMoveString[3] - ONE;\r
*promoChar = currentMoveString[4];\r
- if (*fromX < 0 || *fromX >= BOARD_WIDTH || *fromY < 0 || *fromY >= BOARD_HEIGHT ||\r
- *toX < 0 || *toX >= BOARD_WIDTH || *toY < 0 || *toY >= BOARD_HEIGHT) {\r
+ if (*fromX < BOARD_LEFT || *fromX >= BOARD_RGHT || *fromY < 0 || *fromY >= BOARD_HEIGHT ||\r
+ *toX < BOARD_LEFT || *toX >= BOARD_RGHT || *toY < 0 || *toY >= BOARD_HEIGHT) {\r
*fromX = *fromY = *toX = *toY = 0;\r
return FALSE;\r
}\r
(int) CharToPiece(ToUpper(currentMoveString[0])) :\r
(int) CharToPiece(ToLower(currentMoveString[0]));\r
*fromY = DROP_RANK;\r
- *toX = currentMoveString[2] - 'a';\r
+ *toX = currentMoveString[2] - AAA;\r
*toY = currentMoveString[3] - ONE;\r
*promoChar = NULLCHAR;\r
return TRUE;\r
board[0][FindEmptySquare(board, 0)] = WhiteKing;\r
board[0][FindEmptySquare(board, 0)] = WhiteRook;\r
\r
- for( i=0; i<BOARD_WIDTH; i++ ) {\r
+ for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
}\r
}\r
board[0][ FindEmptySquare(board, 0) ] = WhiteRook;\r
\r
/* Mirror piece placement for black */\r
- for( i=0; i<BOARD_WIDTH; i++ ) {\r
+ for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
}\r
}\r
int redraw;\r
{\r
ChessSquare (* pieces)[BOARD_SIZE];\r
- int i, j;\r
+ int i, j, pawnRow, overrule,\r
+ oldx = gameInfo.boardWidth,\r
+ oldy = gameInfo.boardHeight,\r
+ oldh = gameInfo.holdingsWidth;\r
\r
currentMove = forwardMostMove = backwardMostMove = 0;\r
\r
/* [HGM] Build normal castling rights */\r
for( j=0; j<BOARD_SIZE; j++ ) initialRights[j] = -1;\r
nrCastlingRights = 6;\r
- castlingRights[0][0] = initialRights[0] = BOARD_WIDTH-1;\r
- castlingRights[0][1] = initialRights[1] = 0;\r
+ castlingRights[0][0] = initialRights[0] = BOARD_RGHT-1;\r
+ castlingRights[0][1] = initialRights[1] = BOARD_LEFT;\r
castlingRights[0][2] = initialRights[2] = BOARD_WIDTH>>1;\r
- castlingRights[0][3] = initialRights[3] = BOARD_WIDTH-1;\r
- castlingRights[0][4] = initialRights[4] = 0;\r
+ castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1;\r
+ castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
\r
castlingRank[0] = castlingRank[1] = castlingRank[2] = 0;\r
/* empty squares. This initial position is then copied to boards[0], */\r
/* possibly after shuffling, so that it remains available. */\r
\r
+ gameInfo.holdingsWidth = 0; /* default board sizes */\r
+ gameInfo.boardWidth = 8;\r
+ gameInfo.boardHeight = 8;\r
+ gameInfo.holdingsSize = 0;\r
+\r
switch (gameInfo.variant) {\r
default:\r
- pieces = BOARD_WIDTH <= 8 ? FIDEArray :\r
- BOARD_WIDTH <= 10 ? CapablancaArray : CourierArray;\r
+ pieces = FIDEArray;\r
break;\r
case VariantShatranj:\r
pieces = ShatranjArray;\r
- CharToPiece('E'); /* associate PGN/FEN letter with internal piece type */\r
- CharToPiece('e');\r
nrCastlingRights = 0;\r
for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
break;\r
castlingRank[6] = BOARD_HEIGHT-1;\r
startedFromSetupPosition = TRUE;\r
break;\r
-#ifdef FAIRY\r
case VariantCapablanca:\r
pieces = CapablancaArray;\r
+ gameInfo.boardWidth = 10;\r
break;\r
case VariantGothic:\r
pieces = GothicArray;\r
+ gameInfo.boardWidth = 10;\r
break;\r
case VariantXiangqi:\r
pieces = XiangqiArray;\r
+ gameInfo.boardWidth = 9;\r
+ gameInfo.boardHeight = 10;\r
+ nrCastlingRights = 0;\r
+ for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
+ strcpy(pieceToChar, "PN.R.MKE...C....pn.r.mke...c...."); \r
+ break;\r
+ case VariantShogi:\r
+ pieces = ShogiArray;\r
+ gameInfo.boardWidth = 9;\r
+ gameInfo.boardHeight = 9;\r
+ gameInfo.holdingsSize = 7;\r
+ nrCastlingRights = 0;\r
+ for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
+ strcpy(pieceToChar, "PNBRLSGPNBRLS..Kpnbrlsgpnbrls..k"); \r
+ break;\r
+ case VariantShowgi:\r
+ pieces = ShogiArray;\r
+ gameInfo.boardWidth = 9;\r
+ gameInfo.boardHeight = 9;\r
+ gameInfo.holdingsSize = 7;\r
+ nrCastlingRights = 0;\r
+ for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
+ strcpy(pieceToChar, "PNBRQFWEHACGOUMKpnbrlsgpnbrls..k"); \r
break;\r
case VariantCourier:\r
pieces = CourierArray;\r
+ gameInfo.boardWidth = 12;\r
nrCastlingRights = 0;\r
for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
break;\r
+ case VariantKnightmate:\r
+ pieces = KnightmateArray;\r
+ strcpy(pieceToChar, "PNBRQFWEHACGOMK.pnbrqfwehacgomK."); \r
+ break;\r
case VariantFairy:\r
pieces = fairyArray;\r
+ strcpy(pieceToChar, "PNBRQFWEHACGOMUKpnbrqfwehacgomuk"); \r
startedFromSetupPosition = TRUE;\r
break;\r
-#endif\r
+ case VariantCrazyhouse:\r
+ case VariantBughouse:\r
+ pieces = FIDEArray;\r
+ gameInfo.holdingsSize = 5;\r
+ strcpy(pieceToChar, "PNBRQ...NBRQ...Kpnbrq...nbrq...k"); \r
+ break;\r
case VariantWildCastle:\r
pieces = FIDEArray;\r
/* !!?shuffle with kings guaranteed to be on d or e file */\r
break;\r
}\r
\r
- for( j=0; j<BOARD_WIDTH; j++ ) {\r
+ overrule = 0;\r
+ if(appData.NrFiles >= 0) {\r
+ if(gameInfo.boardWidth != appData.NrFiles) overrule++;\r
+ gameInfo.boardWidth = appData.NrFiles;\r
+ }\r
+ if(appData.NrRanks >= 0) {\r
+ if(gameInfo.boardHeight != appData.NrRanks) overrule++;\r
+ gameInfo.boardHeight = appData.NrRanks;\r
+ }\r
+ if(appData.holdingsSize >= 0) {\r
+ i = appData.holdingsSize;\r
+ if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;\r
+ gameInfo.holdingsSize = i;\r
+ }\r
+ if(gameInfo.holdingsSize) gameInfo.holdingsWidth = 2;\r
+ if(BOARD_HEIGHT > BOARD_SIZE || BOARD_WIDTH > BOARD_SIZE)\r
+ DisplayFatalError("Recompile to support this BOARD_SIZE!", 0, 2);\r
+\r
+ pawnRow = gameInfo.boardHeight - 7; /* seems to work in all variants */\r
+\r
+ /* User pieceToChar list overrules defaults */\r
+ if(appData.pieceToCharTable != NULL)\r
+ strcpy(pieceToChar, appData.pieceToCharTable);\r
+\r
+ for( j=0; j<BOARD_WIDTH; j++ ) { ChessSquare s = EmptySquare;\r
+\r
+ if(j==BOARD_LEFT-1 || j==BOARD_RGHT)\r
+ s = (ChessSquare) 0; /* account holding counts in guard band */\r
for( i=0; i<BOARD_HEIGHT; i++ )\r
- initialPosition[i][j] = EmptySquare;\r
- initialPosition[0][j] = pieces[0][j];\r
+ initialPosition[i][j] = s;\r
+\r
+ if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue;\r
+ initialPosition[0][j] = pieces[0][j-gameInfo.holdingsWidth];\r
+ initialPosition[pawnRow][j] = WhitePawn;\r
+ initialPosition[BOARD_HEIGHT-pawnRow-1][j] = BlackPawn;\r
if(gameInfo.variant == VariantXiangqi) {\r
if(j&1) {\r
- initialPosition[3][j] = \r
- initialPosition[BOARD_HEIGHT-4][j] = EmptySquare;\r
- if(j==1 || j>=BOARD_WIDTH-2) {\r
- initialPosition[2][j] = WhiteFairyMarshall;\r
- initialPosition[BOARD_HEIGHT-3][j] = BlackFairyMarshall;\r
+ initialPosition[pawnRow][j] = \r
+ initialPosition[BOARD_HEIGHT-pawnRow-1][j] = EmptySquare;\r
+ if(j==BOARD_LEFT+1 || j>=BOARD_RGHT-2) {\r
+ initialPosition[2][j] = WhiteCannon;\r
+ initialPosition[BOARD_HEIGHT-3][j] = BlackCannon;\r
}\r
- } else {\r
- initialPosition[3][j] = WhitePawn;\r
- initialPosition[BOARD_HEIGHT-4][j] = BlackPawn;\r
}\r
- } else {\r
- initialPosition[1][j] = WhitePawn;\r
- initialPosition[BOARD_HEIGHT-2][j] = BlackPawn;\r
}\r
- initialPosition[BOARD_HEIGHT-1][j] = pieces[1][j];\r
+ initialPosition[BOARD_HEIGHT-1][j] = pieces[1][j-gameInfo.holdingsWidth];\r
+ }\r
+ if( (gameInfo.variant == VariantShogi\r
+ ||gameInfo.variant == VariantShowgi\r
+ ) && !overrule ) {\r
+ j=BOARD_LEFT+1;\r
+ initialPosition[1][j] = WhiteBishop;\r
+ initialPosition[BOARD_HEIGHT-2][j] = BlackRook;\r
+ j=BOARD_RGHT-2;\r
+ initialPosition[1][j] = WhiteRook;\r
+ initialPosition[BOARD_HEIGHT-2][j] = BlackBishop;\r
}\r
\r
if(gameInfo.variant == VariantFischeRandom) {\r
\r
CopyBoard(boards[0], initialPosition);\r
\r
+ if(oldx != gameInfo.boardWidth ||\r
+ oldy != gameInfo.boardHeight ||\r
+ oldh != gameInfo.holdingsWidth )\r
+ InitDrawingSizes(-1 ,0);\r
+\r
if (redraw)\r
DrawPosition(TRUE, boards[currentMove]);\r
}\r
SendToProgram("#\n", cps);\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
bp = &boards[moveNum][i][0];\r
- for (j = 0; j < BOARD_WIDTH; j++, bp++) {\r
+ for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
if ((int) *bp < (int) BlackPawn) {\r
sprintf(message, "%c%c%c\n", PieceToChar(*bp), \r
- 'a' + j, ONE + i);\r
+ AAA + j, ONE + i);\r
SendToProgram(message, cps);\r
}\r
}\r
SendToProgram("c\n", cps);\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
bp = &boards[moveNum][i][0];\r
- for (j = 0; j < BOARD_WIDTH; j++, bp++) {\r
+ for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
if (((int) *bp != (int) EmptySquare)\r
&& ((int) *bp >= (int) BlackPawn)) {\r
sprintf(message, "%c%c%c\n", ToUpper(PieceToChar(*bp)),\r
- 'a' + j, ONE + i);\r
+ AAA + j, ONE + i);\r
SendToProgram(message, cps);\r
}\r
}\r
IsPromotion(fromX, fromY, toX, toY)\r
int fromX, fromY, toX, toY;\r
{\r
- return gameMode != EditPosition && gameInfo.variant != VariantXiangqi &&\r
- fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0 &&\r
- ((boards[currentMove][fromY][fromX] == WhitePawn && toY == BOARD_HEIGHT-1) ||\r
- (boards[currentMove][fromY][fromX] == BlackPawn && toY == 0));\r
+ /* [HGM] add Shogi promotions */\r
+ int promotionZoneSize=1, highestPromotingPiece = (int)WhitePawn;\r
+ ChessSquare piece;\r
+\r
+ if(gameMode == EditPosition || gameInfo.variant == VariantXiangqi ||\r
+ !(fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0) ) return FALSE;\r
+ /* [HGM] Note to self: line above also weeds out drops */\r
+ piece = boards[currentMove][fromY][fromX];\r
+ if(gameInfo.variant == VariantShogi) {\r
+ promotionZoneSize = 3;\r
+ highestPromotingPiece = (int)WhiteFerz; /* Silver */\r
+ }\r
+ if((int)piece >= BlackPawn) {\r
+ if(toY >= promotionZoneSize && fromY >= promotionZoneSize)\r
+ return FALSE;\r
+ highestPromotingPiece = WHITE_TO_BLACK highestPromotingPiece;\r
+ } else {\r
+ if( toY < BOARD_HEIGHT - promotionZoneSize &&\r
+ fromY < BOARD_HEIGHT - promotionZoneSize) return FALSE;\r
+ }\r
+ return ( (int)piece <= highestPromotingPiece );\r
}\r
\r
+int\r
+InPalace(row, column)\r
+ int row, column;\r
+{ /* [HGM] for Xiangqi */\r
+ if( (row < 3 || row > BOARD_HEIGHT-4) &&\r
+ column < (BOARD_WIDTH + 4)/2 &&\r
+ column > (BOARD_WIDTH - 5)/2 ) return TRUE;\r
+ return FALSE;\r
+}\r
\r
int\r
PieceForSquare (x, y)\r
int x;\r
int y;\r
{\r
- if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)\r
+ if (x < BOARD_LEFT || x >= BOARD_RGHT || y < 0 || y >= BOARD_HEIGHT)\r
return -1;\r
else\r
return boards[currentMove][y][x];\r
ChessMove lastLoadGameStart = (ChessMove) 0;\r
\r
\r
-void\r
-UserMoveEvent(fromX, fromY, toX, toY, promoChar)\r
+ChessMove\r
+UserMoveTest(fromX, fromY, toX, toY, promoChar)\r
int fromX, fromY, toX, toY;\r
int promoChar;\r
{\r
ChessMove moveType;\r
\r
- if (fromX < 0 || fromY < 0) return;\r
+ if (fromX < 0 || fromY < 0) return ImpossibleMove;\r
if ((fromX == toX) && (fromY == toY)) {\r
- return;\r
+ return ImpossibleMove;\r
}\r
+ /* [HGM] suppress all moves into holdings area and guard band */\r
+ if( toX < BOARD_LEFT || toX >= BOARD_RGHT ) return ImpossibleMove;\r
\r
/* Check if the user is playing in turn. This is complicated because we\r
let the user "pick up" a piece before it is his turn. So the piece he\r
case IcsIdle:\r
/* We switched into a game mode where moves are not accepted,\r
perhaps while the mouse button was down. */\r
- return;\r
+ return ImpossibleMove;\r
\r
case MachinePlaysWhite:\r
/* User is moving for Black */\r
if (WhiteOnMove(currentMove)) {\r
DisplayMoveError("It is White's turn");\r
- return;\r
+ return ImpossibleMove;\r
}\r
break;\r
\r
/* User is moving for White */\r
if (!WhiteOnMove(currentMove)) {\r
DisplayMoveError("It is Black's turn");\r
- return;\r
+ return ImpossibleMove;\r
}\r
break;\r
\r
/* User is moving for Black */\r
if (WhiteOnMove(currentMove)) {\r
DisplayMoveError("It is White's turn");\r
- return;\r
+ return ImpossibleMove;\r
}\r
} else {\r
/* User is moving for White */\r
if (!WhiteOnMove(currentMove)) {\r
DisplayMoveError("It is Black's turn");\r
- return;\r
+ return ImpossibleMove;\r
}\r
}\r
break;\r
"fromY %d, toX %d, toY %d\n",\r
fromX, fromY, toX, toY);\r
}\r
- return;\r
+ return ImpossibleMove;\r
}\r
break;\r
\r
"fromY %d, toX %d, toY %d\n",\r
fromX, fromY, toX, toY);\r
}\r
- return;\r
+ return ImpossibleMove;\r
}\r
break;\r
\r
boards[0][fromY][fromX] = EmptySquare;\r
DrawPosition(FALSE, boards[currentMove]);\r
}\r
- return;\r
+ return ImpossibleMove;\r
+ }\r
+\r
+ if (toX < 0 || toY < 0) return ImpossibleMove;\r
+\r
+ /* [HGM] If move started in holdings, it means a drop */\r
+ if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) {\r
+ if( boards[currentMove][toY][toX] != EmptySquare ) return ImpossibleMove;\r
+ return WhiteDrop; /* Not needed to specify white or black yet */\r
}\r
\r
- if (toX < 0 || toY < 0) return;\r
userOfferedDraw = FALSE;\r
\r
if (appData.testLegality) {\r
fromY, fromX, toY, toX, promoChar);\r
if (moveType == IllegalMove || moveType == ImpossibleMove) {\r
DisplayMoveError("Illegal move");\r
- return;\r
+ return ImpossibleMove;\r
}\r
} else {\r
moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);\r
}\r
\r
+ return moveType;\r
+ /* [HGM] <popupFix> in stead of calling FinishMove directly, this\r
+ function is made into one that returns an OK move type if FinishMove\r
+ should be called. This to give the calling driver routine the\r
+ opportunity to finish the userMove input with a promotion popup,\r
+ without bothering the user with this for invalid or illegal moves */\r
+\r
+/* FinishMove(moveType, fromX, fromY, toX, toY, promoChar); */\r
+}\r
+\r
+/* Common tail of UserMoveEvent and DropMenuEvent */\r
+void\r
+FinishMove(moveType, fromX, fromY, toX, toY, promoChar)\r
+ ChessMove moveType;\r
+ int fromX, fromY, toX, toY;\r
+ /*char*/int promoChar;\r
+{\r
+ /* [HGM] <popupFix> kludge to avoid having know the exact promotion\r
+ move type in caller when we know the move is a legal promotion */\r
+ if(moveType == NormalMove)\r
+ moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);\r
+\r
+ /* [HGM] convert drag-and-drop piece drops to standard form */\r
+ if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) {\r
+ moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop;\r
+ fromX = boards[currentMove][fromY][fromX];\r
+ fromY = DROP_RANK;\r
+ }\r
+\r
+ /* [HGM] <popupFix> The following if has been moved here from\r
+ UserMoveEnevt(). Because it seemed to belon here (why not allow\r
+ piece drops in training games?), and because it can only be\r
+ performed after it is known to what we promote. */\r
if (gameMode == Training) {\r
/* compare the move played on the board to the next move in the\r
* game. If they match, display the move and the opponent's response. \r
return;\r
}\r
\r
- FinishMove(moveType, fromX, fromY, toX, toY, promoChar);\r
-}\r
-\r
-/* Common tail of UserMoveEvent and DropMenuEvent */\r
-void\r
-FinishMove(moveType, fromX, fromY, toX, toY, promoChar)\r
- ChessMove moveType;\r
- int fromX, fromY, toX, toY;\r
- /*char*/int promoChar;\r
-{\r
/* Ok, now we know that the move is good, so we can kill\r
the previous line in Analysis Mode */\r
if (gameMode == AnalyzeMode && currentMove < forwardMostMove) {\r
}\r
}\r
\r
+void\r
+UserMoveEvent(fromX, fromY, toX, toY, promoChar)\r
+ int fromX, fromY, toX, toY;\r
+ int promoChar;\r
+{\r
+ /* [HGM] This routine was added to allow calling of its two logical\r
+ parts from other modules in the old way. Before, UserMoveEvent()\r
+ automatically called FinishMove() if the move was OK, and returned\r
+ otherwise. I separated the two, in order to make it possible to\r
+ slip a promotion popup in between. But that it always needs two\r
+ calls, to the first part, (now called UserMoveTest() ), and to\r
+ FinishMove if the first part succeeded. Calls that do not need\r
+ to do anything in between, can call this routine the old way. \r
+ */\r
+ ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar);\r
+\r
+ if(moveType != ImpossibleMove)\r
+ FinishMove(moveType, fromX, fromY, toX, toY, promoChar);\r
+}\r
+\r
void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )\r
{\r
char * hint = lastHint;\r
return;\r
}\r
\r
- if (!ParseOneMove(machineMove, forwardMostMove, &moveType,\r
- &fromX, &fromY, &toX, &toY, &promoChar)) {\r
+ if (!ParseOneMove(machineMove, forwardMostMove, &moveType,\r
+ &fromX, &fromY, &toX, &toY, &promoChar)) {\r
/* Machine move could not be parsed; ignore it. */\r
sprintf(buf1, "Illegal move \"%s\" from %s machine",\r
machineMove, cps->which);\r
DisplayError(buf1, 0);\r
+ sprintf(buf1, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d%c",\r
+ machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
if (gameMode == TwoMachinesPlay) {\r
GameEnds(machineWhite ? BlackWins : WhiteWins,\r
- "Forfeit due to illegal move", GE_XBOARD);\r
+ buf1, GE_XBOARD);\r
}\r
return;\r
}\r
/* to cause a forfeit on a justified illegal-move complaint */\r
/* of the opponent. */\r
if(gameMode==TwoMachinesPlay && appData.testLegality &&\r
+ fromY != DROP_RANK && /* [HGM] temporary; should still add legality test for drops */\r
LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),\r
epStatus[forwardMostMove], castlingRights[forwardMostMove],\r
fromY, fromX, toY, toX, promoChar) == IllegalMove)\r
- { static char buf[MSG_SIZ];\r
+ {\r
if (appData.debugMode) {\r
int i;\r
for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",\r
castlingRights[forwardMostMove][i], castlingRank[i]);\r
fprintf(debugFP, "castling rights\n");\r
}\r
- sprintf(buf, "Xboard: Forfeit due to illegal move %s (%c%c%c%c)%c",\r
- machineMove, fromX+'a', fromY+ONE, toX+'a', toY+ONE, 0);\r
- GameEnds(machineWhite ? BlackWins : WhiteWins, buf, GE_XBOARD);\r
+ sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",\r
+ machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
+ GameEnds(machineWhite ? BlackWins : WhiteWins,\r
+ buf1, GE_XBOARD);\r
}\r
hintRequested = FALSE;\r
lastHint[0] = NULLCHAR;\r
\r
#ifdef ADJUDICATE // [HGM] some adjudications useful with buggy engines\r
\r
- if( gameMode == TwoMachinesPlay ) {\r
+ if( gameMode == TwoMachinesPlay && gameInfo.holdingsSize == 0) {\r
int count = 0, epFile = epStatus[forwardMostMove];\r
\r
- if(appData.testLegality) // don't wait for engine to announce game end if we can judge ourselves\r
+ if(appData.testLegality && appData.checkMates) \r
+ // don't wait for engine to announce game end if we can judge ourselves\r
switch (MateTest(boards[forwardMostMove],\r
PosFlags(forwardMostMove), epFile,\r
castlingRights[forwardMostMove]) ) {\r
static int moveCount;\r
\r
/* First absolutely insufficient mating material. Count what is on board. */\r
- for(i=0; i<BOARD_HEIGHT; i++) for(j=0; j<BOARD_WIDTH; j++)\r
+ for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
{ ChessSquare p = boards[forwardMostMove][i][j];\r
int m=i;\r
\r
/* always flag draws, for judging claims */\r
epStatus[forwardMostMove] = EP_INSUF_DRAW;\r
\r
- if(adjudicateLossThreshold != 0) {\r
+ if(appData.materialDraws) {\r
/* but only adjudicate them if adjudication enabled */\r
ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD );\r
|| NrWN==2 || NrBN==2 /* KNNK */\r
|| NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */\r
) ) {\r
- if(--moveCount < 0 && adjudicateLossThreshold != 0)\r
+ if(--moveCount < 0 && appData.trivialDraws)\r
{ /* if the first 3 moves do not show a tactical win, declare draw */\r
ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD );\r
fprintf(debugFP, " %d %d\n", rights, k);\r
}\r
if( rights == 0 && ++count > appData.drawRepeats-2\r
- && adjudicateLossThreshold != 0) {\r
+ && appData.drawRepeats > 1) {\r
/* adjudicate after user-specified nr of repeats */\r
ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );\r
if( count >= 100)\r
epStatus[forwardMostMove] = EP_RULE_DRAW;\r
/* this is used to judge if draw claims are legal */\r
- if(adjudicateLossThreshold != 0 && count >= 2*appData.ruleMoves) {\r
+ if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {\r
ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD );\r
return;\r
/* [HGM] illegal-move claim should forfeit game when Xboard */\r
/* only passes fully legal moves */\r
if( appData.testLegality && gameMode == TwoMachinesPlay ) {\r
- static char buf[MSG_SIZ];\r
- sprintf(buf, "False illegal-move claim on %s (%c%c%c%c)%c",\r
- machineMove, fromX+'a', fromY+ONE, toX+'a', toY+ONE, 0);\r
GameEnds( cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins,\r
- buf, GE_XBOARD );\r
+ "False illegal-move claim", GE_XBOARD );\r
}\r
return;\r
}\r
case BlackASideCastleFR:\r
/* POP Fabien */\r
case IllegalMove: /* maybe suicide chess, etc. */\r
- fromX = currentMoveString[0] - 'a';\r
+ fromX = currentMoveString[0] - AAA;\r
fromY = currentMoveString[1] - ONE;\r
- toX = currentMoveString[2] - 'a';\r
+ toX = currentMoveString[2] - AAA;\r
toY = currentMoveString[3] - ONE;\r
promoChar = currentMoveString[4];\r
break;\r
(int) CharToPiece(ToUpper(currentMoveString[0])) :\r
(int) CharToPiece(ToLower(currentMoveString[0]));\r
fromY = DROP_RANK;\r
- toX = currentMoveString[2] - 'a';\r
+ toX = currentMoveString[2] - AAA;\r
toY = currentMoveString[3] - ONE;\r
promoChar = NULLCHAR;\r
break;\r
int promoChar;\r
Board board;\r
{\r
+ ChessSquare captured = board[toY][toX], piece; int p;\r
+\r
/* [HGM] In Shatranj and Courier all promotions are to Ferz */\r
if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier)\r
- && promoChar != 0) promoChar = 'f';\r
+ && promoChar != 0) promoChar = 'F';\r
\r
- ChessSquare captured = board[toY][toX];\r
if (fromY == DROP_RANK) {\r
/* must be first */\r
board[toY][toX] = (ChessSquare) fromX;\r
return;\r
}\r
\r
+ piece = board[fromY][fromX];\r
+ \r
/* Code added by Tord: */\r
/* FRC castling assumed when king captures friendly rook. */\r
else if (board[fromY][fromX] == WhiteKing &&\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = EmptySquare;\r
if(toX > fromX) {\r
- board[0][BOARD_WIDTH-2] = WhiteKing; board[0][BOARD_WIDTH-3] = WhiteRook;\r
+ board[0][BOARD_RGHT-2] = WhiteKing; board[0][BOARD_RGHT-3] = WhiteRook;\r
} else {\r
- board[0][2] = WhiteKing; board[0][3] = WhiteRook;\r
+ board[0][BOARD_LEFT+2] = WhiteKing; board[0][BOARD_LEFT+3] = WhiteRook;\r
}\r
} else if (board[fromY][fromX] == BlackKing &&\r
board[toY][toX] == BlackRook) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = EmptySquare;\r
if(toX > fromX) {\r
- board[BOARD_HEIGHT-1][BOARD_WIDTH-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_WIDTH-3] = BlackRook;\r
+ board[BOARD_HEIGHT-1][BOARD_RGHT-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_RGHT-3] = BlackRook;\r
} else {\r
- board[BOARD_HEIGHT-1][2] = BlackKing; board[BOARD_HEIGHT-1][3] = BlackRook;\r
+ board[BOARD_HEIGHT-1][BOARD_LEFT+2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_LEFT+3] = BlackRook;\r
}\r
/* End of code added by Tord */\r
\r
&& toY == fromY && toX > fromX+1) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = WhiteKing;\r
- board[fromY][BOARD_WIDTH-1] = EmptySquare;\r
+ board[fromY][BOARD_RGHT-1] = EmptySquare;\r
board[toY][toX-1] = WhiteRook;\r
} else if (initialPosition[fromY][fromX] == WhiteKing\r
&& board[fromY][fromX] == WhiteKing\r
&& toY == fromY && toX < fromX-1) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = WhiteKing;\r
- board[fromY][0] = EmptySquare;\r
+ board[fromY][BOARD_LEFT] = EmptySquare;\r
board[toY][toX+1] = WhiteRook;\r
} else if (fromY == 0 && fromX == 3\r
&& board[fromY][fromX] == WhiteKing\r
if (board[toY][toX] == EmptySquare) {\r
board[toY][toX] = WhiteQueen;\r
}\r
+ if(gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */\r
+ board[toY][toX] += (int) WhiteAlfil - (int) WhitePawn;\r
board[fromY][fromX] = EmptySquare;\r
} else if ((fromY == BOARD_HEIGHT-4)\r
&& (toX != fromX)\r
&& toY == fromY && toX > fromX+1) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = BlackKing;\r
- board[fromY][BOARD_WIDTH-1] = EmptySquare;\r
+ board[fromY][BOARD_RGHT-1] = EmptySquare;\r
board[toY][toX-1] = BlackRook;\r
} else if (initialPosition[fromY][fromX] == BlackKing\r
&& board[fromY][fromX] == BlackKing\r
&& toY == fromY && toX < fromX-1) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = BlackKing;\r
- board[fromY][0] = EmptySquare;\r
+ board[fromY][BOARD_LEFT] = EmptySquare;\r
board[toY][toX+1] = BlackRook;\r
} else if (fromY == 7 && fromX == 3\r
&& board[fromY][fromX] == BlackKing\r
if (board[0][toX] == EmptySquare) {\r
board[0][toX] = BlackQueen;\r
}\r
+ if(gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */\r
+ board[toY][toX] += (int) WhiteAlfil - (int) WhitePawn;\r
board[fromY][fromX] = EmptySquare;\r
} else if ((fromY == 3)\r
&& (toX != fromX)\r
board[toY][toX] = board[fromY][fromX];\r
board[fromY][fromX] = EmptySquare;\r
}\r
- if (gameInfo.variant == VariantCrazyhouse) {\r
-#if 0\r
- /* !!A lot more code needs to be written to support holdings */\r
+ if (gameInfo.holdingsWidth != 0) {\r
+\r
+ /* !!A lot more code needs to be written to support holdings */\r
+ /* [HGM] OK, so I have written it. Holdings are stored in the */\r
+ /* penultimate board files, so they are automaticlly stored */\r
+ /* in the game history. */\r
if (fromY == DROP_RANK) {\r
- /* Delete from holdings */\r
- if (holdings[(int) fromX] > 0) holdings[(int) fromX]--;\r
+ /* Delete from holdings, by decreasing count */\r
+ /* and erasing image if necessary */\r
+ p = (int) fromX;\r
+ if(p < (int) BlackPawn) { /* white drop */\r
+ p -= (int)WhitePawn;\r
+ if(p >= gameInfo.holdingsSize) p = 0;\r
+ if(--board[p][BOARD_WIDTH-2] == 0)\r
+ board[p][BOARD_WIDTH-1] = EmptySquare;\r
+ } else { /* black drop */\r
+ p -= (int)BlackPawn;\r
+ if(p >= gameInfo.holdingsSize) p = 0;\r
+ if(--board[BOARD_HEIGHT-1-p][1] == 0)\r
+ board[BOARD_HEIGHT-1-p][0] = EmptySquare;\r
+ }\r
}\r
- if (captured != EmptySquare) {\r
- /* Add to holdings */\r
- if (captured < BlackPawn) {\r
- holdings[(int)captured - (int)BlackPawn + (int)WhitePawn]++;\r
+ if (captured != EmptySquare && gameInfo.holdingsSize > 0\r
+ && gameInfo.variant != VariantBughouse ) {\r
+ /* Add to holdings, if holdings exist */\r
+ p = (int) captured;\r
+ if (p >= (int) BlackPawn) {\r
+ p -= (int)BlackPawn;\r
+ if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) {\r
+ /* in Shogi restore piece to its original first */\r
+ captured = (ChessSquare) (DEMOTED captured);\r
+ p = DEMOTED p;\r
+ }\r
+ if(p >= gameInfo.holdingsSize) { p = 0; captured = BlackPawn; }\r
+ board[p][BOARD_WIDTH-2]++;\r
+ board[p][BOARD_WIDTH-1] =\r
+ BLACK_TO_WHITE captured;\r
} else {\r
- holdings[(int)captured - (int)WhitePawn + (int)BlackPawn]++;\r
+ p -= (int)WhitePawn;\r
+ if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) {\r
+ captured = (ChessSquare) (DEMOTED captured);\r
+ p = DEMOTED p;\r
+ }\r
+ if(p >= gameInfo.holdingsSize) { p = 0; captured = WhitePawn; }\r
+ board[BOARD_HEIGHT-1-p][1]++;\r
+ board[BOARD_HEIGHT-1-p][0] =\r
+ WHITE_TO_BLACK captured;\r
}\r
}\r
-#endif\r
+\r
} else if (gameInfo.variant == VariantAtomic) {\r
if (captured != EmptySquare) {\r
int y, x;\r
for (y = toY-1; y <= toY+1; y++) {\r
for (x = toX-1; x <= toX+1; x++) {\r
- if (y >= 0 && y < BOARD_WIDTH && x >= 0 && x < BOARD_WIDTH &&\r
+ if (y >= 0 && y < BOARD_HEIGHT && x >= BOARD_LEFT && x < BOARD_RGHT &&\r
board[y][x] != WhitePawn && board[y][x] != BlackPawn) {\r
board[y][x] = EmptySquare;\r
}\r
board[toY][toX] = EmptySquare;\r
}\r
}\r
+ if(gameInfo.variant == VariantShogi && promoChar != NULLCHAR) {\r
+ /* [HGM] Shogi promotions */\r
+ board[toY][toX] = (ChessSquare) (PROMOTED piece);\r
+ }\r
+\r
}\r
\r
/* Updates forwardMostMove */\r
if( boards[forwardMostMove][fromY][fromX] == WhitePawn ) {\r
epStatus[forwardMostMove] = EP_PAWN_MOVE; \r
if( toY-fromY==2 &&\r
- (toX>1 && boards[forwardMostMove][toY][toX-1] == BlackPawn ||\r
- toX<BOARD_WIDTH-1 && boards[forwardMostMove][toY][toX+1] == BlackPawn ) )\r
+ (toX>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == BlackPawn ||\r
+ toX<BOARD_RGHT-1 && boards[forwardMostMove][toY][toX+1] == BlackPawn ) )\r
epStatus[forwardMostMove] = toX;\r
} else \r
if( boards[forwardMostMove][fromY][fromX] == BlackPawn ) {\r
epStatus[forwardMostMove] = EP_PAWN_MOVE; \r
if( toY-fromY== -2 &&\r
- (toX>1 && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
- toX<BOARD_WIDTH-1 && boards[forwardMostMove][toY][toX+1] == WhitePawn ) )\r
+ (toX>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
+ toX<BOARD_RGHT-1 && boards[forwardMostMove][toY][toX+1] == WhitePawn ) )\r
epStatus[forwardMostMove] = toX;\r
}\r
\r
InitChessProgram(cps)\r
ChessProgramState *cps;\r
{\r
- char buf[MSG_SIZ];\r
+ char buf[MSG_SIZ], *b; int overruled;\r
if (appData.noChessProgram) return;\r
hintRequested = FALSE;\r
bookRequested = FALSE;\r
SendToProgram(cps->initString, cps);\r
if (gameInfo.variant != VariantNormal &&\r
- gameInfo.variant != VariantLoadable) {\r
+ gameInfo.variant != VariantLoadable\r
+ /* [HGM] also send variant if board size non-standard */\r
+ || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8\r
+ ) {\r
char *v = VariantName(gameInfo.variant);\r
if (StrStr(cps->variants, v) == NULL) {\r
sprintf(buf, "Variant %s not supported by %s", v, cps->tidy);\r
DisplayFatalError(buf, 0, 1);\r
return;\r
}\r
- sprintf(buf, "variant %s\n", VariantName(gameInfo.variant));\r
+ b = buf;\r
+ /* [HGM] make prefix for non-standard board size. Awkward testing... */\r
+ overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;\r
+ if( gameInfo.variant == VariantXiangqi )\r
+ overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 0;\r
+ if( gameInfo.variant == VariantShogi )\r
+ overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 9 || gameInfo.holdingsSize != 7;\r
+ if( gameInfo.variant == VariantBughouse || gameInfo.variant == VariantCrazyhouse )\r
+ overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 5;\r
+ if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantGothic )\r
+ overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;\r
+ if( gameInfo.variant == VariantCourier )\r
+ overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;\r
+\r
+ if(overruled) {\r
+#if 0\r
+ // doesn't work in protocol 1\r
+ if (StrStr(cps->variants, "boardsize") == NULL,) {\r
+ sprintf(buf, "Board size %dx%d+%d not supported by %s",\r
+ gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize, cps->tidy);\r
+ DisplayFatalError(buf, 0, 1);\r
+ return;\r
+ }\r
+#endif\r
+ sprintf(buf, "%dx%d+%d_", gameInfo.boardWidth,\r
+ gameInfo.boardHeight, gameInfo.holdingsSize );\r
+ while(*b++ != '_');\r
+ }\r
+ sprintf(b, "variant %s\n", VariantName(gameInfo.variant));\r
SendToProgram(buf, cps);\r
}\r
if (cps->sendICS) {\r
return FALSE;\r
}\r
\r
- toX = moveList[currentMove][2] - 'a';\r
+ toX = moveList[currentMove][2] - AAA;\r
toY = moveList[currentMove][3] - ONE;\r
\r
if (moveList[currentMove][1] == '@') {\r
SetHighlights(-1, -1, toX, toY);\r
}\r
} else {\r
- fromX = moveList[currentMove][0] - 'a';\r
+ fromX = moveList[currentMove][0] - AAA;\r
fromY = moveList[currentMove][1] - ONE;\r
\r
HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove); /* [AS] */\r
/* POP Fabien */\r
if (appData.debugMode)\r
fprintf(debugFP, "Parsed %s into %s\n", yy_text, currentMoveString);\r
- fromX = currentMoveString[0] - 'a';\r
+ fromX = currentMoveString[0] - AAA;\r
fromY = currentMoveString[1] - ONE;\r
- toX = currentMoveString[2] - 'a';\r
+ toX = currentMoveString[2] - AAA;\r
toY = currentMoveString[3] - ONE;\r
promoChar = currentMoveString[4];\r
break;\r
(int) CharToPiece(ToUpper(currentMoveString[0])) :\r
(int) CharToPiece(ToLower(currentMoveString[0]));\r
fromY = DROP_RANK;\r
- toX = currentMoveString[2] - 'a';\r
+ toX = currentMoveString[2] - AAA;\r
toY = currentMoveString[3] - ONE;\r
break;\r
\r
if (appData.debugMode)\r
fprintf(debugFP, "Parsed %s into IllegalMove %s\n",\r
yy_text, currentMoveString);\r
- fromX = currentMoveString[0] - 'a';\r
+ fromX = currentMoveString[0] - AAA;\r
fromY = currentMoveString[1] - ONE;\r
- toX = currentMoveString[2] - 'a';\r
+ toX = currentMoveString[2] - AAA;\r
toY = currentMoveString[3] - ONE;\r
promoChar = currentMoveString[4];\r
}\r
\r
thinkOutput[0] = NULLCHAR;\r
strcpy(moveList[currentMove], cmailMove[lastLoadGameNumber - 1]);\r
- fromX = cmailMove[lastLoadGameNumber - 1][0] - 'a';\r
+ fromX = cmailMove[lastLoadGameNumber - 1][0] - AAA;\r
fromY = cmailMove[lastLoadGameNumber - 1][1] - ONE;\r
- toX = cmailMove[lastLoadGameNumber - 1][2] - 'a';\r
+ toX = cmailMove[lastLoadGameNumber - 1][2] - AAA;\r
toY = cmailMove[lastLoadGameNumber - 1][3] - ONE;\r
promoChar = cmailMove[lastLoadGameNumber - 1][4];\r
MakeMove(fromX, fromY, toX, toY, promoChar);\r
if (!startedFromSetupPosition) {\r
p = yy_text;\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--)\r
- for (j = 0; j < BOARD_WIDTH; p++)\r
+ for (j = BOARD_LEFT; j < BOARD_RGHT; p++)\r
switch (*p) {\r
case '[':\r
case '-':\r
\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
(void) fgets(line, MSG_SIZ, f);\r
- for (p = line, j = 0; j < BOARD_WIDTH; p++) {\r
+ for (p = line, j = BOARD_LEFT; j < BOARD_RGHT; p++) {\r
if (*p == ' ')\r
continue;\r
initial_position[i][j++] = CharToPiece(*p);\r
if (gameMode == IcsExamining) {\r
if (boards[currentMove][y][x] != EmptySquare) {\r
sprintf(buf, "%sx@%c%c\n", ics_prefix,\r
- 'a' + x, ONE + y);\r
+ AAA + x, ONE + y);\r
SendToICS(buf);\r
}\r
} else {\r
\r
case EmptySquare:\r
if (gameMode == IcsExamining) {\r
- sprintf(buf, "%sx@%c%c\n", ics_prefix, 'a' + x, ONE + y);\r
+ sprintf(buf, "%sx@%c%c\n", ics_prefix, AAA + x, ONE + y);\r
SendToICS(buf);\r
} else {\r
boards[0][y][x] = EmptySquare;\r
default:\r
if (gameMode == IcsExamining) {\r
sprintf(buf, "%s%c@%c%c\n", ics_prefix,\r
- PieceToChar(selection), 'a' + x, ONE + y);\r
+ PieceToChar(selection), AAA + x, ONE + y);\r
SendToICS(buf);\r
} else {\r
boards[0][y][x] = selection;\r
\r
if (target > 0 && moveList[target - 1][0]) {\r
int fromX, fromY, toX, toY;\r
- toX = moveList[target - 1][2] - 'a';\r
+ toX = moveList[target - 1][2] - AAA;\r
toY = moveList[target - 1][3] - ONE;\r
if (moveList[target - 1][1] == '@') {\r
if (appData.highlightLastMove) {\r
SetHighlights(-1, -1, toX, toY);\r
}\r
} else {\r
- fromX = moveList[target - 1][0] - 'a';\r
+ fromX = moveList[target - 1][0] - AAA;\r
fromY = moveList[target - 1][1] - ONE;\r
if (target == currentMove + 1) {\r
AnimateMove(boards[currentMove], fromX, fromY, toX, toY);\r
\r
if (moveList[target][0]) {\r
int fromX, fromY, toX, toY;\r
- toX = moveList[target][2] - 'a';\r
+ toX = moveList[target][2] - AAA;\r
toY = moveList[target][3] - ONE;\r
if (moveList[target][1] == '@') {\r
if (appData.highlightLastMove) {\r
SetHighlights(-1, -1, toX, toY);\r
}\r
} else {\r
- fromX = moveList[target][0] - 'a';\r
+ fromX = moveList[target][0] - AAA;\r
fromY = moveList[target][1] - ONE;\r
if (target == currentMove - 1) {\r
AnimateMove(boards[currentMove], toX, toY, fromX, fromY);\r
int i, j;\r
\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
- for (j = 0; j < BOARD_WIDTH; j++) {\r
+ for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {\r
char c = PieceToChar(boards[move][i][j]);\r
fputc(c == 'x' ? '.' : c, fp);\r
- fputc(j == BOARD_WIDTH - 1 ? '\n' : ' ', fp);\r
+ fputc(j == BOARD_RGHT - 1 ? '\n' : ' ', fp);\r
}\r
}\r
if ((gameMode == EditPosition) ? !blackPlaysFirst : (move % 2 == 0))\r
char buf[128];\r
char *p, *q;\r
int emptycount;\r
+ ChessSquare piece;\r
\r
whiteToPlay = (gameMode == EditPosition) ?\r
!blackPlaysFirst : (move % 2 == 0);\r
/* Piece placement data */\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
emptycount = 0;\r
- for (j = 0; j < BOARD_WIDTH; j++) {\r
+ for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {\r
if (boards[move][i][j] == EmptySquare) {\r
emptycount++;\r
} else {\r
else { *p++ = '0' + emptycount/10; *p++ = '0' + emptycount%10; }\r
emptycount = 0;\r
}\r
- *p++ = PieceToChar(boards[move][i][j]);\r
+ *p++ = PieceToChar(boards[move][i][j]);\r
+ if(gameInfo.variant == VariantCrazyhouse) {\r
+ /* [HGM] flag Crazyhouse promoted pieces */\r
+ if( (int)boards[move][i][j] > (int) WhiteQueen && (int)boards[move][i][j] < (int) WhiteKing ||\r
+ (int)boards[move][i][j] > (int) BlackQueen && (int)boards[move][i][j] < (int) BlackKing ) {\r
+ p[-1] = PieceToChar((ChessSquare)((int)boards[move][i][j]-(int)WhiteAlfil+(int)WhitePawn));\r
+ *p++ = '~';\r
+ }\r
+ }\r
}\r
}\r
if (emptycount > 0) {\r
\r
/* White castling rights */\r
\r
- for (fk = 1; fk < BOARD_WIDTH-1; fk++) {\r
+ for (fk = BOARD_LEFT+1; fk < BOARD_RGHT-1; fk++) {\r
\r
if (boards[move][0][fk] == WhiteKing) {\r
\r
- for (fr = BOARD_WIDTH-1; fr > fk; fr--) { /* H side */\r
+ for (fr = BOARD_RGHT-1; fr > fk; fr--) { /* H side */\r
if (boards[move][0][fr] == WhiteRook) {\r
*p++ = useFEN960 ? 'A' + fr : 'K';\r
break;\r
}\r
}\r
\r
- for (fr = 0; fr < fk; fr++) { /* A side */\r
+ for (fr = BOARD_LEFT; fr < fk; fr++) { /* A side */\r
if (boards[move][0][fr] == WhiteRook) {\r
*p++ = useFEN960 ? 'A' + fr : 'Q';\r
break;\r
\r
/* Black castling rights */\r
\r
- for (fk = 1; fk < BOARD_WIDTH-1; fk++) {\r
+ for (fk = BOARD_LEFT+1; fk < BOARD_RGHT-1; fk++) {\r
\r
if (boards[move][BOARD_HEIGHT-1][fk] == BlackKing) {\r
\r
- for (fr = BOARD_WIDTH-1; fr > fk; fr--) { /* H side */\r
+ for (fr = BOARD_RGHT-1; fr > fk; fr--) { /* H side */\r
if (boards[move][BOARD_HEIGHT-1][fr] == BlackRook) {\r
*p++ = useFEN960 ? 'a' + fr : 'k';\r
break;\r
}\r
}\r
\r
- for (fr = 0; fr < fk; fr++) { /* A side */\r
+ for (fr = BOARD_LEFT; fr < fk; fr++) { /* A side */\r
if (boards[move][BOARD_HEIGHT-1][fr] == BlackRook) {\r
*p++ = useFEN960 ? 'a' + fr : 'q';\r
break;\r
\r
#ifdef OLDCASTLINGCODE\r
if (boards[move][0][BOARD_WIDTH>>1] == WhiteKing) {\r
- if (boards[move][0][BOARD_WIDTH-1] == WhiteRook) *p++ = 'K';\r
- if (boards[move][0][0] == WhiteRook) *p++ = 'Q';\r
+ if (boards[move][0][BOARD_RGHT-1] == WhiteRook) *p++ = 'K';\r
+ if (boards[move][0][BOARD_LEFT] == WhiteRook) *p++ = 'Q';\r
}\r
if (boards[move][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == BlackKing) {\r
if (boards[move][BOARD_HEIGHT-1][BOARD_HEIGHT-1] == BlackRook) *p++ = 'k';\r
- if (boards[move][BOARD_HEIGHT-1][0] == BlackRook) *p++ = 'q';\r
+ if (boards[move][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook) *p++ = 'q';\r
} \r
#else\r
/* [HGM] write true castling rights */\r
if( nrCastlingRights == 6 ) {\r
- if(castlingRights[move][0] == BOARD_WIDTH-1 &&\r
+ if(castlingRights[move][0] == BOARD_RGHT-1 &&\r
castlingRights[move][2] >= 0 ) *p++ = 'K';\r
- if(castlingRights[move][1] == 0 &&\r
+ if(castlingRights[move][1] == BOARD_LEFT &&\r
castlingRights[move][2] >= 0 ) *p++ = 'Q';\r
- if(castlingRights[move][3] == BOARD_WIDTH-1 &&\r
+ if(castlingRights[move][3] == BOARD_RGHT-1 &&\r
castlingRights[move][5] >= 0 ) *p++ = 'k';\r
- if(castlingRights[move][4] == 0 &&\r
+ if(castlingRights[move][4] == BOARD_LEFT &&\r
castlingRights[move][5] >= 0 ) *p++ = 'q';\r
}\r
#endif\r
\r
/* En passant target square */\r
if (move > backwardMostMove) {\r
- fromX = moveList[move - 1][0] - 'a';\r
+ fromX = moveList[move - 1][0] - AAA;\r
fromY = moveList[move - 1][1] - ONE;\r
- toX = moveList[move - 1][2] - 'a';\r
+ toX = moveList[move - 1][2] - AAA;\r
toY = moveList[move - 1][3] - ONE;\r
if (fromY == (whiteToPlay ? BOARD_HEIGHT-2 : 1) &&\r
toY == (whiteToPlay ? BOARD_HEIGHT-4 : 3) &&\r
boards[move][toY][toX] == (whiteToPlay ? BlackPawn : WhitePawn) &&\r
fromX == toX) {\r
/* 2-square pawn move just happened */\r
- *p++ = toX + 'a';\r
+ *p++ = toX + AAA;\r
*p++ = whiteToPlay ? '6'+BOARD_HEIGHT-8 : '3';\r
} else {\r
*p++ = '-';\r
*p++ = '-';\r
}\r
\r
+ /* [HGM] print Crazyhouse holdings */\r
+ if( gameInfo.variant == VariantCrazyhouse ) {\r
+ *p++ = ' '; q = p;\r
+ for(i=0; i<gameInfo.holdingsSize; i++) { /* white holdings */\r
+ piece = boards[move][i][BOARD_WIDTH-1];\r
+ if( piece != EmptySquare )\r
+ for(j=0; j<(int) boards[move][i][BOARD_WIDTH-2]; j++)\r
+ *p++ = PieceToChar(piece);\r
+ }\r
+ for(i=0; i<gameInfo.holdingsSize; i++) { /* black holdings */\r
+ piece = boards[move][BOARD_HEIGHT-i-1][0];\r
+ if( piece != EmptySquare )\r
+ for(j=0; j<(int) boards[move][BOARD_HEIGHT-i-1][1]; j++)\r
+ *p++ = PieceToChar(piece);\r
+ }\r
+\r
+ if( q == p ) *p++ = '-';\r
+ *p++ = ' ';\r
+ }\r
+\r
/* [HGM] find reversible plies */\r
{ int i = 0, j=move;\r
\r
int i, j;\r
char *p;\r
int emptycount;\r
+ ChessSquare piece;\r
\r
p = fen;\r
\r
+ /* [HGM] by default clear Crazyhouse holdings, if present */\r
+ if(gameInfo.holdingsWidth) {\r
+ for(i=0; i<BOARD_HEIGHT; i++) {\r
+ board[i][0] = EmptySquare; /* black holdings */\r
+ board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */\r
+ board[i][1] = (ChessSquare) 0; /* black counts */\r
+ board[i][BOARD_WIDTH-2] = (ChessSquare) 0; /* white counts */\r
+ }\r
+ }\r
+\r
/* Piece placement data */\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
j = 0;\r
for (;;) {\r
if (*p == '/' || *p == ' ') {\r
if (*p == '/') p++;\r
- emptycount = BOARD_WIDTH - j;\r
- while (emptycount--) board[i][j++] = EmptySquare;\r
+ emptycount = gameInfo.boardWidth - j;\r
+ while (emptycount--)\r
+ board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;\r
break;\r
#if(BOARD_SIZE >= 10)\r
} else if(*p=='x' || *p=='X') { /* [HGM] X means 10 */\r
p++; emptycount=10;\r
- if (j + emptycount > BOARD_WIDTH) return FALSE;\r
- while (emptycount--) board[i][j++] = EmptySquare;\r
+ if (j + emptycount > gameInfo.boardWidth) return FALSE;\r
+ while (emptycount--)\r
+ board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;\r
#endif\r
} else if (isdigit(*p)) {\r
emptycount = *p++ - '0';\r
while(isdigit(*p)) emptycount = 10*emptycount + *p++ - '0'; /* [HGM] allow > 9 */\r
- if (j + emptycount > BOARD_WIDTH) return FALSE;\r
- while (emptycount--) board[i][j++] = EmptySquare;\r
+ if (j + emptycount > gameInfo.boardWidth) return FALSE;\r
+ while (emptycount--)\r
+ board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;\r
} else if (isalpha(*p)) {\r
- if (j >= BOARD_WIDTH) return FALSE;\r
- board[i][j++] = CharToPiece(*p++);\r
+ if (j >= gameInfo.boardWidth) return FALSE;\r
+ piece = CharToPiece(*p++);\r
+ if(*p == '~') { /* [HGM] make it a promoted piece for Crazyhouse */\r
+ piece = (ChessSquare) ((int)piece + (int)WhiteAlfil - (int)WhitePawn);\r
+ p++;\r
+ }\r
+ board[i][(j++)+gameInfo.holdingsWidth] = piece;\r
} else {\r
return FALSE;\r
}\r
for(i=0; i<nrCastlingRights; i++ ) {\r
FENcastlingRights[i] = initialRights[i];\r
} /* assume possible unless obviously impossible */\r
- if(board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1;\r
- if(board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1;\r
- if(board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1;\r
- if(board[castlingRank[3]][initialRights[3]] != BlackRook) FENcastlingRights[3] = -1;\r
- if(board[castlingRank[4]][initialRights[4]] != BlackRook) FENcastlingRights[4] = -1;\r
- if(board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1;\r
+ if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1;\r
+ if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1;\r
+ if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1;\r
+ if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) FENcastlingRights[3] = -1;\r
+ if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) FENcastlingRights[4] = -1;\r
+ if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1;\r
FENrulePlies = 0;\r
\r
while(*p==' ') p++;\r
\r
if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
- /* castling indicator present, so default is impossible */\r
+ /* castling indicator present, so default is no castlings */\r
for(i=0; i<nrCastlingRights; i++ ) {\r
FENcastlingRights[i] = -1;\r
}\r
while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
switch(*p++) {\r
case'K':\r
- FENcastlingRights[0] = BOARD_WIDTH-1;\r
+ FENcastlingRights[0] = BOARD_RGHT-1;\r
FENcastlingRights[2] = BOARD_WIDTH>>1;\r
break;\r
case'Q':\r
- FENcastlingRights[1] = 0;\r
+ FENcastlingRights[1] = BOARD_LEFT;\r
FENcastlingRights[2] = BOARD_WIDTH>>1;\r
break;\r
case'k':\r
- FENcastlingRights[3] = BOARD_WIDTH-1;\r
+ FENcastlingRights[3] = BOARD_RGHT-1;\r
FENcastlingRights[5] = BOARD_WIDTH>>1;\r
break;\r
case'q':\r
- FENcastlingRights[4] = 0;\r
+ FENcastlingRights[4] = BOARD_LEFT;\r
FENcastlingRights[5] = BOARD_WIDTH>>1;\r
break;\r
/* Tord! FRC! */\r
if(*p=='-') {\r
p++; FENepStatus = EP_NONE;\r
} else {\r
- char c = *p++ - 'a';\r
+ char c = *p++ - AAA;\r
\r
- if(c < 0 || c >= BOARD_WIDTH) return TRUE;\r
+ if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;\r
if(*p >= '0' && *p <='9') *p++;\r
FENepStatus = c;\r
}\r
\r
+ /* [HGM] look for Crazyhouse holdings here */\r
+ while(*p==' ') p++;\r
+ if( !isdigit(*p) ) {\r
+ if(*p == '-' ) *p++; /* empty holdings */ else {\r
+ if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */\r
+ /* if we would allow FEN reading to set board size, we would */\r
+ /* have to add holdings and shift the board read so far here */\r
+ while( (piece = CharToPiece(*p) ) != EmptySquare ) {\r
+ *p++;\r
+ if((int) piece >= (int) BlackPawn ) {\r
+ i = (int)piece - (int)BlackPawn;\r
+ if( i >= BOARD_HEIGHT ) return FALSE;\r
+ board[BOARD_HEIGHT-1-i][0] = piece; /* black holdings */\r
+ board[BOARD_HEIGHT-1-i][1]++; /* black counts */\r
+ } else {\r
+ i = (int)piece - (int)WhitePawn;\r
+ if( i >= BOARD_HEIGHT ) return FALSE;\r
+ board[i][BOARD_WIDTH-1] = piece; /* white holdings */\r
+ board[i][BOARD_WIDTH-2]++; /* black holdings */\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+\r
if(sscanf(p, "%d", &i) == 1) {\r
FENrulePlies = i; /* 50-move ply counter */\r
/* (The move number is still ignored) */\r