return TRUE;
}
+// [HGM] move generation now based on hierarchy of subroutines for rays and combinations of rays
+
+void
+SlideForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, rt, ft = ff;
+ for (i = 1;; i++) {
+ rt = rf + i;
+ if (rt >= BOARD_HEIGHT) 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;
+ }
+}
+
+void
+SlideBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, rt, ft = ff;
+ for (i = 1;; i++) {
+ rt = rf - i;
+ if (rt < 0) 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;
+ }
+}
+
+void
+SlideVertical (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ SlideForward(board, flags, rf, ff, callback, closure);
+ SlideBackward(board, flags, rf, ff, callback, closure);
+}
+
+void
+SlideSideways (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, s, rt = rf, ft;
+ for(s = -1; s <= 1; s+= 2) {
+ for (i = 1;; i++) {
+ ft = ff + i*s;
+ if (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;
+ }
+ }
+}
+
+void
+SlideDiagForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, s, rt, ft;
+ for(s = -1; s <= 1; s+= 2) {
+ for (i = 1;; i++) {
+ rt = rf + i;
+ ft = ff + i * s;
+ if (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;
+ }
+ }
+}
+
+void
+SlideDiagBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, s, rt, ft;
+ for(s = -1; s <= 1; s+= 2) {
+ for (i = 1;; i++) {
+ rt = rf - i;
+ ft = ff + i * s;
+ if (rt < 0 || 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;
+ }
+ }
+}
+
+void
+Rook (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ SlideSideways(board, flags, rf, ff, callback, closure);
+}
+
+void
+Bishop (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ SlideDiagForward(board, flags, rf, ff, callback, closure);
+ SlideDiagBackward(board, flags, rf, ff, callback, closure);
+}
+
+void
+Sting (Board board, int flags, int rf, int ff, int dy, int dx, MoveCallback callback, VOIDSTAR closure)
+{ // Lion-like move of Horned Falcon and Souring Eagle
+ int ft = ff + dx, rt = rf + dy;
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
+ if (!SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure);
+ ft += dx; rt += dy;
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
+ if (!SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int ft = ff, rt = rf + 1;
+ if (rt >= BOARD_HEIGHT) return;
+ if (SameColor(board[rf][ff], board[rt][ft])) return;
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int ft = ff, rt = rf - 1;
+ if (rt < 0) return;
+ if (SameColor(board[rf][ff], board[rt][ft])) return;
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepSideways (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int ft, rt = rf;
+ ft = ff + 1;
+ if (!(rt >= BOARD_HEIGHT || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ ft = ff - 1;
+ if (!(rt >= BOARD_HEIGHT || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepDiagForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int ft, rt = rf + 1;
+ if (rt >= BOARD_HEIGHT) return;
+ ft = ff + 1;
+ if (!(rt >= BOARD_HEIGHT || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ ft = ff - 1;
+ if (!(rt >= BOARD_HEIGHT || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepDiagBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int ft, rt = rf - 1;
+ if(rt < 0) return;
+ ft = ff + 1;
+ if (!(rt < 0 || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ ft = ff - 1;
+ if (!(rt < 0 || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+}
+
+void
+StepVertical (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ StepForward(board, flags, rf, ff, callback, closure);
+ StepBackward(board, flags, rf, ff, callback, closure);
+}
+
+void
+Ferz (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ StepDiagForward(board, flags, rf, ff, callback, closure);
+ StepDiagBackward(board, flags, rf, ff, callback, closure);
+}
+
+void
+Wazir (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ StepVertical(board, flags, rf, ff, callback, closure);
+ StepSideways(board, flags, rf, ff, callback, closure);
+}
+
+void
+Knight (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
+{
+ int i, j, s, rt, ft;
+ for (i = -1; i <= 1; i += 2)
+ for (j = -1; j <= 1; j += 2)
+ for (s = 1; s <= 2; s++) {
+ rt = rf + i*s;
+ ft = ff + j*(3-s);
+ if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
+ && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)
+ && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ }
+}
/* Call callback once for each pseudo-legal move in the given
position, except castling moves. A move is pseudo-legal if it is
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++) {
if(PieceToChar(piece) == '~')
piece = (ChessSquare) ( DEMOTED piece );
if(filter != EmptySquare && piece != filter) continue;
- if(gameInfo.variant == VariantShogi)
+ if(IS_SHOGI(gameInfo.variant))
piece = (ChessSquare) ( SHOGI piece );
switch ((int)piece) {
case BlackUnicorn:
case WhiteKnight:
case BlackKnight:
- mounted:
for (i = -1; i <= 1; i += 2)
for (j = -1; j <= 1; j += 2)
for (s = 1; s <= 2; s++) {
/* Gold General (and all its promoted versions) . First do the */
/* diagonal forward steps, then proceed as normal Wazir */
- case SHOGI WhiteWazir:
case SHOGI (PROMOTED WhitePawn):
+ if(gameInfo.variant == VariantShogi) goto WhiteGold;
+ case SHOGI (PROMOTED BlackPawn):
+ if(gameInfo.variant == VariantShogi) goto BlackGold;
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ break;
+
case SHOGI (PROMOTED WhiteKnight):
- case SHOGI (PROMOTED WhiteQueen):
- case SHOGI (PROMOTED WhiteFerz):
- for (s = -1; s <= 1; s += 2) {
- if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
- !SameColor(board[rf][ff], board[rf + 1][ff + s])) {
- callback(board, flags, NormalMove,
- rf, ff, rf + 1, ff + s, closure);
- }
- }
- goto finishGold;
+ if(gameInfo.variant == VariantShogi) goto WhiteGold;
+ case SHOGI BlackDrunk:
+ case SHOGI BlackAlfil:
+ Ferz(board, flags, rf, ff, callback, closure);
+ StepSideways(board, flags, rf, ff, callback, closure);
+ StepBackward(board, flags, rf, ff, callback, closure);
+ break;
- case SHOGI BlackWazir:
- case SHOGI (PROMOTED BlackPawn):
case SHOGI (PROMOTED BlackKnight):
+ if(gameInfo.variant == VariantShogi) goto BlackGold;
+ case SHOGI WhiteDrunk:
+ case SHOGI WhiteAlfil:
+ Ferz(board, flags, rf, ff, callback, closure);
+ StepSideways(board, flags, rf, ff, callback, closure);
+ StepForward(board, flags, rf, ff, callback, closure);
+ break;
+
+
+ case SHOGI WhiteStag:
+ case SHOGI BlackStag:
+ if(gameInfo.variant == VariantShogi) goto BlackGold;
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ Ferz(board, flags, rf, ff, callback, closure);
+ StepSideways(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI (PROMOTED WhiteQueen):
+ case SHOGI WhiteTokin:
+ case SHOGI WhiteWazir:
+ WhiteGold:
+ StepDiagForward(board, flags, rf, ff, callback, closure);
+ Wazir(board, flags, rf, ff, callback, closure);
+ break;
+
case SHOGI (PROMOTED BlackQueen):
- case SHOGI (PROMOTED BlackFerz):
- for (s = -1; s <= 1; s += 2) {
- if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
- !SameColor(board[rf][ff], board[rf - 1][ff + s])) {
- callback(board, flags, NormalMove,
- rf, ff, rf - 1, ff + s, closure);
- }
- }
+ case SHOGI BlackTokin:
+ case SHOGI BlackWazir:
+ BlackGold:
+ StepDiagBackward(board, flags, rf, ff, callback, closure);
+ Wazir(board, flags, rf, ff, callback, closure);
+ break;
case WhiteWazir:
case BlackWazir:
- finishGold:
- for (d = 0; d <= 1; d++)
- for (s = -1; s <= 1; s += 2) {
- rt = rf + s * d;
- ft = ff + s * (1 - d);
- if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
- && !SameColor(board[rf][ff], board[rt][ft]) &&
- (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
- callback(board, flags, NormalMove,
- rf, ff, rt, ft, closure);
- }
- break;
+ Wazir(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteMarshall:
+ case SHOGI BlackMarshall:
+ Ferz(board, flags, rf, ff, callback, closure);
+ for (d = 0; d <= 1; d++)
+ 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]) )
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ }
+ break;
+
+ case SHOGI WhiteAngel:
+ case SHOGI BlackAngel:
+ Wazir(board, flags, rf, ff, callback, closure);
case WhiteAlfil:
case BlackAlfil:
&& !SameColor(board[rf][ff], board[rt][ft]))
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
- if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier
- || gameInfo.variant == VariantXiangqi) continue; // classical Alfil
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+ gameInfo.variant == VariantChu || gameInfo.variant == VariantXiangqi) 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)
/* 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;
/* Shogi Dragon Horse has to continue with Wazir after Bishop */
case SHOGI WhiteCardinal:
case SHOGI BlackCardinal:
- m++;
+ case SHOGI WhitePCardinal:
+ case SHOGI BlackPCardinal:
+ DragonHorse:
+ Bishop(board, flags, rf, ff, callback, closure);
+ Wazir(board, flags, rf, ff, callback, closure);
+ break;
/* Capablanca Archbishop continues as Knight */
case WhiteAngel:
case BlackAngel:
- m++;
+ Knight(board, flags, rf, ff, callback, closure);
/* Shogi Bishops are ordinary Bishops */
case SHOGI WhiteBishop:
case SHOGI BlackBishop:
+ case SHOGI WhitePBishop:
+ case SHOGI BlackPBishop:
case WhiteBishop:
case BlackBishop:
- 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;
- }
- if(m==1) goto mounted;
- if(m==2) goto finishGold;
- /* Bishop falls through */
- break;
+ Bishop(board, flags, rf, ff, callback, closure);
+ break;
/* Shogi Lance is unlike anything, and asymmetric at that */
case SHOGI WhiteQueen:
+ if(gameInfo.variant == VariantChu) goto doQueen;
for(i = 1;; i++) {
rt = rf + i;
ft = ff;
break;
case SHOGI BlackQueen:
+ if(gameInfo.variant == VariantChu) goto doQueen;
for(i = 1;; i++) {
rt = rf - i;
ft = ff;
/* 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;
/* Shogi Dragon King has to continue as Ferz after Rook moves */
case SHOGI WhiteDragon:
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;
m++;
/* Capablanca Chancellor sets flag to continue as Knight */
case WhiteMarshall:
case BlackMarshall:
- m++;
- m += (gameInfo.variant == VariantSpartan); // in Spartan Chess Chancellor is used for Dragon King.
+ Rook(board, flags, rf, ff, callback, closure);
+ if(gameInfo.variant == VariantSpartan) // in Spartan Chess Chancellor is used for Dragon King.
+ Ferz(board, flags, rf, ff, callback, closure);
+ else
+ Knight(board, flags, rf, ff, callback, closure);
+ break;
/* Shogi Rooks are ordinary Rooks */
case SHOGI WhiteRook:
case SHOGI BlackRook:
+ case SHOGI WhitePRook:
+ case SHOGI BlackPRook:
case WhiteRook:
case BlackRook:
doRook:
- for (d = 0; d <= 1; d++)
- for (s = -1; s <= 1; s += 2)
- for (i = 1;; i++) {
- rt = rf + (i * s) * d;
- ft = ff + (i * s) * (1 - d);
- 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 || i == rookRange) break;
- }
- if(m==1) goto mounted;
- if(m==2) goto finishSilver;
- break;
+ Rook(board, flags, rf, ff, callback, closure);
+ break;
case WhiteQueen:
case BlackQueen:
- for (rs = -1; rs <= 1; rs++)
- for (fs = -1; fs <= 1; fs++) {
- if (rs == 0 && fs == 0) continue;
- 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;
- }
- }
- break;
+ case SHOGI WhiteMother:
+ case SHOGI BlackMother:
+ doQueen:
+ Rook(board, flags, rf, ff, callback, closure);
+ Bishop(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhitePawn:
+ StepForward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackPawn:
+ StepBackward(board, flags, rf, ff, callback, closure);
+ break;
- /* Shogi Pawn and Silver General: first the Pawn move, */
- /* then the General continues like a Ferz */
case WhiteMan:
if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner;
- case SHOGI WhitePawn:
case SHOGI WhiteFerz:
- if (rf < BOARD_HEIGHT-1 &&
- !SameColor(board[rf][ff], board[rf + 1][ff]) )
- callback(board, flags, NormalMove,
- rf, ff, rf + 1, ff, closure);
- if(piece != SHOGI WhitePawn) goto finishSilver;
- break;
+ Ferz(board, flags, rf, ff, callback, closure);
+ StepForward(board, flags, rf, ff, callback, closure);
+ break;
case BlackMan:
if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner;
- case SHOGI BlackPawn:
case SHOGI BlackFerz:
- if (rf > 0 &&
- !SameColor(board[rf][ff], board[rf - 1][ff]) )
- callback(board, flags, NormalMove,
- rf, ff, rf - 1, ff, closure);
- if(piece == SHOGI BlackPawn) break;
+ StepBackward(board, flags, rf, ff, callback, closure);
case WhiteFerz:
case BlackFerz:
- finishSilver:
/* [HGM] support Shatranj pieces */
- for (rs = -1; rs <= 1; rs += 2)
- for (fs = -1; fs <= 1; fs += 2) {
- rt = rf + rs;
- ft = ff + fs;
- if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
- if (!SameColor(board[rf][ff], board[rt][ft]) &&
- (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
- callback(board, flags, NormalMove,
- rf, ff, rt, ft, closure);
- }
- break;
+ Ferz(board, flags, rf, ff, callback, closure);
+ break;
case WhiteSilver:
case BlackSilver:
- m++; // [HGM] superchess: use for Centaur
+ Knight(board, flags, rf, ff, callback, closure); // [HGM] superchess: use for Centaur
+
commoner:
+ case SHOGI WhiteMonarch:
+ case SHOGI BlackMonarch:
case SHOGI WhiteKing:
case SHOGI BlackKing:
case WhiteKing:
case BlackKing:
-// walking:
- for (i = -1; i <= 1; i++)
- for (j = -1; j <= 1; j++) {
- if (i == 0 && j == 0) continue;
- rt = rf + i;
- ft = ff + j;
- 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);
- }
- if(m==1) goto mounted;
- break;
+ Ferz(board, flags, rf, ff, callback, closure);
+ Wazir(board, flags, rf, ff, callback, closure);
+ break;
case WhiteNightrider:
case BlackNightrider:
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;
+ Bishop(board, flags, rf, ff, callback, closure);
+ Rook(board, flags, rf, ff, callback, closure);
+ Knight(board, flags, rf, ff, callback, closure);
+ break;
// Use Lance as Berolina / Spartan Pawn.
case WhiteLance:
}
break;
+ case SHOGI WhiteNothing:
+ case SHOGI BlackNothing:
+ case SHOGI WhiteLion:
+ case SHOGI BlackLion:
+ case WhiteLion:
+ case BlackLion:
+ for(rt = rf - 2; rt <= rf + 2; rt++) for(ft = ff - 2; ft <= ff + 2; ft++) {
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+ if (!(ff == ft && rf == rt) && SameColor(board[rf][ff], board[rt][ft])) continue;
+ callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove,
+ rf, ff, rt, ft, closure);
+ }
+ break;
+
+ case SHOGI WhiteFalcon:
+ case SHOGI BlackFalcon:
+ case SHOGI WhitePDagger:
+ case SHOGI BlackPDagger:
+ SlideSideways(board, flags, rf, ff, callback, closure);
+ StepVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteCobra:
+ case SHOGI BlackCobra:
+ StepVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI (PROMOTED WhiteFerz):
+ if(gameInfo.variant == VariantShogi) goto WhiteGold;
+ case SHOGI (PROMOTED BlackFerz):
+ if(gameInfo.variant == VariantShogi) goto BlackGold;
+ case SHOGI WhitePSword:
+ case SHOGI BlackPSword:
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ StepSideways(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteUnicorn:
+ case SHOGI BlackUnicorn:
+ Ferz(board, flags, rf, ff, callback, closure);
+ StepVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteMan:
+ StepDiagForward(board, flags, rf, ff, callback, closure);
+ StepVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackMan:
+ StepDiagBackward(board, flags, rf, ff, callback, closure);
+ StepVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteHCrown:
+ case SHOGI BlackHCrown:
+ Bishop(board, flags, rf, ff, callback, closure);
+ SlideSideways(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteCrown:
+ case SHOGI BlackCrown:
+ Bishop(board, flags, rf, ff, callback, closure);
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteHorned:
+ Sting(board, flags, rf, ff, 1, 0, callback, closure);
+ callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
+ if(killX >= 0) break;
+ Bishop(board, flags, rf, ff, callback, closure);
+ SlideSideways(board, flags, rf, ff, callback, closure);
+ SlideBackward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackHorned:
+ Sting(board, flags, rf, ff, -1, 0, callback, closure);
+ callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
+ if(killX >= 0) break;
+ Bishop(board, flags, rf, ff, callback, closure);
+ SlideSideways(board, flags, rf, ff, callback, closure);
+ SlideForward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteEagle:
+ Sting(board, flags, rf, ff, 1, 1, callback, closure);
+ Sting(board, flags, rf, ff, 1, -1, callback, closure);
+ callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
+ if(killX >= 0) break;
+ Rook(board, flags, rf, ff, callback, closure);
+ SlideDiagBackward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackEagle:
+ Sting(board, flags, rf, ff, -1, 1, callback, closure);
+ Sting(board, flags, rf, ff, -1, -1, callback, closure);
+ callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
+ if(killX >= 0) break;
+ Rook(board, flags, rf, ff, callback, closure);
+ SlideDiagForward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteDolphin:
+ case SHOGI BlackHorse:
+ SlideDiagBackward(board, flags, rf, ff, callback, closure);
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackDolphin:
+ case SHOGI WhiteHorse:
+ SlideDiagForward(board, flags, rf, ff, callback, closure);
+ SlideVertical(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI WhiteLance:
+ SlideForward(board, flags, rf, ff, callback, closure);
+ break;
+
+ case SHOGI BlackLance:
+ SlideBackward(board, flags, rf, ff, callback, closure);
+ break;
+
case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere
case BlackFalcon:
case WhiteCobra:
if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square
+ if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion
+
if (!(flags & F_IGNORE_CHECK) ) {
int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion);
if(promo) {
cl->check++;
xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1)
}
+ if( board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)
+ && (gameInfo.variant != VariantLion || board[rf][ff] != WhiteKing && board[rf][ff] != BlackKing) )
+ cl->check++; // [HGM] lion: forbidden counterstrike against Lion equated to putting yourself in check
}
{
CheckTestClosure cl;
ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
- ChessSquare captured = EmptySquare;
+ ChessSquare captured = EmptySquare, ep, trampled;
/* Suppress warnings on uninitialized variables */
if(gameInfo.variant == VariantXiangqi)
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];
board[rf][ff] = EmptySquare;
}
+ ep = board[EP_STATUS];
+ if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules
+ 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[EP_STATUS] = EP_ROYAL_LION; // on distant Lion x Lion victim must not be pseudo-legally protected
+ }
}
/* For compatibility with ICS wild 9, we scan the board in the
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
if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
}
} else
+ if(gameInfo.variant == VariantChu) {
+ if(cl.kind != NormalMove || promoChar == NULLCHAR || promoChar == '=') return cl.kind;
+ if(promoChar != '+')
+ return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove;
+ if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') return ImpossibleMove;
+ return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
+ } else
if(gameInfo.variant == VariantShogi) {
/* [HGM] Shogi promotions. '=' means defer */
if(rf != DROP_RANK && cl.kind == NormalMove) {
}
} 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;
if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
}
} else
+ if(gameInfo.variant == VariantChu) {
+ if(c == '+') closure->kind = (flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion); // for now, accept any
+ } 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) {
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.
/* Use promotion suffix style "=Q" */
*outp = NULLCHAR;
if (promoChar != NULLCHAR) {
- if(gameInfo.variant == VariantShogi) {
+ if(IS_SHOGI(gameInfo.variant)) {
/* [HGM] ... but not in Shogi! */
*outp++ = promoChar == '=' ? '=' : '+';
} else {
*/
if( c == '~' || c == '+') {
/* [HGM] print nonexistent piece as its demoted version */
- piece = (ChessSquare) (DEMOTED piece);
+ piece = (ChessSquare) (DEMOTED piece - 11*(gameInfo.variant == VariantChu));
}
if(c=='+') *outp++ = c;
*outp++ = ToUpper(PieceToChar(piece));
if(rt+ONE <= '9')
*outp++ = rt + ONE;
else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
- if (gameInfo.variant == VariantShogi) {
+ if (IS_SHOGI(gameInfo.variant)) {
/* [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);