From: H.G. Muller Date: Thu, 1 Dec 2011 20:47:24 +0000 (+0100) Subject: Implement Spartan Chess X-Git-Url: http://winboard.nl/cgi-bin?p=capablanca.git;a=commitdiff_plain;h=15d6762279fb7e4c1fecc81699507d9011287779 Implement Spartan Chess This required new pieces, their parsing in algebraic moves and promotions, a lot of promotion code because Hoplites can promote, implementation of the duple-check rule by letting in_check recursively call itself after abdicating the first king, making the test for nr of kings less critical, and choosing a promotion piece in the mate test (because promotion to K could solve the mate). --- diff --git a/lasker-2.2.3/data/boards/spartan/0 b/lasker-2.2.3/data/boards/spartan/0 new file mode 100644 index 0000000..bbdf487 --- /dev/null +++ b/lasker-2.2.3/data/boards/spartan/0 @@ -0,0 +1,3 @@ +S 8x8 +W: P a2 b2 c2 d2 e2 f2 g2 h2 N b1 g1 B c1 f1 Q d1 K e1 R a1 h1 +B: v a7 b7 c7 d7 e7 f7 g7 h7 K c8 f8 y d8 e8 Y b8 X g8 x a8 h8 diff --git a/lasker-2.2.3/src/Makefile.in b/lasker-2.2.3/src/Makefile.in index b0aff55..61a1292 100644 --- a/lasker-2.2.3/src/Makefile.in +++ b/lasker-2.2.3/src/Makefile.in @@ -142,6 +142,7 @@ install: $(ALL) install -d -m0755 ${CHESSDDIR}/data/boards/fairy install -d -m0755 ${CHESSDDIR}/data/boards/great install -d -m0755 ${CHESSDDIR}/data/boards/seirawan + install -d -m0755 ${CHESSDDIR}/data/boards/spartan install -d -m0755 ${CHESSDDIR}/games/history install -d -m0755 ${CHESSDDIR}/games/journal install -d -m0755 ${CHESSDDIR}/games/adjourned @@ -168,6 +169,7 @@ install: $(ALL) cp -u ${srcdir}/../data/boards/great/* ${CHESSDDIR}/data/boards/great cp -u ${srcdir}/../data/boards/caparandom/* ${CHESSDDIR}/data/boards/caparandom cp -u ${srcdir}/../data/boards/seirawan/* ${CHESSDDIR}/data/boards/seirawan + cp -u ${srcdir}/../data/boards/seirawan/* ${CHESSDDIR}/data/boards/spartan perl -e 'mkdir("${CHESSDDIR}/players/$$_",0755) for ("a".."z")' perl -e 'mkdir("${CHESSDDIR}/games/history/$$_",0755) for ("0".."99")' perl -e 'mkdir("${CHESSDDIR}/games/journal/$$_",0755) for ("a".."z")' diff --git a/lasker-2.2.3/src/algcheck.c b/lasker-2.2.3/src/algcheck.c index 33f6b28..219b5de 100644 --- a/lasker-2.2.3/src/algcheck.c +++ b/lasker-2.2.3/src/algcheck.c @@ -248,7 +248,8 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move } if(gs->drops != 2 || (gs->onMove == WHITE ? 0 : gs->ranks-1) != mt->fromRank) { // [HGM] always accept if backrank mover in Seirawan - if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) { + if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN && + piecetype(gs->board[mt->fromFile][mt->fromRank]) != HOPLITE) { return; } if (mt->toRank < gs->ranks - gs->promoZone && mt->toRank >= gs->promoZone) { @@ -264,6 +265,7 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move piece = QUEEN; break; case 'c': + if(piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) piece = CAPTAIN; else if(!gs->capablancaPieces) return; // [HGM] should make variant-dependent piece mask piece = MARSHALL; break; @@ -287,14 +289,24 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move break; // Superchess promotons: filtered out later by promoType case 'g': + if(piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) piece = GENERAL; else piece = MASTODON; break; case 'o': piece = SQUIRREL; break; case 'w': + if(piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) piece = WARLORD; else piece = WOODY; break; + case 'k': + if(piecetype(gs->board[mt->fromFile][mt->fromRank]) != HOPLITE) return; + piece = KING; + break; + case 'l': + if(piecetype(gs->board[mt->fromFile][mt->fromRank]) != HOPLITE) return; + piece = LIEUTENANT; + break; case 'v': piece = CENTAUR; break; @@ -568,6 +580,7 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case CARDINAL: strcpy(mStr, "A"); break; + case CAPTAIN: case CANNON: case MARSHALL: strcpy(mStr, "C"); @@ -590,6 +603,7 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case FERZ2: strcpy(mStr, "F"); break; + case WARLORD: case WOODY: case WAZIR: strcpy(mStr, "W"); @@ -603,6 +617,7 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case HORSE: case DRAGONHORSE: case HAWK: + case HOPLITE: strcpy(mStr, "H"); break; case HONORABLEHORSE: @@ -611,6 +626,7 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case DRAGONKING: strcpy(mStr, "D"); break; + case LIEUTENANT: case LANCE: strcpy(mStr, "L"); break; @@ -619,6 +635,7 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) strcpy(mStr, "S"); break; case MASTODON: + case GENERAL: case GOLD: strcpy(mStr, "G"); break; @@ -697,9 +714,12 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9)); strcat(mStr, tmp); suffix: - if ((piece == PAWN || gs->promoType == 3 || gs->drops == 2) && (mt->piecePromotionTo != NOPIECE)) { + if ((piece == PAWN || piece == HOPLITE || gs->promoType == 3 || gs->drops == 2) && (mt->piecePromotionTo != NOPIECE)) { strcat(mStr, "="); /* = before promoting piece */ switch (piecetype(abs(mt->piecePromotionTo))) { + case KING: + strcat(mStr, "K"); + break; case KNIGHT: strcat(mStr, "N"); break; @@ -713,6 +733,7 @@ suffix: strcat(mStr, "A"); break; case MARSHALL: + case CAPTAIN: strcat(mStr, "C"); break; case MAN: @@ -724,6 +745,7 @@ suffix: case FERZ2: strcat(mStr, "F"); break; + case WARLORD: case WOODY: strcat(mStr, "W"); break; @@ -741,8 +763,7 @@ suffix: strcat(mStr, "O"); break; case MASTODON: - strcat(mStr, "G"); - break; + case GENERAL: case GOLD: // [HGM] Shogi promotions: avoid use of '+' strcat(mStr, "G"); break; @@ -753,6 +774,9 @@ suffix: case DRAGONKING: strcat(mStr, "D"); break; + case LIEUTENANT: + strcat(mStr, "L"); + break; default: break; } diff --git a/lasker-2.2.3/src/board.c b/lasker-2.2.3/src/board.c index 40e7037..f2fa5f0 100644 --- a/lasker-2.2.3/src/board.c +++ b/lasker-2.2.3/src/board.c @@ -24,11 +24,14 @@ const char *wpstring[] = {" ", "P", "N", "B", "R", "A", "C", "M", "Q", "E", "B", "Q", "W", "H", "N", "D", "H", "L", - "C", "S", "G", "H", "A", "F", "E", "H", "M", "S", "E", "W", "O", "G", "V", "S", "E", "A", "K", "H", "E"}; + "C", "S", "G", "H", "A", "F", "E", "H", "M", "S", "E", "W", "O", "G", "V", "S", "E", "A", + "K", "H", "E", "W", "G", "L", "C", "H"}; const char *bpstring[] = {" ", "p", "n", "b", "r", "a", "c", "m", "q", "e", "b", "q", "w", "h", "n", "d", "h", "l", - "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a", "k", "h", "e"}; + "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a", + "k", "h", "e", "w", "g", "l", "c", "h"}; -int pieceValues[PIECES] = {0, 1, 3, 3, 5, 8, 9, 3, 9, 1, 1, 2, 2, 2, 1, 6, 5, 2, 3, 3, 3, 1, 5, 2, 1, 7, 7, 3, 3, 3, 7, 7, 7, 8, 9, 12, 0, 8, 9}; +int pieceValues[PIECES] = {0, 1, 3, 3, 5, 8, 9, 3, 9, 1, 1, 2, 2, 2, 1, 6, 5, 2, 3, 3, 3, 1, 5, 2, 1, 7, 7, 3, 3, 3, 7, 7, 7, 8, 9, 12, + 0, 8, 9, 8, 7, 3, 3, 1}; static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11); #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0) @@ -574,10 +577,12 @@ static int style1(struct game_state_t *b, struct move_t *ml) { static const char *wp[] = {" |", " P |", " N |", " B |", " R |", " A |", " C |", " M |", " Q |", " E |", " B |", " Q |", " W |", " H |", " N |", " D |", " H |", " L |", " C |", " S |", " G |", " H |", " A |", " F |", - " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", " K |", " H |", " E |"}; + " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", + " K |", " H |", " E |", " W |", " G |", " L |", " C |", " H |"}; static const char *bp[] = {" |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|", " *W|", " *H|", " *N|", " *D|", " *H|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|", - " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", " *K|", " *H|", " *E|"}; + " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", + " *K|", " *H|", " *E|", " *W|", " *G|", " *L|", " *C|", " *H|"}; static char *wsqr = ""; static char *bsqr = ""; static char *top = "\t---------------------------------\n"; @@ -595,10 +600,12 @@ static int style2(struct game_state_t *b, struct move_t *ml) { static const char *wp[] = {"- ", "P ", "N ", "B ", "R ", "A ", "C ", "M ", "Q ", "E ", "B ", "Q ", "W ", "H ", "N ", "D ", "H ", "L ", "C ", "S ", "G ", "H ", "A ", "F ", - "E ", "H ", "M ", "S ", "E ", "W ", "O ", "G ", "V ", "S ", "E ", "A ", "K ", "H ", "E "}; + "E ", "H ", "M ", "S ", "E ", "W ", "O ", "G ", "V ", "S ", "E ", "A ", + "K ", "H ", "E ", "W ", "G ", "L ", "C ", "H "}; static const char *bp[] = {"+ ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ", "w' ", "h' ", "n' ", "d' ", "h' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ", - "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", "k' ", "h' ", "e' "}; + "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", + "k' ", "h' ", "e' ", "w' ", "g' ", "l' ", "c' ", "h' "}; static char *wsqr = ""; static char *bsqr = ""; static char *top = ""; @@ -616,10 +623,12 @@ static int style3(struct game_state_t *b, struct move_t *ml) { static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ", - " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K ", " H ", " E "}; + " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", + " K ", " H ", " E ", " W ", " G ", " L ", " C ", " H "}; static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F", - " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K", " *H", " *E"}; + " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", + " *K", " *H", " *E", " *W", " *G", " *L", " *C", " *H"}; static char *wsqr = "\033[0m"; static char *bsqr = "\033[7m"; static char *top = "\t+------------------------+\n"; @@ -637,10 +646,12 @@ static int style4(struct game_state_t *b, struct move_t *ml) { static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ", - " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K ", " H ", " E "}; + " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", + " K ", " H ", " E ", " W ", " G ", " L ", " C ", " H "}; static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F", - " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K", " *H", " *E"}; + " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", + " *K", " *H", " *E", " *W", " *G", " *L", " *C", " *H"}; static char *wsqr = "\033[7m"; static char *bsqr = "\033[0m"; static char *top = "\t+------------------------+\n"; @@ -659,11 +670,13 @@ static int style5(struct game_state_t *b, struct move_t *ml) static const char *wp[] = {" ", " o ", " :N:", " ", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!", " ", " {Q}", " .W.", " :H:", " :N:", " ", " |D|", " |L|", " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:", - " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", " =K=", " (H)", " [E]"}; + " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", + " =K=", " (H)", " [E]", " (W)", " [G]", " ", " |C|", " h "}; static const char *bp[] = {" ", " p ", " :n:", " ", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!", " ", " {q}", " .w.", " :h:", " :n:", " ", " |d|", " |l|", " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:", - " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", " =k=", " (f)", " [e]"}; + " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", + " =k=", " (f)", " [e]", " (w)", " [g]", " ", " |c|", " h "}; static char *wsqr = ""; static char *bsqr = ""; static char *top = " . . . . . . . . .\n"; @@ -682,11 +695,13 @@ static int style6(struct game_state_t *b, struct move_t *ml) static const char *wp[] = {" |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |", " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WD |", " WH |", " WL |", " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |", - " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", " WK |", " WH |", " WE |"}; + " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", + " WK |", " WH |", " WE |", " WW |", " WG |", " WL |", " WC |", " Wh |"}; static const char *bp[] = {" |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |", " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BD |", " BH |", " BL |", " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |", - " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", " BK |", " BH |", " BE |"}; + " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", + " BK |", " BH |", " BE |", " BW |", " BG |", " BL |", " BC |", " Bh |"}; static char *wsqr = ""; static char *bsqr = ""; static char *top = "\t-----------------------------------------\n"; @@ -704,9 +719,11 @@ static int style6(struct game_state_t *b, struct move_t *ml) static int style7(struct game_state_t *b, struct move_t *ml) { static const char *wp[] = {" ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " D", " H", " L", - " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", " K", " H", " E"}; + " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", + " K", " H", " E", " W", " G", " L", " C", " H"}; static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " d", " h", " l", - " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k", " h", " e"}; + " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", + " k", " h", " e", " w", " g", " l", " c", " h"}; static char *wsqr = ""; static char *bsqr = ""; static char *top = "\t:::::::::::::::::::::\n"; @@ -1081,110 +1098,125 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) onNewLine = 0; } else { switch (c) { - case 'P': - onPiece = PAWN; - break; - case 'R': - onPiece = ROOK; - break; - case 'N': - onPiece = KNIGHT; + case 'A': + onPiece = CARDINAL; break; case 'B': onPiece = BISHOP; break; - case 'A': - onPiece = CARDINAL; - break; case 'C': onPiece = MARSHALL; break; - case 'M': - onPiece = MAN; - break; - case 'Q': - onPiece = QUEEN; - break; - case 'T': - onPiece = ELEPHANT; + case 'D': + onPiece = SELEPHANT; break; case 'E': onPiece = ALFIL; break; - case 't': - onPiece = ALFIL2; - break; - case 'q': - onPiece = FERZ; - break; case 'F': onPiece = FERZ2; break; - case 'W': - onPiece = WAZIR; + case 'G': + onPiece = GOLD; break; - case 'w': - onPiece = WOODY; + case 'H': + onPiece = HORSE; break; - case 'p': - onPiece = PRIESTESS; + case 'I': + onPiece = DRAGONHORSE; break; - case 'r': - onPiece = MINISTER; + case 'J': + onPiece = DRAGONKING; break; - case 'z': - onPiece = MAN2; + case 'K': + onPiece = KING; break; - case 'u': - onPiece = NIGHTRIDER; + case 'L': + onPiece = LANCE; break; - case 'o': - onPiece = MODERNELEPHANT; + case 'M': + onPiece = MAN; break; - case 's': - onPiece = MASTODON; + case 'N': + onPiece = KNIGHT; break; - case 'Z': - onPiece = AMAZON; + case 'O': + onPiece = CANNON; + break; + case 'P': + onPiece = PAWN; + break; + case 'Q': + onPiece = QUEEN; + break; + case 'R': + onPiece = ROOK; + break; + case 'S': + onPiece = SILVER; + break; + case 'T': + onPiece = ELEPHANT; + break; + case 'U': + onPiece = HAWK; break; case 'V': onPiece = CENTAUR; break; - case 'H': - onPiece = HORSE; + case 'W': + onPiece = WAZIR; + break; + case 'X': + onPiece = WARLORD; + break; + case 'Y': + onPiece = GENERAL; + break; + case 'Z': + onPiece = AMAZON; + break; + case 'm': + onPiece = MANDARIN; break; case 'n': onPiece = HONORABLEHORSE; break; - case 'J': - onPiece = DRAGONKING; + case 'o': + onPiece = MODERNELEPHANT; break; - case 'I': - onPiece = DRAGONHORSE; + case 'p': + onPiece = PRIESTESS; break; - case 'L': - onPiece = LANCE; + case 'q': + onPiece = FERZ; break; - case 'O': - onPiece = CANNON; + case 'r': + onPiece = MINISTER; break; - case 'S': - onPiece = SILVER; + case 's': + onPiece = MASTODON; break; - case 'G': - onPiece = GOLD; + case 't': + onPiece = ALFIL2; break; - case 'm': - onPiece = MANDARIN; + case 'u': + onPiece = NIGHTRIDER; break; - case 'K': - onPiece = KING; + case 'v': + onPiece = HOPLITE; break; - case 'D': - onPiece = SELEPHANT; + case 'w': + onPiece = WOODY; break; - case 'U': - onPiece = HAWK; + case 'x': + onPiece = LIEUTENANT; + break; + case 'y': + onPiece = CAPTAIN; + break; + case 'z': + onPiece = MAN2; break; case 'a': case 'b': diff --git a/lasker-2.2.3/src/board.h b/lasker-2.2.3/src/board.h index 611ff80..461fec1 100644 --- a/lasker-2.2.3/src/board.h +++ b/lasker-2.2.3/src/board.h @@ -67,7 +67,12 @@ #define KING 36 #define HAWK 37 #define SELEPHANT 38 -#define PIECES 39 +#define WARLORD 39 +#define GENERAL 40 +#define LIEUTENANT 41 +#define CAPTAIN 42 +#define HOPLITE 43 +#define PIECES 44 #define MAX_BOARD_STRING_LENGTH 1280 /* Abitrarily 80 * 16 */ #define MAX_STYLES 13 @@ -145,6 +150,11 @@ #define B_NIGHTRIDER (NIGHTRIDER | BLACK) #define B_HAWK (HAWK | BLACK) #define B_SELEPHANT (SELEPHANT | BLACK) +#define B_WARLORD (WARLORD | BLACK) +#define B_GENERAL (GENERAL | BLACK) +#define B_LIEUTENANT (LIEUTENANT | BLACK) +#define B_CAPTAIN (CAPTAIN | BLACK) +#define B_HOPLITE (HOPLITE | BLACK) #define isblack(p) ((p) & BLACK) #define iswhite(p) (!isblack(p)) diff --git a/lasker-2.2.3/src/gamedb.c b/lasker-2.2.3/src/gamedb.c index becb7a0..da255dc 100644 --- a/lasker-2.2.3/src/gamedb.c +++ b/lasker-2.2.3/src/gamedb.c @@ -723,6 +723,19 @@ int CharToPiece(char c, char *variant) case 'v': return B_CENTAUR; } + } else if(!strcmp(variant, "spartan")) { + switch(c) { + case 'w': + return B_WARLORD; + case 'g': + return B_GENERAL; + case 'l': + return B_LIEUTENANT; + case 'c': + return B_CAPTAIN; + case 'h': + return B_HOPLITE; + } } } switch (c) { @@ -808,6 +821,7 @@ char PieceToChar(int piece) case W_CANNON: case W_MARSHALL: return 'C'; + case B_CAPTAIN: case B_CANNON: case B_MARSHALL: return 'c'; @@ -844,6 +858,7 @@ char PieceToChar(int piece) case W_WAZIR: case W_WOODY: return 'W'; + case B_WARLORD: case B_WAZIR: case B_WOODY: return 'w'; @@ -854,6 +869,7 @@ char PieceToChar(int piece) return 'H'; case B_HAWK: case B_HORSE: + case B_HOPLITE: case B_PRIESTESS: case B_NIGHTRIDER: return 'h'; @@ -869,6 +885,7 @@ char PieceToChar(int piece) case W_MASTODON: return 'G'; case B_GOLD: + case B_GENERAL: case B_MASTODON: return 'g'; case W_AMAZON: @@ -885,6 +902,7 @@ char PieceToChar(int piece) return 'k'; case W_LANCE: return 'L'; + case B_LIEUTENANT: case B_LANCE: return 'l'; default: @@ -1716,7 +1734,7 @@ static int check_kings(struct game_state_t *gs) } } - if (blackking == 1 && whiteking == 1) return 0; /* Perfect! */ + if ((blackking == 1 || blackking == 2 && !strcmp(gs->variant, "spartan")) && whiteking == 1) return 0; /* Perfect! */ return -1; } diff --git a/lasker-2.2.3/src/gameproc.c b/lasker-2.2.3/src/gameproc.c index e6e59bd..c5f5d35 100644 --- a/lasker-2.2.3/src/gameproc.c +++ b/lasker-2.2.3/src/gameproc.c @@ -608,6 +608,12 @@ printf("promo '%s'\n", command); case 'g': pp->promote = MASTODON; break; + case 'l': + pp->promote = LIEUTENANT; + break; + case 'k': + pp->promote = KING; + break; // Shogi promotions case 'h': pp->promote = DRAGONHORSE; diff --git a/lasker-2.2.3/src/matchproc.c b/lasker-2.2.3/src/matchproc.c index 88c0366..5f6cd0b 100644 --- a/lasker-2.2.3/src/matchproc.c +++ b/lasker-2.2.3/src/matchproc.c @@ -543,6 +543,9 @@ static int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc, if(!strcmp("gr", category)) { strcpy(category, "great"); } else + if(!strcmp("sp", category)) { + strcpy(category, "spartan"); + } else if(!strcmp("xq", category)) { strcpy(category, "xiangqi"); } diff --git a/lasker-2.2.3/src/movecheck.c b/lasker-2.2.3/src/movecheck.c index 61bc64c..a2cb8c9 100644 --- a/lasker-2.2.3/src/movecheck.c +++ b/lasker-2.2.3/src/movecheck.c @@ -178,6 +178,36 @@ static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int return 0; } +static int legal_hoplite_move( struct game_state_t *gs, int ff, int fr, int tf, int tr ) +{ + if (ff == tf) { /* Capture ? */ + if (gs->board[tf][tr] == NOPIECE) return 0; + if (gs->onMove == WHITE) { + if(iscolor(gs->board[tf][tr],WHITE)) return 0; + if (tr - fr == 1) return 1; + } else { + if(iscolor(gs->board[tf][tr],BLACK)) return 0; + if (fr - tr == 1) return 1; + } + return 0; + } + if (ff != tf) { + if (gs->board[tf][tr] != NOPIECE) return 0; + if (gs->onMove == WHITE) { + if (tr == fr+1 && abs(tf-ff) == 1) return 1; + if (tr != fr+2 || abs(tf-ff) != 2) return 0; + if (fr > gs->pawnDblStep) return 0; + return 1; + } else { + if (tr == fr-1 && abs(tf-ff) == 1) return 1; + if (tr != fr-2 || abs(tf-ff) != 2) return 0; + if (fr < gs->ranks - 1 - gs->pawnDblStep) return 0; + return 1; + } + } + return 0; +} + static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { int dx, dy; @@ -535,6 +565,12 @@ static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, i return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr); } +static int legal_lieutenant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_modernelephant_move(gs, ff, fr, tf, tr) || + fr == tr && abs(ff - tf) == 1 && gs->board[tf][tr] == NOPIECE; +} + static int legal_priestess_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { return legal_knight_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr) @@ -679,6 +715,51 @@ static void possible_pawn_moves(struct game_state_t * gs, } } +static void possible_hoplite_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + if (gs->onMove == WHITE) { // in Spartan Chess there are no white hoplites... + if (gs->board[onf][onr + 1] != NOPIECE && + iscolor(gs->board[onf][onr + 1], BLACK)) { + add_pos(onf, onr + 1, posf, posr, numpos); + } + if (onf > 0) { + if (gs->board[onf - 1][onr + 1] == NOPIECE) { + add_pos(onf - 1, onr + 1, posf, posr, numpos); + if (onf > 1 && (onr <= gs->pawnDblStep) /*&& (gs->board[onf-2][onr + 2] == NOPIECE)*/) + add_pos(onf - 2, onr + 2, posf, posr, numpos); + } + } + if (onf < gs->files-1) { + if (gs->board[onf + 1][onr + 1] == NOPIECE) { + add_pos(onf + 1, onr + 1, posf, posr, numpos); + if (onf < gs->files-2 && (onr <= gs->pawnDblStep) /*&& (gs->board[onf+2][onr + 2] == NOPIECE)*/) + add_pos(onf + 2, onr + 2, posf, posr, numpos); + } + } + } else { + if (gs->board[onf][onr - 1] != NOPIECE && + iscolor(gs->board[onf][onr - 1], WHITE)) { + add_pos(onf, onr - 1, posf, posr, numpos); + } + if (onf > 0) { + if (gs->board[onf - 1][onr - 1] == NOPIECE) { + add_pos(onf - 1, onr - 1, posf, posr, numpos); + if (onf > 1 && (onr >= gs->ranks - gs->pawnDblStep - 1) /*&& (gs->board[onf - 2][onr - 2] == NOPIECE)*/) + add_pos(onf - 2, onr - 2, posf, posr, numpos); + } + } + if (onf < gs->files-1) { + if (gs->board[onf + 1][onr - 1] == NOPIECE) { + add_pos(onf + 1, onr - 1, posf, posr, numpos); + if (onf < gs->files-2 && (onr >= gs->ranks - gs->pawnDblStep - 1) /*&& (gs->board[onf + 2][onr - 2] == NOPIECE)*/) + add_pos(onf + 2, onr - 2, posf, posr, numpos); + } + } + } +} + static void possible_knight_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) @@ -1186,6 +1267,17 @@ static void possible_modernelephant_moves(struct game_state_t * gs, possible_alfil_moves(gs, onf, onr, posf, posr, numpos); } +static void possible_lieutenant_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_modernelephant_moves(gs, onf, onr, posf, posr, numpos); + if (onf < gs->files-1 && (gs->board[onf+1][onr] == NOPIECE)) + add_pos(onf + 1, onr, posf, posr, numpos); + if (onf > 0 && (gs->board[onf-1][onr] == NOPIECE)) + add_pos(onf - 1, onr, posf, posr, numpos); +} + static void possible_priestess_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) @@ -1388,6 +1480,9 @@ int legal_move(struct game_state_t * gs, case PAWN: legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank); break; + case HOPLITE: + legal = legal_hoplite_move(gs, fFile, fRank, tFile, tRank); + break; case KNIGHT: legal = legal_knight_move(gs, fFile, fRank, tFile, tRank); break; @@ -1397,6 +1492,7 @@ int legal_move(struct game_state_t * gs, case ROOK: legal = legal_rook_move(gs, fFile, fRank, tFile, tRank); break; + case WARLORD: case HAWK: case CARDINAL: case PRINCESS: @@ -1420,6 +1516,7 @@ int legal_move(struct game_state_t * gs, case AMAZON: legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank); break; + case CAPTAIN: case WOODY: legal = legal_woody_move(gs, fFile, fRank, tFile, tRank); break; @@ -1445,6 +1542,9 @@ int legal_move(struct game_state_t * gs, case WAZIR: legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank); break; + case LIEUTENANT: + legal = legal_lieutenant_move(gs, fFile, fRank, tFile, tRank); + break; case ALFIL: case ALFIL2: legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank); @@ -1473,6 +1573,7 @@ int legal_move(struct game_state_t * gs, case DRAGONHORSE: legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank); break; + case GENERAL: case DRAGONKING: legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank); break; @@ -1552,6 +1653,7 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && !gs->palace && // [HGM] XQ: no promotions in xiangqi ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) { + if(promote == KING) return MOVE_ILLEGAL; // no king in normal chess if(!promote && (mt->toRank == 0 || mt->toRank == gs->ranks-1)) { // promotion obligatory, but not specified if(gs->promoType != 2) promote = QUEEN; else { // choose a default for(promote=PIECES-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break; @@ -1563,6 +1665,22 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom // non-promotion can still be an option for deeper promotion zones mt->piecePromotionTo = promote ? (promote | stm) : NOPIECE; if(promote && gs->promoType == 2 && !gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified + } else + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) && + ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) { + if(!promote || promote == KING) { + int f, r, k=0, king = gs->onMove == WHITE ? W_KING : B_KING; + for(r=0; rranks;r++) for(f=0; ffiles; f++) k += (gs->board[f][r] == king); + if(k > 1) { // we already have two kings + if(promote == KING) return MOVE_ILLEGAL; // three kings not allowed + promote = WARLORD; // use strongest piece as default + } else promote = KING; // if no promo-piece given, this could be mate test, so test if promoting to King evades + } else + if(promote == MASTODON) promote = GENERAL; else + if(promote == WOODY) promote = WARLORD; else + if(promote == MARSHALL) promote = CAPTAIN; else + if(promote != LIEUTENANT) return MOVE_ILLEGAL; + mt->piecePromotionTo = (promote | stm); } else if(gs->drops == 2 && promote && mt->fromRank == (stm == WHITE ? 0 : gs->ranks-1)) { // [HGM] Seirawan-style gating int i; struct game *g = &game_globals.garray[gs->gameNum]; if(!gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified @@ -1663,12 +1781,20 @@ int in_check(struct game_state_t * gs) } } if (kf < 0) { - d_printf( "CHESSD: Error game with no king!\n"); - return 0; +// d_printf( "CHESSD: Error game with no king!\n"); + return -1; } for (InitPieceLoop(gs->board, &f, &r, gs->onMove); NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { if (legal_move(gs, f, r, kf, kr)) { /* In Check? */ + if(gs->onMove == WHITE && !strcmp(gs->variant, "spartan")) { // first king is in check, but we might have spare +//printf("spartan K-capt %c%d%c%d\n",f+'a',r+1,kf+'a',kr+1); + gs->board[kf][kr] = B_MAN; // temporarily cure the check on the first King by replacing the latter; + r = in_check(gs); + gs->board[kf][kr] = B_KING; // and put it back +//printf("duple = %d\n",r); + return r != 0; // if we have no second king (r = -1) or the second is also attacked (r = 1) we are in check. + } return 1; } } @@ -1689,6 +1815,9 @@ int has_legal_move(struct game_state_t * gs) case PAWN: possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case HOPLITE: + possible_hoplite_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case KNIGHT: possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1698,6 +1827,7 @@ int has_legal_move(struct game_state_t * gs) case ROOK: possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case WARLORD: case HAWK: case CARDINAL: case PRINCESS: @@ -1721,6 +1851,7 @@ int has_legal_move(struct game_state_t * gs) case AMAZON: possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case CAPTAIN: case WOODY: possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1753,6 +1884,9 @@ int has_legal_move(struct game_state_t * gs) case MODERNELEPHANT: possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case LIEUTENANT: + possible_lieutenant_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case PRIESTESS: possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1774,6 +1908,7 @@ int has_legal_move(struct game_state_t * gs) case DRAGONHORSE: possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case GENERAL: case DRAGONKING: possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -2178,7 +2313,19 @@ int backup_move(int g, int mode) } gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank]; if (m->piecePromotionTo != NOPIECE) { - gs->board[m->fromFile][m->fromRank] = PAWN | + int piece; + switch(piecetype(m->piecePromotionTo)) { // Spartan pieces came from Hoplite, Shogi is problematic + case KING: + case CAPTAIN: + case LIEUTENANT: + case WARLORD: + case GENERAL: piece = HOPLITE; break; + case DRAGONHORSE: piece = BISHOP; break; + case DRAGONKING: piece = ROOK; break; + case GOLD: // TODO: figure out what original was + default: piece = PAWN; + } + gs->board[m->fromFile][m->fromRank] = piece | colorval(gs->board[m->fromFile][m->fromRank]); } /******************