Implement Spartan Chess
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 1 Dec 2011 20:47:24 +0000 (21:47 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 31 Dec 2011 10:29:23 +0000 (11:29 +0100)
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).

lasker-2.2.3/data/boards/spartan/0 [new file with mode: 0644]
lasker-2.2.3/src/Makefile.in
lasker-2.2.3/src/algcheck.c
lasker-2.2.3/src/board.c
lasker-2.2.3/src/board.h
lasker-2.2.3/src/gamedb.c
lasker-2.2.3/src/gameproc.c
lasker-2.2.3/src/matchproc.c
lasker-2.2.3/src/movecheck.c

diff --git a/lasker-2.2.3/data/boards/spartan/0 b/lasker-2.2.3/data/boards/spartan/0
new file mode 100644 (file)
index 0000000..bbdf487
--- /dev/null
@@ -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
index b0aff55..61a1292 100644 (file)
@@ -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")'
index 33f6b28..219b5de 100644 (file)
@@ -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;
     }
index 40e7037..f2fa5f0 100644 (file)
 
 
 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:", " <B>", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!",
                             " <B>", " {Q}", " .W.", " :H:", " :N:", " <H>", " |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]", " <L>", " |C|", "  h "};
   static const char *bp[] = {"    ", "  p ", " :n:", " <b>", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!",
                             " <b>", " {q}", " .w.", " :h:", " :n:", " <h>", " |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]", " <l>", " |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':
index 611ff80..461fec1 100644 (file)
 #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
 #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))
index becb7a0..da255dc 100644 (file)
@@ -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;
 }
index e6e59bd..c5f5d35 100644 (file)
@@ -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;
index 88c0366..5f6cd0b 100644 (file)
@@ -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");
        }
index 61bc64c..a2cb8c9 100644 (file)
@@ -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; r<gs->ranks;r++) for(f=0; f<gs->files; 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]);
   }
   /******************