for (rf = 0; rf < BOARD_HEIGHT; rf++)
for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
ChessSquare piece;
+ int rookRange = 1000;
if (flags & F_WHITE_ON_MOVE) {
if (!WhitePiece(board[rf][ff])) continue;
&& !SameColor(board[rf][ff], board[rt][ft]))
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
- if(gameInfo.variant != VariantFairy && gameInfo.variant != VariantGreat) continue;
+ if(gameInfo.variant == VariantShatranj && gameInfo.variant == VariantCourier) continue; // classical Alfil
rt = rf + rs; // in unknown variant we assume Modern Elephant, which can also do one step
ft = ff + fs;
if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
}
+ if(gameInfo.variant == VariantSpartan)
+ for(fs = -1; fs <= 1; fs += 2) {
+ ft = ff + fs;
+ if (!(ft < BOARD_LEFT || ft >= BOARD_RGHT) && board[rf][ft] == EmptySquare)
+ callback(board, flags, NormalMove, rf, ff, rf, ft, closure);
+ }
break;
+ /* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */
+ case WhiteCardinal:
+ case BlackCardinal:
+ for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
+ for (s = -2; s <= 2; s += 4) {
+ rt = rf + s * d;
+ ft = ff + s * (1 - d);
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+ if (SameColor(board[rf][ff], board[rt][ft])) continue;
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ }
+
/* Shogi Dragon Horse has to continue with Wazir after Bishop */
case SHOGI WhiteCardinal:
case SHOGI BlackCardinal:
if (SameColor(board[rf][ff], board[rt][ft])) continue;
callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
}
+ if(gameInfo.variant == VariantSpartan) rookRange = 2; // in Spartan Chess restrict range to modern Dababba
goto doRook;
/* Shogi Dragon King has to continue as Ferz after Rook moves */
case WhiteMarshall:
case BlackMarshall:
m++;
+ m += (gameInfo.variant == VariantSpartan); // in Spartan Chess Chancellor is used for Dragon King.
/* Shogi Rooks are ordinary Rooks */
case SHOGI WhiteRook:
if (SameColor(board[rf][ff], board[rt][ft])) break;
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
- if (board[rt][ft] != EmptySquare) break;
+ if (board[rt][ft] != EmptySquare || i == rookRange) break;
}
if(m==1) goto mounted;
if(m==2) goto finishSilver;
}
break;
+ Amazon:
+ /* First do Bishop,then continue like Chancellor */
+ for (rs = -1; rs <= 1; rs += 2)
+ for (fs = -1; fs <= 1; fs += 2)
+ for (i = 1;; i++) {
+ rt = rf + (i * rs);
+ ft = ff + (i * fs);
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+ if (SameColor(board[rf][ff], board[rt][ft])) break;
+ callback(board, flags, NormalMove,
+ rf, ff, rt, ft, closure);
+ if (board[rt][ft] != EmptySquare) break;
+ }
+ m++;
+ goto doRook;
+
// Use Lance as Berolina / Spartan Pawn.
case WhiteLance:
+ if(gameInfo.variant == VariantSuper) goto Amazon;
if (rf < BOARD_HEIGHT-1 && BlackPiece(board[rf + 1][ff]))
callback(board, flags,
rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
break;
case BlackLance:
+ if(gameInfo.variant == VariantSuper) goto Amazon;
if (rf > 0 && WhitePiece(board[rf - 1][ff]))
callback(board, flags,
rf <= promoRank ? BlackPromotion : NormalMove,
VOIDSTAR closure;
{
GenLegalClosure cl;
- int ff, ft, k, left, right;
+ int ff, ft, k, left, right, swap;
int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING];
}
}
- if(flags & F_FRC_TYPE_CASTLING) {
+ if((swap = gameInfo.variant == VariantSChess) || flags & F_FRC_TYPE_CASTLING) {
/* generate all potential FRC castling moves (KxR), ignoring flags */
/* [HGM] test if the Rooks we find have castling rights */
+ /* In S-Chess we generate RxK for allowed castlings, for gating at Rook square */
if ((flags & F_WHITE_ON_MOVE) != 0) {
for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[0][ft] == WhiteRook)
- callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
+ callback(board, flags, WhiteHSideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
ft = castlingRights[1]; /* Rook file if we have A-side rights */
left = BOARD_LEFT+2;
for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[0][ft] == WhiteRook)
- callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
+ callback(board, flags, WhiteASideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
}
} else {
ff = castlingRights[5]; /* King file if we have any rights */
for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
- callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+ callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : ft, closure);
ft = castlingRights[4]; /* Rook file if we have A-side rights */
left = BOARD_LEFT+2;
for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
- callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+ callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : ft, closure);
}
}
/* For compatibility with ICS wild 9, we scan the board in the
order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
and we test only whether that one is in check. */
- cl.check = 0;
for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)
for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {
if (board[cl.rking][cl.fking] == king) {
board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )
cl.check++;
}
-
+ cl.check = 0;
GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl);
- goto undo_move; /* 2-level break */
+ if(gameInfo.variant != VariantSpartan || cl.check == 0) // in Spartan Chess go on to test if other King is checked too
+ goto undo_move; /* 2-level break */
}
}
if(board[r][ft] == piece) return IllegalMove; // or there already is a Pawn in file
// should still test if we mate with this Pawn
}
+ } else if(gameInfo.variant == VariantSChess) { // only back-rank drops
+ if (rt != (piece < BlackPawn ? 0 : BOARD_HEIGHT-1)) return IllegalMove;
} else {
if( (piece == WhitePawn || piece == BlackPawn) &&
(rt == 0 || rt == BOARD_HEIGHT -1 ) )
return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
if(promoChar == 'x') promoChar = NULLCHAR; // [HGM] is this ever the case?
+ if(gameInfo.variant == VariantSChess && promoChar && promoChar != '=' && board[rf][ff] != WhitePawn && board[rf][ff] != BlackPawn) {
+ if(board[rf][ff] < BlackPawn) { // white
+ if(rf != 0) return IllegalMove; // must be on back rank
+ if(board[PieceToNumber(CharToPiece(ToUpper(promoChar)))][BOARD_WIDTH-2] == 0) return ImpossibleMove;// must be in stock
+ } else {
+ if(rf != BOARD_HEIGHT-1) return IllegalMove;
+ if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
+ }
+ } else
if(gameInfo.variant == VariantShogi) {
/* [HGM] Shogi promotions. '=' means defer */
if(rf != DROP_RANK && cl.kind == NormalMove) {
if (cl.count > 0) {
return inCheck ? MT_CHECK : MT_NONE;
} else {
- if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper || gameInfo.variant != VariantGreat) { // drop game
+ if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat) { // drop game
int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0;
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) if(board[r][f] == EmptySquare) // all empty squares
for(n=0; n<BOARD_HEIGHT; n++) // all pieces in hand
if(board[n][holdings] != EmptySquare) {
int moveType = LegalDrop(board, flags, board[n][holdings], r, f);
- if(moveType == WhiteDrop || moveType == BlackDrop) return MT_CHECK; // we can resolve check by legal drop
+ if(moveType == WhiteDrop || moveType == BlackDrop) return (inCheck ? MT_CHECK : MT_NONE); // we have legal drop
}
}
if(gameInfo.variant == VariantSuicide) // [HGM] losers: always stalemate, since no check, but result varies
}
if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
+ if(gameInfo.variant == VariantSChess && c && c != '=' && closure->piece != WhitePawn && closure->piece != BlackPawn) {
+ if(closure->piece < BlackPawn) { // white
+ if(closure->rf != 0) closure->kind = IllegalMove; // must be on back rank
+ if(board[PieceToNumber(CharToPiece(ToUpper(c)))][BOARD_WIDTH-2] == 0) closure->kind = ImpossibleMove;// must be in stock
+ } else {
+ if(closure->rf != BOARD_HEIGHT-1) closure->kind = IllegalMove;
+ if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
+ }
+ } else
if(gameInfo.variant == VariantShogi) {
/* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */
if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
(ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
- safeStrCpy(out, "O-O", MOVE_LEN);
+ snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
else
- safeStrCpy(out, "O-O-O", MOVE_LEN);
+ snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
/* This notation is always unambiguous, unless there are
kings on both the d and e files, with "wild castling"
/* [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 &&
+ (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn
+ *outp++ = '=';
+ *outp++ = ToUpper(promoChar);
+ }
+ else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating
+ *outp++ = '/';
+ *outp++ = ToUpper(promoChar);
+ }
*outp = NULLCHAR;
return cl.kind;