if (!e) return v;\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
+ if( sscanf(e, "%dx%d_", &i, &i) == 2 ||\r
+ sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) {\r
while( *e++ != '_');\r
}\r
\r
char p;\r
ChessSquare piece;\r
\r
- if(gameInfo.holdingsWidth < 1) return;\r
+ if(gameInfo.holdingsWidth < 2) return;\r
\r
if( (int)lowestPiece >= BlackPawn ) {\r
holdingsColumn = 0;\r
countsColumn = 1;\r
holdingsStartRow = BOARD_HEIGHT-1;\r
- direction = 1;\r
+ direction = -1;\r
} else {\r
holdingsColumn = BOARD_WIDTH-1;\r
countsColumn = BOARD_WIDTH-2;\r
while( (p=*holdings++) != NULLCHAR ) {\r
piece = CharToPiece( ToUpper(p) );\r
if(piece == EmptySquare) continue;\r
- j = (int) piece - (int) WhitePawn;\r
+ /*j = (int) piece - (int) WhitePawn;*/\r
+ j = PieceToNumber(piece);\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
+ piece = (ChessSquare) ( j + (int)lowestPiece );\r
+ board[holdingsStartRow+j*direction][holdingsColumn] = piece;\r
+ board[holdingsStartRow+j*direction][countsColumn]++;\r
}\r
\r
}\r
\r
+void\r
+VariantSwitch(Board board, VariantClass newVariant)\r
+{\r
+ int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;\r
+ if(gameInfo.variant == newVariant) return;\r
+\r
+ /* [HGM] This routine is called each time an assignment is made to\r
+ * gameInfo.variant during a game, to make sure the board sizes\r
+ * are set to match the new variant. If that means adding or deleting\r
+ * holdings, we shift the playing board accordingly\r
+ */\r
+\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Switch board from %s to %s\n",\r
+ VariantName(gameInfo.variant), VariantName(newVariant));\r
+ setbuf(debugFP, NULL);\r
+ }\r
+ gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */\r
+ switch(newVariant) {\r
+ case VariantShogi:\r
+ case VariantShowgi:\r
+ newWidth = 9; newHeight = 9;\r
+ gameInfo.holdingsSize = 7;\r
+ case VariantBughouse:\r
+ case VariantCrazyhouse:\r
+ newHoldingsWidth = 2; break;\r
+ default:\r
+ newHoldingsWidth = gameInfo.holdingsSize = 0;\r
+ }\r
+\r
+ if(newWidth != gameInfo.boardWidth ||\r
+ newHeight != gameInfo.boardHeight ||\r
+ newHoldingsWidth != gameInfo.holdingsWidth ) {\r
+\r
+ /* shift position to new playing area, if needed */\r
+ if(newHoldingsWidth > gameInfo.holdingsWidth) {\r
+ for(i=0; i<BOARD_HEIGHT; i++) \r
+ for(j=BOARD_RGHT-1; j>=BOARD_LEFT; j--)\r
+ board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =\r
+ board[i][j];\r
+ for(i=0; i<newHeight; i++) {\r
+ board[i][0] = board[i][newWidth+2*newHoldingsWidth-1] = EmptySquare;\r
+ board[i][1] = board[i][newWidth+2*newHoldingsWidth-2] = (ChessSquare) 0;\r
+ }\r
+ } else if(newHoldingsWidth < gameInfo.holdingsWidth) {\r
+ for(i=0; i<BOARD_HEIGHT; i++)\r
+ for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
+ board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =\r
+ board[i][j];\r
+ }\r
+\r
+ gameInfo.boardWidth = newWidth;\r
+ gameInfo.boardHeight = newHeight;\r
+ gameInfo.holdingsWidth = newHoldingsWidth;\r
+ gameInfo.variant = newVariant;\r
+ InitDrawingSizes(-2, 0);\r
+\r
+ if(board != boards[0]) InitPosition(FALSE);\r
+\r
+ } else gameInfo.variant = newVariant;\r
+}\r
+\r
static int loggedOn = FALSE;\r
\r
/*-- Game start info cache: --*/\r
"* * match, initial time: * minute*, increment: * second")) {\r
/* Header for a move list -- second line */\r
/* Initial board will follow if this is a wild game */\r
-\r
if (gameInfo.event != NULL) free(gameInfo.event);\r
sprintf(str, "ICS %s %s match", star_match[0], star_match[1]);\r
gameInfo.event = StrSave(str);\r
- gameInfo.variant = StringToVariant(gameInfo.event);\r
+ /* [HGM] we switched variant. Translate boards if needed. */\r
+ VariantSwitch(boards[currentMove], StringToVariant(gameInfo.event));\r
continue;\r
}\r
\r
started = STARTED_NONE;\r
parse[parse_pos] = NULLCHAR;\r
if (appData.debugMode)\r
- fprintf(debugFP, "Parsing holdings: %s\n", parse);\r
+ fprintf(debugFP, "Parsing holdings: %s, currentMove = %d\n",\r
+ parse, currentMove);\r
if (sscanf(parse, " game %d", &gamenum) == 1 &&\r
gamenum == ics_gamenum) {\r
if (gameInfo.variant == VariantNormal) {\r
- gameInfo.variant = VariantCrazyhouse; /*temp guess*/\r
+ /* [HGM] We seem to switch variant during a game!\r
+ * Presumably no holdings were displayed, so we have\r
+ * to move the position two files to the right to\r
+ * create room for them!\r
+ */\r
+ VariantSwitch(boards[currentMove], VariantCrazyhouse); /* temp guess */\r
/* Get a move list just to see the header, which\r
will tell us whether this is really bug or zh */\r
if (ics_getting_history == H_FALSE) {\r
new_piece);\r
white_holding[strlen(white_holding)-1] = NULLCHAR;\r
black_holding[strlen(black_holding)-1] = NULLCHAR;\r
+ /* [HGM] copy holdings to board holdings area */\r
+ CopyHoldings(boards[currentMove], white_holding, WhitePawn);\r
+ CopyHoldings(boards[currentMove], black_holding, BlackPawn);\r
#if ZIPPY\r
if (appData.zippyPlay && first.initDone) {\r
ZippyHoldings(white_holding, black_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
+ DrawPosition(FALSE, boards[currentMove]);\r
DisplayTitle(str);\r
}\r
/* Suppress following prompt */\r
timeIncrement = increment * 1000;\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
+ VariantSwitch(board, StringToVariant(gameInfo.event) );\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "ParseBoard says variant = '%s'\n", gameInfo.event);\r
+ fprintf(debugFP, "recognized as %s\n", VariantName(gameInfo.variant));\r
+ setbuf(debugFP, NULL);\r
+ }\r
+\r
gameInfo.outOfBook = NULL;\r
\r
/* Do we have the ratings? */\r
}\r
\r
/* Parse the board */\r
- for (k = 0; k < 8; k++)\r
+ for (k = 0; k < 8; k++) {\r
for (j = 0; j < 8; j++)\r
- board[k][j] = CharToPiece(board_chars[(7-k)*9 + j]);\r
+ board[k][j+gameInfo.holdingsWidth] = CharToPiece(board_chars[(7-k)*9 + j]);\r
+ if(gameInfo.holdingsWidth > 1) {\r
+ board[k][0] = board[k][BOARD_WIDTH-1] = EmptySquare;\r
+ board[k][1] = board[k][BOARD_WIDTH-2] = (ChessSquare) 0;;\r
+ }\r
+ }\r
CopyBoard(boards[moveNum], board);\r
if (moveNum == 0) {\r
startedFromSetupPosition =\r
/* Put the move on the move list, first converting\r
to canonical algebraic form. */\r
if (moveNum > 0) {\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "accepted move %s from ICS, parse it.\n", move_str);\r
+ fprintf(debugFP, "board = %d-%d x %d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT);\r
+ setbuf(debugFP, NULL);\r
+ }\r
if (moveNum <= backwardMostMove) {\r
/* We don't know what the board looked like before\r
this move. Punt. */\r
default:\r
break;\r
case MT_CHECK:\r
- strcat(parseList[moveNum - 1], "+");\r
+ if(gameInfo.variant != VariantShogi)\r
+ strcat(parseList[moveNum - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
strcat(parseList[moveNum - 1], "#");\r
fromX = fromY = toX = toY = -1;\r
} else {\r
/* Move from ICS was illegal!? Punt. */\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Illegal move from ICS '%s'\n", move_str);\r
+ fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+ }\r
#if 0\r
if (appData.testLegality && appData.debugMode) {\r
sprintf(str, "Illegal move \"%s\" from ICS", move_str);\r
moveList[moveNum - 1][0] = NULLCHAR;\r
fromX = fromY = toX = toY = -1;\r
}\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Move parsed to '%s'\n", parseList[moveNum - 1]);\r
+ setbuf(debugFP, NULL);\r
+ }\r
\r
#if ZIPPY\r
/* Send move to chess program (BEFORE animating it). */\r
} else {\r
sprintf(buf, "%s\n", parseList[moveNum]);\r
}\r
- /* [HGM] decrement all digits to code ranks starting from 0 */\r
- if(BOARD_HEIGHT>8) {\r
- char *p = buf;\r
- while(*p) { if(*p < 'A') (*p)--; p++; }\r
- }\r
SendToProgram(buf, cps);\r
} else {\r
/* Added by Tord: Send castle moves in "O-O" in FRC games if required by\r
void\r
AlphaRank(char *move, int n)\r
{\r
- char *p = move, c;\r
+ char *p = move, c; int x, y;\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
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "alphaRank(%s,%d)\n", move, n);\r
+ }\r
+\r
+ if(move[1]=='*' && \r
+ move[2]>='0' && move[2]<='9' &&\r
+ move[3]>='a' && move[3]<='x' ) {\r
+ move[2] = (move[2]-'1')+BOARD_LEFT + AAA;\r
+ move[3] = (move[3]-'a') + ONE;\r
+ } else\r
+ if(move[0]>='0' && move[0]<='9' &&\r
+ move[1]>='a' && move[1]<='x' &&\r
+ move[2]>='0' && move[2]<='9' &&\r
+ move[3]>='a' && move[3]<='x' ) {\r
+ /* input move, Shogi -> normal */\r
+/*\r
+ move[0] = BOARD_RGHT -1-(move[0]-'1') + AAA;\r
+ move[1] = BOARD_HEIGHT-1-(move[1]-'a') + ONE;\r
+ move[2] = BOARD_RGHT -1-(move[2]-'1') + AAA;\r
+ move[3] = BOARD_HEIGHT-1-(move[3]-'a') + ONE;\r
+*/\r
+ move[0] = (move[0]-'1')+BOARD_LEFT + AAA;\r
+ move[1] = (move[1]-'a') + ONE;\r
+ move[2] = (move[2]-'1')+BOARD_LEFT + AAA;\r
+ move[3] = (move[3]-'a') + ONE;\r
+ } else\r
+ if(move[1]=='@' &&\r
+ move[3]>='0' && move[3]<='9' &&\r
+ move[2]>='a' && move[2]<='x' ) {\r
+ move[1] = '*';\r
+ move[2] = (move[2]-AAA)-BOARD_LEFT + '1';\r
+ move[3] = (move[3]-ONE) + 'a';\r
+ } else\r
+ if(\r
+ move[0]>='a' && move[0]<='x' &&\r
+ move[3]>='0' && move[3]<='9' &&\r
+ move[2]>='a' && move[2]<='x' ) {\r
+ /* output move, normal -> Shogi */\r
+/*\r
+ move[0] = BOARD_RGHT -1-(move[0]-AAA) + '1';\r
+ move[1] = BOARD_HEIGHT-1-(move[1]-ONE) + 'a';\r
+ move[2] = BOARD_RGHT -1-(move[2]-AAA) + '1';\r
+ move[3] = BOARD_HEIGHT-1-(move[3]-ONE) + 'a';\r
+*/\r
+ move[0] = (move[0]-AAA)-BOARD_LEFT + '1';\r
+ move[1] = (move[1]-ONE) + 'a';\r
+ move[2] = (move[2]-AAA)-BOARD_LEFT + '1';\r
+ move[3] = (move[3]-ONE) + 'a';\r
+ if(move[4] == PieceToChar(BlackQueen)) move[4] = '+';\r
+ }\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, " out = '%s'\n", move);\r
}\r
}\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
-#ifdef FAIRY\r
case WhitePromotionChancellor:\r
case BlackPromotionChancellor:\r
case WhitePromotionArchbishop:\r
case BlackPromotionArchbishop:\r
-#endif\r
case WhitePromotionQueen:\r
case BlackPromotionQueen:\r
case WhitePromotionRook:\r
*promoChar = currentMoveString[4];\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
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Off-board move (%d,%d)-(%d,%d)%c, type = %d\n", *fromX, *fromY, *toX, *toY, *promoChar, *moveType);\r
+ }\r
*fromX = *fromY = *toX = *toY = 0;\r
return FALSE;\r
}\r
case BlackWins:\r
case GameIsDrawn:\r
default:\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Impossible move %s, type = %d\n", currentMoveString, *moveType);\r
+ }\r
/* bug? */\r
*fromX = *fromY = *toX = *toY = 0;\r
*promoChar = NULLCHAR;\r
}\r
}\r
\r
+BOOL SetCharTable( char *table, const char * map )\r
+/* [HGM] moved here from winboard.c because of its general usefulness */\r
+/* Basically a safe strcpy that uses the last character as King */\r
+{\r
+ BOOL result = FALSE; int NrPieces;\r
+\r
+ if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare \r
+ && NrPieces >= 12 && !(NrPieces&1)) {\r
+ int i; /* [HGM] Accept even length from 12 to 34 */\r
+\r
+ for( i=0; i<(int) EmptySquare; i++ ) table[i] = '.';\r
+ for( i=0; i<NrPieces/2-1; i++ ) {\r
+ table[i] = map[i];\r
+ table[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];\r
+ }\r
+ table[(int) WhiteKing] = map[NrPieces/2-1];\r
+ table[(int) BlackKing] = map[NrPieces-1];\r
+\r
+ result = TRUE;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
void\r
InitPosition(redraw)\r
int redraw;\r
int i, j, pawnRow, overrule,\r
oldx = gameInfo.boardWidth,\r
oldy = gameInfo.boardHeight,\r
- oldh = gameInfo.holdingsWidth;\r
+ oldh = gameInfo.holdingsWidth,\r
+ oldv = gameInfo.variant;\r
\r
currentMove = forwardMostMove = backwardMostMove = 0;\r
\r
for( j=0; j<BOARD_SIZE; j++ ) castlingRights[i][j] = -1;\r
}\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_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_RGHT-1;\r
- castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
- castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
+ initialRulePlies = 0; /* 50-move counter start */\r
\r
castlingRank[0] = castlingRank[1] = castlingRank[2] = 0;\r
castlingRank[3] = castlingRank[4] = castlingRank[5] = BOARD_HEIGHT-1;\r
-\r
- initialRulePlies = 0; /* 50-move counter start */\r
}\r
\r
\r
gameInfo.boardWidth = 8;\r
gameInfo.boardHeight = 8;\r
gameInfo.holdingsSize = 0;\r
+ nrCastlingRights = -1; /* [HGM] Kludge to indicate default should be used */\r
+ for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1; /* but no rights yet */\r
+ SetCharTable(pieceToChar, "PNBRQ...........Kpnbrq...........k"); \r
\r
switch (gameInfo.variant) {\r
default:\r
case VariantShatranj:\r
pieces = ShatranjArray;\r
nrCastlingRights = 0;\r
- for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
break;\r
case VariantTwoKings:\r
pieces = twoKingsArray;\r
castlingRights[0][6] = initialRights[2] = 5;\r
castlingRights[0][7] = initialRights[5] = 5;\r
castlingRank[6] = 0;\r
- castlingRank[6] = BOARD_HEIGHT-1;\r
+ castlingRank[7] = BOARD_HEIGHT-1;\r
startedFromSetupPosition = TRUE;\r
break;\r
case VariantCapablanca:\r
pieces = CapablancaArray;\r
gameInfo.boardWidth = 10;\r
+ SetCharTable(pieceToChar, "PNBRQ.......AC..Kpnbrq.......ac..k"); \r
break;\r
case VariantGothic:\r
pieces = GothicArray;\r
gameInfo.boardWidth = 10;\r
+ SetCharTable(pieceToChar, "PNBRQ.......AC..Kpnbrq.......ac..k"); \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
+ SetCharTable(pieceToChar, "PH.R.AKE.C.......ph.r.ake.c......."); \r
break;\r
case VariantShogi:\r
pieces = ShogiArray;\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
+ SetCharTable(pieceToChar, "PNBRLSG...++++++Kpnbrlsg...++++++k"); \r
break;\r
case VariantShowgi:\r
pieces = ShogiArray;\r
gameInfo.holdingsSize = 7;\r
nrCastlingRights = 0;\r
for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
- strcpy(pieceToChar, "PNBRQFWEHACGOUMKpnbrlsgpnbrls..k"); \r
+ SetCharTable(pieceToChar, "PNBRQFWEMOUHACG.Kpnbrlsgpnbrls...k"); \r
break;\r
case VariantCourier:\r
pieces = CourierArray;\r
gameInfo.boardWidth = 12;\r
nrCastlingRights = 0;\r
+ SetCharTable(pieceToChar, "PNBR.FWEM.......Kpnbr.fwem.......k"); \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
+ SetCharTable(pieceToChar, "P.BRQ...M.K......p.brq...m.k......"); \r
break;\r
case VariantFairy:\r
pieces = fairyArray;\r
- strcpy(pieceToChar, "PNBRQFWEHACGOMUKpnbrqfwehacgomuk"); \r
+ SetCharTable(pieceToChar, "PNBRQFWEMOUHACGSKpnbrqfwemouhacgsk"); \r
startedFromSetupPosition = TRUE;\r
break;\r
case VariantCrazyhouse:\r
case VariantBughouse:\r
pieces = FIDEArray;\r
+ SetCharTable(pieceToChar, "PNBRQ......~~~~.Kpnbrq......~~~~.k"); \r
gameInfo.holdingsSize = 5;\r
- strcpy(pieceToChar, "PNBRQ...NBRQ...Kpnbrq...nbrq...k"); \r
break;\r
case VariantWildCastle:\r
pieces = FIDEArray;\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
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
+ pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */\r
+ if(pawnRow < 1) pawnRow = 1;\r
\r
/* User pieceToChar list overrules defaults */\r
if(appData.pieceToCharTable != NULL)\r
- strcpy(pieceToChar, appData.pieceToCharTable);\r
+ SetCharTable(pieceToChar, appData.pieceToCharTable);\r
\r
for( j=0; j<BOARD_WIDTH; j++ ) { ChessSquare s = EmptySquare;\r
\r
initialPosition[BOARD_HEIGHT-2][j] = BlackBishop;\r
}\r
\r
+ if( nrCastlingRights == -1) {\r
+ /* [HGM] Build normal castling rights (must be done after board sizing!) */\r
+ /* This sets default castling rights from none to normal corners */\r
+ /* Variants with other castling rights must set them themselves above */\r
+ nrCastlingRights = 6;\r
+ \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_RGHT-1;\r
+ castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
+ castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
+ }\r
+\r
if(gameInfo.variant == VariantFischeRandom) {\r
if( appData.defaultFrcPosition < 0 ) {\r
ShuffleFRC( initialPosition );\r
\r
if(oldx != gameInfo.boardWidth ||\r
oldy != gameInfo.boardHeight ||\r
- oldh != gameInfo.holdingsWidth )\r
- InitDrawingSizes(-1 ,0);\r
+ oldh != gameInfo.holdingsWidth\r
+#ifdef GOTHIC\r
+ || oldv == VariantGothic ||\r
+ gameInfo.variant == VariantGothic\r
+#endif\r
+ )\r
+ InitDrawingSizes(-2 ,0);\r
\r
if (redraw)\r
DrawPosition(TRUE, boards[currentMove]);\r
piece = boards[currentMove][fromY][fromX];\r
if(gameInfo.variant == VariantShogi) {\r
promotionZoneSize = 3;\r
- highestPromotingPiece = (int)WhiteFerz; /* Silver */\r
+ highestPromotingPiece = (int)WhiteKing;\r
+ /* [HGM] Should be Silver = Ferz, really, but legality testing is off,\r
+ and if in normal chess we then allow promotion to King, why not\r
+ allow promotion of other piece in Shogi? */\r
}\r
if((int)piece >= BlackPawn) {\r
if(toY >= promotionZoneSize && fromY >= promotionZoneSize)\r
int promoChar;\r
{\r
ChessMove moveType;\r
+ ChessSquare pdown, pup;\r
\r
if (fromX < 0 || fromY < 0) return ImpossibleMove;\r
if ((fromX == toX) && (fromY == toY)) {\r
return ImpossibleMove;\r
}\r
+\r
/* [HGM] suppress all moves into holdings area and guard band */\r
- if( toX < BOARD_LEFT || toX >= BOARD_RGHT ) return ImpossibleMove;\r
- \r
+ if( toX < BOARD_LEFT || toX >= BOARD_RGHT || toY < 0 )\r
+ return ImpossibleMove;\r
+\r
+ /* [HGM] <sameColor> moved to here from winboard.c */\r
+ /* note: this code seems to exist for filtering out some obviously illegal premoves */\r
+ pdown = boards[currentMove][fromY][fromX];\r
+ pup = boards[currentMove][toY][toX];\r
+ if ( gameMode != EditPosition &&\r
+ (WhitePawn <= pdown && pdown < BlackPawn &&\r
+ WhitePawn <= pup && pup < BlackPawn ||\r
+ BlackPawn <= pdown && pdown < EmptySquare &&\r
+ BlackPawn <= pup && pup < EmptySquare) )\r
+ 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
tried to pick up may have been captured by the time he puts it down!\r
break;\r
\r
case EditPosition:\r
+ /* EditPosition, empty square, or different color piece;\r
+ click-click move is possible */\r
if (toX == -2 || toY == -2) {\r
boards[0][fromY][fromX] = EmptySquare;\r
DrawPosition(FALSE, boards[currentMove]);\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
+ if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { \r
+ if( pup != EmptySquare ) return ImpossibleMove;\r
+ if(appData.testLegality) {\r
+ /* it would be more logical if LegalityTest() also figured out\r
+ * which drops are legal. For now we forbid pawns on back rank.\r
+ * Shogi is on its own here...\r
+ */\r
+ if( (pdown == WhitePawn || pdown == BlackPawn) &&\r
+ (toY == 0 || toY == BOARD_HEIGHT -1 ) )\r
+ return(ImpossibleMove); /* no pawn drops on 1st/8th */\r
+ }\r
return WhiteDrop; /* Not needed to specify white or black yet */\r
}\r
\r
userOfferedDraw = FALSE;\r
\r
- if (appData.testLegality) {\r
- moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),\r
- EP_UNKNOWN, castlingRights[currentMove],\r
+ /* [HGM] always test for legality, to get promotion info */\r
+ moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),\r
+ epStatus[currentMove], castlingRights[currentMove],\r
fromY, fromX, toY, toX, promoChar);\r
+\r
+ /* [HGM] but possibly ignore an IllegalMove result */\r
+ if (appData.testLegality) {\r
if (moveType == IllegalMove || moveType == ImpossibleMove) {\r
DisplayMoveError("Illegal move");\r
return ImpossibleMove;\r
}\r
- } else {\r
- moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);\r
}\r
\r
return moveType;\r
return;\r
}\r
\r
+ AlphaRank(machineMove, 4);\r
if (!ParseOneMove(machineMove, forwardMostMove, &moveType,\r
&fromX, &fromY, &toX, &toY, &promoChar)) {\r
/* Machine move could not be parsed; ignore it. */\r
/* to make sure an illegal e.p. capture does not slip through, */\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
+ if( gameMode==TwoMachinesPlay && appData.testLegality\r
+ && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */\r
+ ) {\r
+ ChessMove moveType;\r
+ moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),\r
epStatus[forwardMostMove], castlingRights[forwardMostMove],\r
- fromY, fromX, toY, toX, promoChar) == IllegalMove)\r
- {\r
+ fromY, fromX, toY, toX, promoChar);\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(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
+ if(moveType == IllegalMove) {\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
+ } else if(gameInfo.variant != VariantFischeRandom)\r
+ /* [HGM] Kludge to handle engines that send FRC-style castling\r
+ when they shouldn't (like TSCP-Gothic) */\r
+ switch(moveType) {\r
+ case WhiteASideCastleFR:\r
+ case BlackASideCastleFR:\r
+ toY++;\r
+ currentMoveString[2]++;\r
+ break;\r
+ case WhiteHSideCastleFR:\r
+ case BlackHSideCastleFR:\r
+ toY--;\r
+ currentMoveString[2]--;\r
+ break;\r
}\r
+ }\r
hintRequested = FALSE;\r
lastHint[0] = NULLCHAR;\r
bookRequested = FALSE;\r
count = 0;\r
for(k = forwardMostMove-2;\r
k>=backwardMostMove && k>=forwardMostMove-100 &&\r
- epStatus[k] <= EP_NONE && epStatus[k+1] <= EP_NONE;\r
+ epStatus[k] < EP_UNKNOWN &&\r
+ epStatus[k+2] <= EP_NONE && epStatus[k+1] <= EP_NONE;\r
k-=2)\r
{ int rights=0;\r
if (appData.debugMode) {\r
cps->useSigterm = FALSE;\r
}\r
\r
+ /* [HGM] Allow engine to set up a position. Don't ask me why one would\r
+ * want this, I was asked to put it in, and obliged.\r
+ */\r
+ if (!strncmp(message, "setboard ", 9)) {\r
+ Board initial_position; int i;\r
+\r
+ GameEnds(GameUnfinished, "Engine aborts game", GE_XBOARD);\r
+\r
+ if (!ParseFEN(initial_position, &blackPlaysFirst, message + 9)) {\r
+ DisplayError("Bad FEN received from engine", 0);\r
+ return ;\r
+ } else {\r
+ Reset(FALSE, FALSE);\r
+ CopyBoard(boards[0], initial_position);\r
+ initialRulePlies = FENrulePlies;\r
+ epStatus[0] = FENepStatus;\r
+ for( i=0; i<nrCastlingRights; i++ )\r
+ castlingRights[0][i] = FENcastlingRights[i];\r
+ if(blackPlaysFirst) gameMode = MachinePlaysWhite;\r
+ else gameMode = MachinePlaysBlack; \r
+ DrawPosition(FALSE, boards[currentMove]);\r
+ }\r
+ return;\r
+ }\r
+\r
/*\r
* Look for communication commands\r
*/\r
} else if (strncmp(message, "Black resign", 12) == 0) {\r
GameEnds(WhiteWins, "Black resigns", GE_ENGINE1 + (cps != &first));\r
return;\r
+ } else if (strncmp(message, "White matches", 13) == 0 ||\r
+ strncmp(message, "Black matches", 13) == 0 ) {\r
+ /* [HGM] ignore GNUShogi noises */\r
+ return;\r
} else if (strncmp(message, "White", 5) == 0 &&\r
message[5] != '(' &&\r
StrStr(message, "Black") == NULL) {\r
yyboardindex = boardIndex;\r
moveType = (ChessMove) yylex();\r
switch (moveType) {\r
-#ifdef FAIRY\r
+ case IllegalMove: /* maybe suicide chess, etc. */\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Illegal move from ICS: '%s'\n", yy_text);\r
+ fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+ setbuf(debugFP, NULL);\r
+ }\r
case WhitePromotionChancellor:\r
case BlackPromotionChancellor:\r
case WhitePromotionArchbishop:\r
case BlackPromotionArchbishop:\r
-#endif\r
case WhitePromotionQueen:\r
case BlackPromotionQueen:\r
case WhitePromotionRook:\r
case BlackHSideCastleFR:\r
case BlackASideCastleFR:\r
/* POP Fabien */\r
- case IllegalMove: /* maybe suicide chess, etc. */\r
fromX = currentMoveString[0] - AAA;\r
fromY = currentMoveString[1] - ONE;\r
toX = currentMoveString[2] - AAA;\r
case AmbiguousMove:\r
/* bug? */\r
sprintf(buf, "Ambiguous move in ICS output: \"%s\"", yy_text);\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Ambiguous move from ICS: '%s'\n", yy_text);\r
+ fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+ setbuf(debugFP, NULL);\r
+ }\r
DisplayError(buf, 0);\r
return;\r
case ImpossibleMove:\r
/* bug? */\r
sprintf(buf, "Illegal move in ICS output: \"%s\"", yy_text);\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Impossible move from ICS: '%s'\n", yy_text);\r
+ fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+ setbuf(debugFP, NULL);\r
+ }\r
DisplayError(buf, 0);\r
return;\r
case (ChessMove) 0: /* end of file */\r
default:\r
break;\r
case MT_CHECK:\r
- strcat(parseList[boardIndex - 1], "+");\r
+ if(gameInfo.variant != VariantShogi)\r
+ strcat(parseList[boardIndex - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
strcat(parseList[boardIndex - 1], "#");\r
int promoChar;\r
Board board;\r
{\r
- ChessSquare captured = board[toY][toX], piece; int p;\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
+ /* [HGM] In Shatranj and Courier all promotions are to Ferz */\r
+ if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier)\r
&& promoChar != 0) promoChar = 'F';\r
\r
- if (fromY == DROP_RANK) {\r
+ if (fromX == toX && fromY == toY) return;\r
+\r
+ if (fromY == DROP_RANK) {\r
/* must be first */\r
board[toY][toX] = (ChessSquare) fromX;\r
- } else if (fromX == toX && fromY == toY) {\r
- return;\r
- }\r
+ } else {\r
+ piece = board[fromY][fromX]; /* [HGM] remember, for Shogi promotion */\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
+ if (board[fromY][fromX] == WhiteKing &&\r
board[toY][toX] == WhiteRook) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = EmptySquare;\r
board[toY][2] = WhiteRook;\r
} else if (board[fromY][fromX] == WhitePawn\r
&& toY == BOARD_HEIGHT-1\r
-#ifdef FAIRY\r
&& gameInfo.variant != VariantXiangqi\r
-#endif\r
) {\r
/* white pawn promotion */\r
board[toY][toX] = CharToPiece(ToUpper(promoChar));\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
+ if(gameInfo.variant==VariantBughouse ||\r
+ gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */\r
+ board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);\r
board[fromY][fromX] = EmptySquare;\r
} else if ((fromY == BOARD_HEIGHT-4)\r
&& (toX != fromX)\r
board[toY][2] = BlackRook;\r
} else if (board[fromY][fromX] == BlackPawn\r
&& toY == 0\r
-#ifdef FAIRY\r
&& gameInfo.variant != VariantXiangqi\r
-#endif\r
) {\r
/* black pawn promotion */\r
board[0][toX] = CharToPiece(ToLower(promoChar));\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
+ if(gameInfo.variant==VariantBughouse ||\r
+ gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */\r
+ board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);\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
+\r
+ /* [HGM] now we promote for Shogi, if needed */\r
+ if(gameInfo.variant == VariantShogi && promoChar == 'q')\r
+ board[toY][toX] = (ChessSquare) (PROMOTED piece);\r
+ }\r
+\r
if (gameInfo.holdingsWidth != 0) {\r
\r
/* !!A lot more code needs to be written to support holdings */\r
captured = (ChessSquare) (DEMOTED captured);\r
p = DEMOTED p;\r
}\r
+ p = PieceToNumber((ChessSquare)p);\r
if(p >= gameInfo.holdingsSize) { p = 0; captured = BlackPawn; }\r
board[p][BOARD_WIDTH-2]++;\r
board[p][BOARD_WIDTH-1] =\r
captured = (ChessSquare) (DEMOTED captured);\r
p = DEMOTED p;\r
}\r
+ p = PieceToNumber((ChessSquare)p);\r
if(p >= gameInfo.holdingsSize) { p = 0; captured = WhitePawn; }\r
board[BOARD_HEIGHT-1-p][1]++;\r
board[BOARD_HEIGHT-1-p][0] =\r
board[toY][toX] = EmptySquare;\r
}\r
}\r
- if(gameInfo.variant == VariantShogi && promoChar != NULLCHAR) {\r
+ if(gameInfo.variant == VariantShogi && promoChar != NULLCHAR && promoChar != '=') {\r
/* [HGM] Shogi promotions */\r
board[toY][toX] = (ChessSquare) (PROMOTED piece);\r
}\r
if( boards[forwardMostMove][fromY][fromX] == WhitePawn ) {\r
epStatus[forwardMostMove] = EP_PAWN_MOVE; \r
if( toY-fromY==2 &&\r
- (toX>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == BlackPawn ||\r
+ (toX>BOARD_LEFT && 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>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
+ (toX>BOARD_LEFT && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
toX<BOARD_RGHT-1 && boards[forwardMostMove][toY][toX+1] == WhitePawn ) )\r
epStatus[forwardMostMove] = toX;\r
}\r
castlingRights[forwardMostMove][i] == toX && castlingRank[i] == toY \r
) castlingRights[forwardMostMove][i] = -1; // revoke for moved or captured piece\r
\r
+\r
+\r
}\r
\r
}\r
default:\r
break;\r
case MT_CHECK:\r
- strcat(parseList[forwardMostMove - 1], "+");\r
+ if(gameInfo.variant != VariantShogi)\r
+ strcat(parseList[forwardMostMove - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
strcat(parseList[forwardMostMove - 1], "#");\r
break;\r
}\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "move: %s, parse: %s (%c)\n", moveList[forwardMostMove-1], parseList[forwardMostMove-1], moveList[forwardMostMove-1][4]);\r
+ }\r
+\r
}\r
\r
/* Updates currentMove if not pausing */\r
|| gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8\r
) {\r
char *v = VariantName(gameInfo.variant);\r
- if (StrStr(cps->variants, v) == NULL) {\r
+ if (cps->protocolVersion != 1 && StrStr(cps->variants, v) == NULL) {\r
+ /* [HGM] in protocol 1 we have to assume all variants valid */\r
sprintf(buf, "Variant %s not supported by %s", v, cps->tidy);\r
DisplayFatalError(buf, 0, 1);\r
return;\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
+ if (cps->protocolVersion != 1 && 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
+ /* [HGM] here we really should compare with the maximum supported board size */\r
sprintf(buf, "%dx%d+%d_", gameInfo.boardWidth,\r
gameInfo.boardHeight, gameInfo.holdingsSize );\r
while(*b++ != '_');\r
claimer = whosays == GE_ENGINE1 ? /* color of claimer */\r
first.twoMachinesColor[0] :\r
second.twoMachinesColor[0] ;\r
- if( result == WhiteWins && claimer == 'w' ||\r
- result == BlackWins && claimer == 'b' ) {\r
+ if( gameInfo.holdingsWidth == 0 &&\r
+ (result == WhiteWins && claimer == 'w' ||\r
+ result == BlackWins && claimer == 'b' ) ) {\r
/* Xboard immediately adjudicates all mates, so win claims must be false */\r
sprintf(buf, "False win claim: '%s'", resultDetails);\r
result = claimer == 'w' ? BlackWins : WhiteWins;\r
\r
case WhiteCapturesEnPassant:\r
case BlackCapturesEnPassant:\r
-#ifdef FAIRY\r
case WhitePromotionChancellor:\r
case BlackPromotionChancellor:\r
case WhitePromotionArchbishop:\r
case BlackPromotionArchbishop:\r
-#endif\r
case WhitePromotionQueen:\r
case BlackPromotionQueen:\r
case WhitePromotionRook:\r
int x, y;\r
{\r
char buf[MSG_SIZ];\r
+ ChessSquare piece = boards[0][y][x];\r
\r
if (gameMode != EditPosition && gameMode != IcsExamining) return;\r
\r
}\r
break;\r
\r
+ case PromotePiece:\r
+ if(piece >= (int)WhitePawn && piece < (int)WhiteWazir ||\r
+ piece >= (int)BlackPawn && piece < (int)BlackWazir ) {\r
+ selection = (ChessSquare) (PROMOTED piece);\r
+ } else if(piece == EmptySquare) selection = WhiteWazir;\r
+ else selection = (ChessSquare)((int)piece - 1);\r
+ goto defaultlabel;\r
+\r
+ case DemotePiece:\r
+ if(piece >= (int)WhiteUnicorn && piece < (int)WhiteKing ||\r
+ piece >= (int)BlackUnicorn && piece < (int)BlackKing ) {\r
+ selection = (ChessSquare) (DEMOTED piece);\r
+ } else if( piece == WhiteKing || piece == BlackKing )\r
+ selection = (ChessSquare)((int)piece - (int)WhiteKing + (int)WhiteMan);\r
+ else if(piece == EmptySquare) selection = BlackWazir;\r
+ else selection = (ChessSquare)((int)piece + 1); \r
+ goto defaultlabel;\r
+\r
+ case WhiteQueen:\r
+ case BlackQueen:\r
+ if(gameInfo.variant == VariantShatranj ||\r
+ gameInfo.variant == VariantXiangqi ||\r
+ gameInfo.variant == VariantCourier )\r
+ selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);\r
+ goto defaultlabel;\r
+\r
+ case WhiteKing:\r
+ case BlackKing:\r
+ if(gameInfo.variant == VariantXiangqi)\r
+ selection = (ChessSquare)((int)selection - (int)WhiteKing + (int)WhiteWazir);\r
+ if(gameInfo.variant == VariantKnightmate)\r
+ selection = (ChessSquare)((int)selection - (int)WhiteKing + (int)WhiteUnicorn);\r
default:\r
+ defaultlabel:\r
if (gameMode == IcsExamining) {\r
sprintf(buf, "%s%c@%c%c\n", ics_prefix,\r
PieceToChar(selection), AAA + x, ONE + y);\r
return nextTickLength;\r
}\r
\r
+/* Adjust clock one minute up or down */\r
+void\r
+AdjustClock(Boolean which, int dir)\r
+{\r
+ if(which) blackTimeRemaining += 60000*dir;\r
+ else whiteTimeRemaining += 60000*dir;\r
+ DisplayBothClocks();\r
+}\r
+\r
/* Stop clocks and reset to a fresh time control */\r
void\r
ResetClocks() \r
for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {\r
if (boards[move][i][j] == EmptySquare) {\r
emptycount++;\r
- } else {\r
+ } else { ChessSquare piece = boards[move][i][j];\r
if (emptycount > 0) {\r
if(emptycount<10) /* [HGM] can be >= 10 */\r
*p++ = '0' + emptycount;\r
else { *p++ = '0' + emptycount/10; *p++ = '0' + emptycount%10; }\r
emptycount = 0;\r
}\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
+ if(PieceToChar(piece) == '+') {\r
+ /* [HGM] write promoted pieces as '+<unpromoted>' (Shogi) */\r
+ *p++ = '+';\r
+ piece = (ChessSquare)(DEMOTED piece);\r
+ } \r
+ *p++ = PieceToChar(piece);\r
+ if(p[-1] == '~') {\r
+ /* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */\r
+ p[-1] = PieceToChar((ChessSquare)(DEMOTED piece));\r
+ *p++ = '~';\r
}\r
}\r
}\r
*p++ = whiteToPlay ? 'w' : 'b';\r
*p++ = ' ';\r
\r
+ if(nrCastlingRights) {\r
/* HACK: we don't keep track of castling availability, so fake it! */\r
/* Tord! please fix with the aid of castlingRights[move][...] */\r
\r
}\r
\r
/* POP Fabien & Tord */\r
+ }\r
\r
+ if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&\r
+ gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { \r
/* En passant target square */\r
if (move > backwardMostMove) {\r
fromX = moveList[move - 1][0] - AAA;\r
} else {\r
*p++ = '-';\r
}\r
+ *p++ = ' ';\r
+ }\r
\r
- /* [HGM] print Crazyhouse holdings */\r
- if( gameInfo.variant == VariantCrazyhouse ) {\r
- *p++ = ' '; q = p;\r
+ /* [HGM] print Crazyhouse or Shogi holdings */\r
+ if( gameInfo.holdingsWidth ) {\r
+ 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
/* [HGM] find reversible plies */\r
{ int i = 0, j=move;\r
\r
- if (appData.debugMode) { int k;\r
- fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);\r
- for(k=backwardMostMove; k<=forwardMostMove; k++)\r
- fprintf(debugFP, "e%d. p=%d\n", k, epStatus[k]);\r
+ if (appData.debugMode) { int k;\r
+ fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);\r
+ for(k=backwardMostMove; k<=forwardMostMove; k++)\r
+ fprintf(debugFP, "e%d. p=%d\n", k, epStatus[k]);\r
\r
- }\r
+ }\r
\r
while(j > backwardMostMove && epStatus[j] <= EP_NONE) j--,i++;\r
if( j == backwardMostMove ) i += initialRulePlies;\r
- sprintf(p, " %d", i);\r
- p += i>=100 ? 4 : i >= 10 ? 3 : 2;\r
+ sprintf(p, "%d ", i);\r
+ p += i>=100 ? 4 : i >= 10 ? 3 : 2;\r
}\r
/* Fullmove number */\r
- sprintf(p, " %d", (move / 2) + 1);\r
+ sprintf(p, "%d", (move / 2) + 1);\r
\r
return StrSave(buf);\r
}\r
p = fen;\r
\r
/* [HGM] by default clear Crazyhouse holdings, if present */\r
- if(gameInfo.holdingsWidth) {\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
\r
/* Piece placement data */\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
if (j + emptycount > gameInfo.boardWidth) return FALSE;\r
while (emptycount--)\r
board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;\r
- } else if (isalpha(*p)) {\r
+ } else if (*p == '+' || isalpha(*p)) {\r
if (j >= gameInfo.boardWidth) return FALSE;\r
- piece = CharToPiece(*p++);\r
+ if(*p=='+') {\r
+ piece = CharToPiece(*++p);\r
+ if(piece == EmptySquare) return FALSE; /* unknown piece */\r
+ piece = (ChessSquare) (PROMOTED piece ); p++;\r
+ if(PieceToChar(piece) != '+') return FALSE; /* unpromotable piece */\r
+ } else piece = CharToPiece(*p++);\r
+\r
+ if(piece==EmptySquare) return FALSE; /* unknown piece */\r
if(*p == '~') { /* [HGM] make it a promoted piece for Crazyhouse */\r
- piece = (ChessSquare) ((int)piece + (int)WhiteAlfil - (int)WhitePawn);\r
+ piece = (ChessSquare) (PROMOTED piece);\r
+ if(PieceToChar(piece) != '~') return FALSE; /* cannot be a promoted piece */\r
p++;\r
}\r
board[i][(j++)+gameInfo.holdingsWidth] = piece;\r
\r
/* [HGM] We NO LONGER ignore the rest of the FEN notation */\r
/* return the extra info in global variiables */\r
- {\r
+\r
/* set defaults in case FEN is incomplete */\r
FENepStatus = EP_UNKNOWN;\r
for(i=0; i<nrCastlingRights; i++ ) {\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 no castlings */\r
- for(i=0; i<nrCastlingRights; i++ ) {\r
- FENcastlingRights[i] = -1;\r
- }\r
- }\r
- while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
+ if(nrCastlingRights) {\r
+ if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
+ /* castling indicator present, so default becomes no castlings */\r
+ for(i=0; i<nrCastlingRights; i++ ) {\r
+ FENcastlingRights[i] = -1;\r
+ }\r
+ }\r
+ while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
switch(*p++) {\r
case'K':\r
FENcastlingRights[0] = BOARD_RGHT-1;\r
break;\r
/* Tord! FRC! */\r
}\r
- }\r
-\r
- while(*p==' ') p++;\r
+ }\r
\r
+ while(*p==' ') p++;\r
+ }\r
\r
- if(*p=='-') {\r
+ /* read e.p. field in games that know e.p. capture */\r
+ if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&\r
+ gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { \r
+ if(*p=='-') {\r
p++; FENepStatus = EP_NONE;\r
- } else {\r
- char c = *p++ - AAA;\r
+ } else {\r
+ char c = *p++ - AAA;\r
\r
- if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;\r
- if(*p >= '0' && *p <='9') *p++;\r
- FENepStatus = c;\r
+ if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;\r
+ if(*p >= '0' && *p <='9') *p++;\r
+ FENepStatus = c;\r
+ }\r
}\r
\r
/* [HGM] look for Crazyhouse holdings here */\r
while(*p==' ') p++;\r
- if( !isdigit(*p) ) {\r
+ if( gameInfo.holdingsWidth ) {\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
}\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
}\r
- }\r
+\r
return TRUE;\r
}\r
\r