int rf, ff;
int i, j, d, s, fs, rs, rt, ft, m;
int epfile = (signed char)board[EP_STATUS]; // [HGM] gamestate: extract ep status from board
- int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
+ int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1;
for (rf = 0; rf < BOARD_HEIGHT; rf++)
for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
/* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */
case WhiteCardinal:
case BlackCardinal:
+ if(gameInfo.variant == VariantChuChess) goto DragonHorse;
for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
for (s = -2; s <= 2; s += 4) {
rt = rf + s * d;
case SHOGI BlackCardinal:
case SHOGI WhitePCardinal:
case SHOGI BlackPCardinal:
+ DragonHorse:
Bishop(board, flags, rf, ff, callback, closure);
Wazir(board, flags, rf, ff, callback, closure);
break;
/* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */
case WhiteDragon:
case BlackDragon:
+ if(gameInfo.variant == VariantChuChess) goto DragonKing;
for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
for (s = -2; s <= 2; s += 4) {
rt = rf + s * d;
case SHOGI BlackDragon:
case SHOGI WhitePDragon:
case SHOGI BlackPDragon:
+ DragonKing:
Rook(board, flags, rf, ff, callback, closure);
Ferz(board, flags, rf, ff, callback, closure);
break;
{
CheckTestClosure cl;
ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
- ChessSquare captured = EmptySquare, ep;
+ ChessSquare captured = EmptySquare, ep, trampled;
/* Suppress warnings on uninitialized variables */
if(gameInfo.variant == VariantXiangqi)
king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
if(gameInfo.variant == VariantKnightmate)
king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
+ if(gameInfo.variant == VariantChu) { // strictly speaking this is not needed, as Chu officially has no check
+ int r, f, k = king, royals=0, prince = flags & F_WHITE_ON_MOVE ? WhiteMonarch : BlackMonarch;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if(board[r][f] == k || board[r][f] == prince) {
+ if(++royals > 1) return FALSE; // no check if we have two royals (ignores double captureby Lion!)
+ king = board[r][f]; // remember hich one we had
+ }
+ }
+ }
if (rt >= 0) {
if (enPassant) {
captured = board[rf][ft];
board[rf][ft] = EmptySquare;
} else {
- captured = board[rt][ft];
+ captured = board[rt][ft];
+ if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; }
}
if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop
board[rt][ft] = board[rf][ff];
}
ep = board[EP_STATUS];
if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules
- ChessSquare victim = killX < 0 ? EmptySquare : board[killY][killX];
+ ChessSquare victim = killX < 0 ? EmptySquare : trampled;
if( (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) && // capturer is Lion
(ff - ft > 1 || ft - ff > 1 || rf - rt > 1 || rt - rf > 1) && // captures from a distance
(victim == EmptySquare || victim == WhitePawn || victim == BlackPawn) ) // no or worthless 'bridge'
board[rf][ft] = captured;
board[rt][ft] = EmptySquare;
} else {
+ if(killX >= 0) board[killY][killX] = trampled;
board[rt][ft] = captured;
}
board[EP_STATUS] = ep;
return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
}
+int
+HasLion (Board board, int flags)
+{
+ int lion = F_WHITE_ON_MOVE & flags ? WhiteLion : BlackLion;
+ int r, f;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
+ if(board[r][f] == lion) return 1;
+ return 0;
+}
+
ChessMove
LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft)
{ // [HGM] put drop legality testing in separate routine for clarity
}
} else
if (promoChar != NULLCHAR) {
+ if(cl.kind == NormalMove && promoChar == '+') { // allow shogi-style promotion is pieceToChar specifies them
+ ChessSquare piece = board[rf][ff];
+ if(piece < BlackPawn ? piece > WhiteMan : piece > BlackMan) return ImpossibleMove; // already promoted
+ // should test if in zone, really
+ if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight) && HasLion(board, flags))
+ return IllegalMove;
+ if(PieceToChar(PROMOTED piece) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
+ } else
if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
ChessSquare piece = CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar));
if(piece == EmptySquare)
cl.kind = ImpossibleMove; // non-existing piece
- if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
+ if(gameInfo.variant == VariantChuChess && promoChar == 'l' && HasLion(board, flags)) {
+ cl.kind = IllegalMove; // no two Lions
+ } else if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
if(promoChar != PieceToChar(BlackKing)) {
if(CheckTest(board, flags, rf, ff, rt, ft, FALSE)) cl.kind = IllegalMove; // [HGM] spartan: only promotion to King was possible
if(piece == BlackLance) cl.kind = ImpossibleMove;
- } else { // promotion to King allowed only if we do not haave two yet
+ } else { // promotion to King allowed only if we do not have two yet
int r, f, kings = 0;
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) kings += (board[r][f] == BlackKing);
if(kings == 2) cl.kind = IllegalMove;
else if(gameInfo.variant == VariantGiveaway) return MT_STEALMATE; // no check exists, stalemated = win
return inCheck ? MT_CHECKMATE
- : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj || gameInfo.variant == VariantShogi) ?
+ : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj || IS_SHOGI(gameInfo.variant)) ?
MT_STAINMATE : MT_STALEMATE;
}
}
else
c = PieceToChar(BlackQueen);
} else if(c == '=') closure->kind = IllegalMove; // no deferral outside Shogi
+ else if(c == 'l' && gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
+ } else if (c == '+') { // '+' outside shogi, check if pieceToCharTable enabled it
+ ChessSquare p = closure->piece;
+ if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED p) != '+')
+ closure->kind = ImpossibleMove; // used on non-promotable piece
+ else if(gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
} else if (c != NULLCHAR) closure->kind = IllegalMove;
closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal.
/* [HGM] in Shogi non-pawns can promote */
*outp++ = promoChar; // Don't bother to correct move type, return value is never used!
}
- else if (gameInfo.variant != VariantSuper && promoChar &&
+ else if (gameInfo.variant == VariantChuChess && promoChar ||
+ gameInfo.variant != VariantSuper && promoChar &&
(piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn
*outp++ = '=';
*outp++ = ToUpper(promoChar);