}\r
\r
char pieceToChar[] = {\r
- 'P', 'N', 'B', 'R', 'Q', \r
-#ifdef FAIRY\r
- 'F', 'W', 'E', 'H', 'A', 'C', 'G', 'O', 'M', 'U', \r
-#endif\r
- 'K', 'p', 'n', 'b', 'r', 'q', \r
-#ifdef FAIRY \r
- 'f', 'w', 'e', 'h', 'a', 'c', 'g', 'o', 'm', 'u',\r
-#endif\r
+ 'P', 'N', 'B', 'R', 'Q', 'F', \r
+ 'W', 'E', 'M', 'O', 'U', 'H', 'A', 'C', 'G', 'S',\r
+ 'K', 'p', 'n', 'b', 'r', 'q', 'f', \r
+ 'w', 'e', 'm', 'o', 'u', 'h', 'a', 'c', 'g', 's',\r
'k', 'x'\r
};\r
\r
char PieceToChar(p)\r
ChessSquare p;\r
{\r
+ if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */\r
return pieceToChar[(int) p];\r
}\r
\r
+int PieceToNumber(p)\r
+ ChessSquare p;\r
+{\r
+ int i=0;\r
+ ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn;\r
+\r
+ while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++;\r
+ return i;\r
+}\r
+\r
ChessSquare CharToPiece(c)\r
int c;\r
{\r
for(i=0; i< (int) EmptySquare; i++)\r
if(pieceToChar[i] == c) return (ChessSquare) i;\r
return EmptySquare;\r
-/* [HGM] code marked for deletion\r
- switch (c) {\r
- default:\r
- case 'x': return EmptySquare;\r
- case 'P': return WhitePawn;\r
- case 'R': return WhiteRook;\r
- case 'N': return WhiteKnight;\r
- case 'B': return WhiteBishop;\r
- case 'Q': return WhiteQueen;\r
- case 'K': return WhiteKing;\r
- case 'p': return BlackPawn;\r
- case 'r': return BlackRook;\r
- case 'n': return BlackKnight;\r
- case 'b': return BlackBishop;\r
- case 'q': return BlackQueen;\r
- case 'k': return BlackKing;\r
-#ifdef FAIRY\r
- case 'A': return WhiteCardinal;\r
- case 'C': return WhiteMarshall;\r
- case 'F': return WhiteFerz;\r
- case 'H': return WhiteNightrider;\r
- case 'E': return WhiteAlfil;\r
- case 'W': return WhiteWazir;\r
- case 'U': return WhiteUnicorn;\r
- case 'O': return WhiteCannon;\r
- case 'G': return WhiteGrasshopper;\r
- case 'M': return WhiteMan;\r
- \r
- case 'a': return BlackCardinal;\r
- case 'c': return BlackMarshall;\r
- case 'f': return BlackFerz;\r
- case 'h': return BlackNightrider;\r
- case 'e': return BlackAlfil;\r
- case 'w': return BlackWazir;\r
- case 'u': return BlackUnicorn;\r
- case 'o': return BlackCannon;\r
- case 'g': return BlackGrasshopper;\r
- case 'm': return BlackMan;\r
- \r
-#endif\r
- }\r
-*/\r
}\r
\r
void CopyBoard(to, from)\r
break;\r
\r
case WhitePawn:\r
-#ifdef FAIRY\r
if(gameInfo.variant == VariantXiangqi) {\r
/* [HGM] capture and move straight ahead in Xiangqi */\r
if (rf < BOARD_HEIGHT-1 &&\r
}\r
break;\r
}\r
-#endif\r
if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {\r
callback(board, flags,\r
rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
break;\r
\r
case BlackPawn:\r
-#ifdef FAIRY\r
if(gameInfo.variant == VariantXiangqi) {\r
/* [HGM] capture straight ahead in Xiangqi */\r
if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {\r
}\r
break;\r
}\r
-#endif\r
if (rf > 0 && board[rf - 1][ff] == EmptySquare) {\r
callback(board, flags, \r
rf == 1 ? BlackPromotionQueen : NormalMove,\r
} \r
break;\r
\r
-#ifdef FAIRY\r
case WhiteUnicorn:\r
case BlackUnicorn:\r
-#endif\r
case WhiteKnight:\r
case BlackKnight:\r
mounted:\r
}\r
break;\r
\r
-#ifdef FAIRY\r
case SHOGI WhiteKnight:\r
for (s = -1; s <= 1; s += 2) {\r
if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
!SameColor(board[rf][ff], board[rf + 2][ff + s])) {\r
- callback(board, flags, \r
- rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+ callback(board, flags, NormalMove,\r
rf, ff, rf + 2, ff + s, closure);\r
}\r
}\r
for (s = -1; s <= 1; s += 2) {\r
if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
!SameColor(board[rf][ff], board[rf - 2][ff + s])) {\r
- callback(board, flags, \r
- rf == 1 ? BlackPromotionQueen : NormalMove,\r
+ callback(board, flags, NormalMove,\r
rf, ff, rf - 2, ff + s, closure);\r
}\r
} \r
for (s = -1; s <= 1; s += 2) {\r
if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
!SameColor(board[rf][ff], board[rf + 1][ff + s])) {\r
- callback(board, flags, \r
- rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+ callback(board, flags, NormalMove,\r
rf, ff, rf + 1, ff + s, closure);\r
}\r
}\r
for (s = -1; s <= 1; s += 2) {\r
if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
!SameColor(board[rf][ff], board[rf - 1][ff + s])) {\r
- callback(board, flags, \r
- rf == 1 ? BlackPromotionQueen : NormalMove,\r
+ callback(board, flags, NormalMove,\r
rf, ff, rf - 1, ff + s, closure);\r
}\r
} \r
/* Shogi Bishops are ordinary Bishops */\r
case SHOGI WhiteBishop:\r
case SHOGI BlackBishop:\r
-#endif\r
case WhiteBishop:\r
case BlackBishop:\r
for (rs = -1; rs <= 1; rs += 2) \r
/* Bishop falls through */\r
break;\r
\r
-#ifdef FAIRY\r
/* Shogi Lance is unlike anything, and asymmetric at that */\r
case SHOGI WhiteQueen:\r
for(i = 1;; i++) {\r
/* Shogi Rooks are ordinary Rooks */\r
case SHOGI WhiteRook:\r
case SHOGI BlackRook:\r
-#endif\r
case WhiteRook:\r
case BlackRook:\r
for (d = 0; d <= 1; d++)\r
}\r
break;\r
\r
-#ifdef FAIRY\r
/* Shogi Pawn and Silver General: first the Pawn move, */\r
/* then the General continues like a Ferz */\r
case SHOGI WhitePawn:\r
case BlackMan:\r
case SHOGI WhiteKing:\r
case SHOGI BlackKing:\r
-#endif\r
case WhiteKing:\r
case BlackKing:\r
walking:\r
!CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
\r
callback(board, flags,\r
- ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
+ ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure);\r
}\r
if ((flags & F_WHITE_ON_MOVE) &&\r
cl.ft = ft;\r
cl.kind = IllegalMove;\r
GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
+\r
+ if(gameInfo.variant == VariantShogi) {\r
+ /* [HGM] Shogi promotions. '=' means defer */\r
+ if(rf != DROP_RANK && cl.kind == NormalMove) {\r
+ ChessSquare piece = board[rf][ff];\r
+\r
+ if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */\r
+ if(promoChar != NULLCHAR && promoChar != 'x' &&\r
+ promoChar != '+' && promoChar != '=' &&\r
+ ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )\r
+ cl.kind = IllegalMove;\r
+ else if(flags & F_WHITE_ON_MOVE) {\r
+ if( (int) piece < (int) WhiteWazir &&\r
+ (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
+ if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
+ piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
+ else /* promotion optional, default is promote */\r
+ cl.kind = promoChar == '=' ? NormalMove : WhitePromotionQueen;\r
+ \r
+ } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+ NormalMove : IllegalMove;\r
+ } else {\r
+ if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
+ if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
+ piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
+ cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
+ else /* promotion optional, default is promote */\r
+ cl.kind = promoChar == '=' ? NormalMove : BlackPromotionQueen;\r
+\r
+ } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+ NormalMove : IllegalMove;\r
+ }\r
+ }\r
+ } else\r
if (promoChar != NULLCHAR && promoChar != 'x') {\r
if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
cl.kind = \r
cl.kind = IllegalMove;\r
}\r
}\r
+ /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */\r
return cl.kind;\r
}\r
\r
(cl->ftIn == -1 || cl->ftIn == ft)) {\r
\r
cl->count++;\r
- cl->piece = board[rf][ff];\r
+ cl->piece = board[rf][ff];\r
cl->rf = rf;\r
cl->ff = ff;\r
cl->rt = rt;\r
int flags, epfile;\r
DisambiguateClosure *closure;\r
{\r
- int illegal = 0;\r
+ int illegal = 0; char c = closure->promoCharIn;\r
closure->count = 0;\r
closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
closure->kind = ImpossibleMove;\r
return;\r
}\r
}\r
+\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Disambiguate in: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+ closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
+ }\r
+ if(gameInfo.variant == VariantShogi) {\r
+ /* [HGM] Shogi promotions. '=' means defer */\r
+ if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {\r
+ ChessSquare piece = closure->piece;\r
+\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Disambiguate A: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+ closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
+ }\r
+ if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&\r
+ ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) \r
+ closure->kind = IllegalMove;\r
+ else if(flags & F_WHITE_ON_MOVE) {\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Disambiguate B: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+ closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
+ }\r
+ if( (int) piece < (int) WhiteWazir &&\r
+ (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {\r
+ if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||\r
+ piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+ closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;\r
+ else /* promotion optional, default is promote */\r
+ closure->kind = c == '=' ? NormalMove : WhitePromotionQueen;\r
+ \r
+ } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
+ NormalMove : IllegalMove;\r
+ } else {\r
+ if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {\r
+ if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||\r
+ piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */\r
+ closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;\r
+ else /* promotion optional, default is promote */\r
+ closure->kind = c == '=' ? NormalMove : BlackPromotionQueen;\r
+\r
+ } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
+ NormalMove : IllegalMove;\r
+ }\r
+ }\r
+ } else\r
if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
if (closure->kind == WhitePromotionQueen\r
|| closure->kind == BlackPromotionQueen) {\r
closure->kind = IllegalMove;\r
}\r
}\r
- closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Disambiguate C: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+ closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
+ }\r
+ /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */\r
+ if(closure->promoCharIn != '=')\r
+ closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+ else closure->promoChar = '=';\r
if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
if (closure->count > 1) {\r
closure->kind = AmbiguousMove;\r
*/\r
closure->kind = IllegalMove;\r
}\r
+ if(closure->kind == IllegalMove)\r
+ /* [HGM] might be a variant we don't understand, pass on promotion info */\r
+ closure->promoChar = closure->promoCharIn;\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+ closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,closure->promoChar);\r
+ }\r
}\r
\r
\r
\r
if (promoChar == 'x') promoChar = NULLCHAR;\r
piece = board[rf][ff];\r
+\r
+ if (appData.debugMode)\r
+ fprintf(debugFP, "CoordsToAlgebraic, piece=%d\n", (int)piece);\r
switch (piece) {\r
case WhitePawn:\r
case BlackPawn:\r
+ if (appData.debugMode)\r
+ fprintf(debugFP, "CoordsToAlgebraic, Pawn\n");\r
kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
/* Keep short notation if move is illegal only because it\r
else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
}\r
/* Use promotion suffix style "=Q" */\r
- if (promoChar != NULLCHAR && promoChar != 'x') {\r
- *outp++ = '=';\r
- *outp++ = ToUpper(promoChar);\r
- }\r
*outp = NULLCHAR;\r
+ if (promoChar != NULLCHAR) {\r
+ if(gameInfo.variant == VariantShogi) {\r
+ /* [HGM] ... but not in Shogi! */\r
+ *outp++ = promoChar == '=' ? '=' : '+';\r
+ } else {\r
+ *outp++ = '=';\r
+ *outp++ = ToUpper(promoChar);\r
+ }\r
+ *outp = NULLCHAR;\r
+ }\r
AlphaRank(out, 10);\r
return kind;\r
\r
else "N1f3" or "N5xf7",\r
else "Ng1f3" or "Ng5xf7".\r
*/\r
- *outp++ = ToUpper(PieceToChar(piece));\r
- \r
+ if(PieceToChar(piece) == '.') {\r
+ /* [HGM] print nonexistent piece as its demoted version */\r
+ piece = (ChessSquare) (DEMOTED piece);\r
+ if( gameInfo.variant == VariantShogi )\r
+ *outp++ = '+';\r
+ }\r
+ *outp++ = ToUpper(PieceToChar(piece));\r
if (cl.file || (cl.either && !cl.rank)) {\r
*outp++ = ff + AAA;\r
}\r
*outp++ = rt + ONE;\r
else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
*outp = NULLCHAR;\r
+ if (gameInfo.variant == VariantShogi) {\r
+ /* [HGM] in Shogi non-pawns can promote */\r
+ if(flags & F_WHITE_ON_MOVE) {\r
+ if( (int) cl.piece < (int) WhiteWazir &&\r
+ (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
+ if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
+ piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
+ else cl.kind = WhitePromotionQueen; /* promotion optional */\r
+ \r
+ } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+ NormalMove : IllegalMove;\r
+ } else {\r
+ if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
+ if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
+ piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
+ cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
+ else cl.kind = BlackPromotionQueen; /* promotion optional */\r
+ } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+ NormalMove : IllegalMove;\r
+ }\r
+ if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
+ /* for optional promotions append '+' or '=' */\r
+ if(promoChar == '=') {\r
+ *outp++ = '=';\r
+ cl.kind = NormalMove;\r
+ } else *outp++ = '+';\r
+ *outp = NULLCHAR;\r
+ } else if(cl.kind == IllegalMove) {\r
+ /* Illegal move specifies any given promotion */\r
+ if(promoChar != NULLCHAR && promoChar != 'x') {\r
+ *outp++ = '=';\r
+ *outp++ = ToUpper(promoChar);\r
+ *outp = NULLCHAR;\r
+ }\r
+ }\r
+ }\r
AlphaRank(out, 10);\r
return cl.kind;\r
\r
-#ifdef FAIRY\r
- /* [HGM] Always long notation for fairies, don't know how they move */\r
+ /* [HGM] Always long notation for fairies we don't know */\r
case WhiteNightrider:\r
case BlackNightrider:\r
case WhiteGrasshopper:\r
case BlackGrasshopper:\r
-#endif\r
case EmptySquare:\r
/* Moving a nonexistent piece */\r
break;\r