BlackMarshall, BlackAngel, BlackBishop, BlackKnight, EmptySquare }
};
+ChessSquare ChuChessArray[2][BOARD_FILES] = {
+ { WhiteMan, WhiteKnight, WhiteBishop, WhiteCardinal, WhiteLion,
+ WhiteQueen, WhiteDragon, WhiteBishop, WhiteKnight, WhiteMan },
+ { BlackMan, BlackKnight, BlackBishop, BlackDragon, BlackQueen,
+ BlackLion, BlackCardinal, BlackBishop, BlackKnight, BlackMan }
+};
+
#ifdef GOTHIC
ChessSquare GothicArray[2][BOARD_FILES] = {
{ WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall,
case VariantGrand: /* should work */
case VariantSpartan: /* should work */
case VariantLion: /* should work */
+ case VariantChuChess: /* should work */
break;
}
}
found = TRUE;
} else
for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {
- if (StrCaseStr(e, variantNames[i])) {
+ if (p = StrCaseStr(e, variantNames[i])) {
+ if(p && i >= VariantShogi && isalpha(p[strlen(variantNames[i])])) continue;
v = (VariantClass) i;
found = TRUE;
break;
char buf[MSG_SIZ];
if(moveList[moveNum][1] == '@' && moveList[moveNum][0] == '@') {
- if(gameInfo.variant == VariantLion || gameInfo.variant == VariantChu) {
+ if(gameInfo.variant == VariantLion || gameInfo.variant == VariantChuChess || gameInfo.variant == VariantChu) {
sprintf(buf, "%s@@@@\n", cps->useUsermove ? "usermove " : "");
SendToProgram(buf, cps);
return;
pieces = lionArray;
SetCharTable(pieceToChar, "PNBRQ................LKpnbrq................lk");
break;
+ case VariantChuChess:
+ pieces = ChuChessArray;
+ gameInfo.boardWidth = 10;
+ gameInfo.boardHeight = 10;
+ SetCharTable(pieceToChar, "PNBRQ.....M.+++......LKpnbrq.....m.+++......lk");
+ break;
case VariantFairy:
pieces = fairyArray;
SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk");
pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
if(pawnRow < 1) pawnRow = 1;
- if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN || gameInfo.variant == VariantGrand) pawnRow = 2;
+ if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN ||
+ gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) pawnRow = 2;
if(gameInfo.variant == VariantChu) pawnRow = 3;
/* User pieceToChar list overrules defaults */
initialPosition[i][j] = s;
if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue;
- initialPosition[gameInfo.variant == VariantGrand][j] = pieces[0][j-gameInfo.holdingsWidth];
+ initialPosition[gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess][j] = pieces[0][j-gameInfo.holdingsWidth];
initialPosition[pawnRow][j] = WhitePawn;
initialPosition[BOARD_HEIGHT-pawnRow-1][j] = gameInfo.variant == VariantSpartan ? BlackLance : BlackPawn;
if(gameInfo.variant == VariantXiangqi) {
initialPosition[BOARD_HEIGHT-1-i][j] = pieces[2*i+1][j-gameInfo.holdingsWidth];
}
}
- if(gameInfo.variant == VariantGrand) {
+ if(gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
if(j==BOARD_LEFT || j>=BOARD_RGHT-1) {
initialPosition[0][j] = WhiteRook;
initialPosition[BOARD_HEIGHT-1][j] = BlackRook;
}
}
- initialPosition[BOARD_HEIGHT-1-(gameInfo.variant == VariantGrand)][j] = pieces[1][j-gameInfo.holdingsWidth];
+ initialPosition[BOARD_HEIGHT-1-(gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess)][j] = pieces[1][j-gameInfo.holdingsWidth];
}
+ if(gameInfo.variant == VariantChuChess) initialPosition[0][BOARD_WIDTH/2] = WhiteKing, initialPosition[BOARD_HEIGHT-1][BOARD_WIDTH/2-1] = BlackKing;
if( (gameInfo.variant == VariantShogi) && !overrule ) {
j=BOARD_LEFT+1;
int p = piece >= BlackPawn ? BLACK_TO_WHITE piece : piece;
promotionZoneSize = BOARD_HEIGHT/3;
highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion;
- } else if(gameInfo.variant == VariantShogi) {
+ } else if(gameInfo.variant == VariantShogi || gameInfo.variant == VariantChuChess) {
promotionZoneSize = BOARD_HEIGHT/3;
highestPromotingPiece = (int)WhiteAlfil;
- } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) {
+ } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
promotionZoneSize = 3;
}
if((int)piece >= BlackPawn) {
if(toY >= promotionZoneSize && fromY >= promotionZoneSize)
return FALSE;
+ if(fromY < promotionZoneSize && gameInfo.variant == VariantChuChess) return FALSE;
highestPromotingPiece = WHITE_TO_BLACK highestPromotingPiece;
} else {
if( toY < BOARD_HEIGHT - promotionZoneSize &&
fromY < BOARD_HEIGHT - promotionZoneSize) return FALSE;
+ if(fromY >= BOARD_HEIGHT - promotionZoneSize && gameInfo.variant == VariantChuChess)
+ return FALSE;
}
if( (int)piece > highestPromotingPiece ) return FALSE; // non-promoting piece
// give caller the default choice even if we will not make it
*promoChoice = ToLower(PieceToChar(defaultPromoChoice));
if(IS_SHOGI(gameInfo.variant)) *promoChoice = (defaultPromoChoice == piece ? '=' : '+');
+ if(gameInfo.variant == VariantChuChess) *promoChoice = (piece == WhitePawn || piece == BlackPawn ? 'q' : '+');
if( sweepSelect && gameInfo.variant != VariantGreat
&& gameInfo.variant != VariantGrand
&& gameInfo.variant != VariantSuper) return FALSE;
gameMode == IcsPlayingBlack && WhiteOnMove(currentMove);
if(appData.testLegality && !premove) {
moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
- fromY, fromX, toY, toX, IS_SHOGI(gameInfo.variant) ? '+' : NULLCHAR);
+ fromY, fromX, toY, toX, IS_SHOGI(gameInfo.variant) || gameInfo.variant == VariantChuChess ? '+' : NULLCHAR);
if(moveType != WhitePromotion && moveType != BlackPromotion)
return FALSE;
}
ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
{
ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
- int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
+ int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1;
/* [HGM] compute & store e.p. status and castling rights for new position */
/* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */
if(promoChar == '+') {
/* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite ordinary Pawn promotion) */
board[toY][toX] = (ChessSquare) (CHUPROMOTED piece);
+ if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight))
+ board[toY][toX] = piece + WhiteLion - WhiteKnight; // adjust Knight promotions to Lion
} else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar
ChessSquare newPiece = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar));
if((newPiece <= WhiteMan || newPiece >= BlackPawn && newPiece <= BlackMan) // unpromoted piece specified
if( v == VariantGreat ) width = 10, holdings = 8;
if( v == VariantSChess ) holdings = 7;
if( v == VariantGrand ) width = 10, height = 10, holdings = 7;
+ if( v == VariantChuChess) width = 10, height = 10;
if( v == VariantChu ) width = 12, height = 12;
return boardWidth >= 0 && boardWidth != width || // -1 is default,
boardHeight >= 0 && boardHeight != height || // and thus by definition OK
{ VariantNoCastle, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("No castle")},
{ VariantCylinder,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Cylinder *")},
{ Variant3Check, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("3-checks")},
-{ VariantBerolina,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Berolina *")},
-{ VariantAtomic, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Atomic")},
-{ VariantTwoKings,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Two kings")},
-{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size (-1 = default for selected variant):")},
+{ VariantBerolina,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("berolina *")},
+{ VariantAtomic, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("atomic")},
+{ VariantTwoKings,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("two kings")},
+{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
+{ VariantSpartan,SAME_ROW, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
+{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size ( -1 = default for selected variant):")},
{ 0, -1, BOARD_RANKS-1, NULL, (void*) &ranksTmp, "", NULL, Spin, N_("Number of Board Ranks:") },
{ 0, -1, BOARD_FILES, NULL, (void*) &filesTmp, "", NULL, Spin, N_("Number of Board Files:") },
{ 0, -1, BOARD_RANKS-1, NULL, (void*) &sizeTmp, "", NULL, Spin, N_("Holdings Size:") },
{ VariantJanus, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Janus (10x8)")},
{ VariantSuicide, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("Suicide")},
{ VariantCapaRandom,SAME_ROW,135,NULL,(void*) &Pick, "#BFBFFF", NULL, Button, N_("CRC (10x8)")},
-{ VariantGiveaway, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("Give-away")},
-{ VariantGrand, SAME_ROW, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("Grand (10x10)")},
-{ VariantLosers, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("Losers")},
-{ VariantShogi, SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("Shogi (9x9)")},
-{ VariantSpartan, 0, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
-{ VariantXiangqi, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")},
+{ VariantGiveaway, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("give-away")},
+{ VariantGrand, SAME_ROW, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("grand (10x10)")},
+{ VariantLosers, 0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("losers")},
+{ VariantShogi, SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("shogi (9x9)")},
{ VariantFairy, 0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")},
-{ VariantCourier, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")},
-//{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
+{ VariantXiangqi, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")},
{ VariantLion, 0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("mighty lion")},
+{ VariantCourier, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")},
+{ VariantChuChess, 0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("chu chess (10x10)")},
{ VariantChu, SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("chu shogi (12x12)")},
+//{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
// optional buttons for engine-defined variants
{ VariantUnknown, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
SetPromo(_("Chancellor"), --count, 'c');
}
SetPromo(_("Queen"), --count, 'q');
+ if(gameInfo.variant == VariantChuChess)
+ SetPromo(_("Lion"), --count, 'l');
}
} else // [HGM] shogi
{
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;
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)) return !HasLion(board, flags);
+ 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));