From 19322454d23ba4bd033d3578978db047bbd49c7d Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Mon, 30 Sep 2013 22:14:15 +0200 Subject: [PATCH] Implement LionChess Add legality testing for Lions, so it ca be played with legality testing on. Cyan markers are now also used in autonomous highlighting, so that double- moving is triggered: A new move type FirstLeg instructs the marker callback to use cyan on Lion contact captures. Igui required a special test, to make XBoard realize the fial square is empty. Implement Lion-capture rules. Forbid Pawn promotion to Lion: The Lion is skipped during the promotion sweep (and it was not in the promotion popp anyway). Chu should not suffer from this, as the piece used as promoted Kylin is not a real Lion (although it looks like one). King is not considered a protector in Mighty-Lion Chess This rule was added to allow trading Lions in the late end-game, to prevent the game from being too drawish. --- backend.c | 32 ++++++++++++++++++++++++++------ common.h | 4 +++- dialogs.c | 3 ++- moves.c | 26 +++++++++++++++++++++++++- moves.h | 8 +++++--- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/backend.c b/backend.c index 5774c4d..001f970 100644 --- a/backend.c +++ b/backend.c @@ -566,6 +566,13 @@ ChessSquare aseanArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj BlackKing, BlackMan, BlackKnight, BlackRook } }; +ChessSquare lionArray[2][BOARD_FILES] = { + { WhiteRook, WhiteLion, WhiteBishop, WhiteQueen, + WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, + { BlackRook, BlackLion, BlackBishop, BlackQueen, + BlackKing, BlackBishop, BlackKnight, BlackRook } +}; + #if (BOARD_FILES>=10) ChessSquare ShogiArray[2][BOARD_FILES] = { @@ -1195,6 +1202,7 @@ InitBackEnd1 () case VariantSChess: /* S-Chess, should work */ case VariantGrand: /* should work */ case VariantSpartan: /* should work */ + case VariantLion: /* should work */ break; } } @@ -5235,7 +5243,7 @@ UploadGameEvent () SendToICS(ics_type == ICS_ICC ? "tag result Game in progress\n" : "commit\n"); } -static int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove +int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove void CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7]) @@ -5289,7 +5297,7 @@ Sweep (int step) else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing; if(!step) step = -1; } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn || - appData.testLegality && promoSweep == king || + appData.testLegality && (promoSweep == king || promoSweep == WhiteLion || promoSweep == BlackLion) || IS_SHOGI(gameInfo.variant) && promoSweep != CHUPROMOTED last && last != CHUPROMOTED promoSweep && last != promoSweep); if(toX >= 0) { int victim = boards[currentMove][toY][toX]; @@ -6031,6 +6039,10 @@ InitPosition (int redraw) pieces = SpartanArray; SetCharTable(pieceToChar, "PNBRQ................K......lwg.....c...h..k"); break; + case VariantLion: + pieces = lionArray; + SetCharTable(pieceToChar, "PNBRQ................LKpnbrq................lk"); + break; case VariantFairy: pieces = fairyArray; SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk"); @@ -7106,10 +7118,10 @@ Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VO { typedef char Markers[BOARD_RANKS][BOARD_FILES]; Markers *m = (Markers *) closure; - if(rf == fromY && ff == fromX) + if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2)) (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare || kind == WhiteCapturesEnPassant - || kind == BlackCapturesEnPassant); + || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0); else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3; } @@ -7488,6 +7500,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) MarkTargetSquares(1); if(x == killX && y == killY) killX = killY = -1; else { killX = x; killY = y; //remeber this square as intermediate + MarkTargetSquares(0); ReportClick("put", x, y); // and inform engine ReportClick("lift", x, y); return; @@ -9639,14 +9652,22 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } piece = board[toY][toX] = (ChessSquare) fromX; } else { + ChessSquare victim; int i; if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something + victim = board[killY][killX], board[killY][killX] = EmptySquare, board[EP_STATUS] = EP_CAPTURE; - if( board[toY][toX] != EmptySquare ) + if( board[toY][toX] != EmptySquare ) { board[EP_STATUS] = EP_CAPTURE; + if( (fromX != toX || fromY != toY) && // not igui! + (captured == WhiteLion && board[fromY][fromX] != BlackLion || + captured == BlackLion && board[fromY][fromX] != WhiteLion ) ) { // [HGM] lion: Chu Lion-capture rules + board[EP_STATUS] = EP_IRON_LION; // non-Lion x Lion: no counter-strike allowed + } + } if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) { if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi ) @@ -9932,7 +9953,6 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) board[BOARD_HEIGHT-1-k][0] = EmptySquare; } } - } /* Updates forwardMostMove */ diff --git a/common.h b/common.h index f06fbcf..3e8adbe 100644 --- a/common.h +++ b/common.h @@ -289,7 +289,7 @@ typedef enum { WhitePromotion, WhiteNonPromotion, BlackPromotion, BlackNonPromotion, WhiteCapturesEnPassant, BlackCapturesEnPassant, - WhiteDrop, BlackDrop, + WhiteDrop, BlackDrop, FirstLeg, NormalMove, AmbiguousMove, IllegalMove, ImpossibleMove, WhiteWins, BlackWins, GameIsDrawn, GameUnfinished, GNUChessGame, XBoardGame, MoveNumberOne, Open, Close, Nothing, @@ -353,6 +353,7 @@ typedef enum { VariantSChess, VariantGrand, VariantSpartan, + VariantLion, VariantUnknown /* Catchall for other unknown variants */ } VariantClass; @@ -401,6 +402,7 @@ typedef enum { "seirawan",\ "grand",\ "spartan",\ + "lion",\ "unknown" \ } diff --git a/dialogs.c b/dialogs.c index 4db3da7..84aaf3a 100644 --- a/dialogs.c +++ b/dialogs.c @@ -447,7 +447,8 @@ static Option variantDescriptors[] = { { VariantXiangqi, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")}, { 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 +//{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment +{ VariantLion, 0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("mighty lion")}, { VariantChu, SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("chu shogi (12x12)")}, // optional buttons for engine-defined variants { VariantUnknown, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, diff --git a/moves.c b/moves.c index 381b188..ad68656 100644 --- a/moves.c +++ b/moves.c @@ -697,6 +697,16 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, } break; + 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 WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere case BlackFalcon: case WhiteCobra: @@ -728,6 +738,8 @@ GenLegalCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt 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) { @@ -972,6 +984,9 @@ CheckTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int r 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 } @@ -987,7 +1002,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant { CheckTestClosure cl; ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing; - ChessSquare captured = EmptySquare; + ChessSquare captured = EmptySquare, ep; /* Suppress warnings on uninitialized variables */ if(gameInfo.variant == VariantXiangqi) @@ -1006,6 +1021,14 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant 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 : board[killY][killX]; + 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 @@ -1042,6 +1065,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant } else { 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 diff --git a/moves.h b/moves.h index 5a7e9ae..bef3073 100644 --- a/moves.h +++ b/moves.h @@ -83,10 +83,12 @@ typedef void (*MoveCallback) P((Board board, int flags, ChessMove kind, #define F_MANDATORY_CAPTURE 0x200 /* Special epfile values. [HGM] positive values are non-reversible moves! */ -#define EP_NONE (-4) /* [HGM] Tricky! order matters: */ -#define EP_UNKNOWN (-1) /* >= EP_UNKNOWN spils rep-draw */ +#define EP_NONE (-6) /* [HGM] Tricky! order matters: */ +#define EP_UNKNOWN (-1) /* >= EP_UNKNOWN spoils rep-draw */ #define EP_CAPTURE (-2) /* <= EP_NONE is reversible move */ #define EP_PAWN_MOVE (-3) +#define EP_IRON_LION (-4) +#define EP_ROYAL_LION (-5) #define EP_REP_DRAW (-15) #define EP_RULE_DRAW (-14) #define EP_INSUF_DRAW (-13) @@ -172,4 +174,4 @@ ChessMove CoordsToAlgebraic P((Board board, int flags, int rf, int ff, int rt, int ft, int promoChar, char out[MOVE_LEN])); -extern int quickFlag; +extern int quickFlag, killX, killY; -- 1.7.0.4