Add variant Makruk
authorH.G. Muller <h.g.muller@hccnet.nl>
Wed, 13 Jan 2010 18:08:45 +0000 (19:08 +0100)
committerArun Persaud <arun@nubati.net>
Tue, 9 Feb 2010 03:45:35 +0000 (19:45 -0800)
Thai Chess, played by 2 million world-wide. Required pawn promotion to
happen in a zone, and the Alfil to move as Shogi Silver, a new opening
array, and unusual Pawn placement. Because of the latter, I consider it
a setup position, so a FEN will always be sent to the engine.

backend.c
common.h
moves.c
parser.l
winboard/help/html/18.htm
winboard/resource.h
winboard/winboard.rc
winboard/woptions.c
xboard.texi
xoptions.c

index ecf338c..91bc82d 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -355,6 +355,7 @@ PosFlags(index)
   case VariantNoCastle:
   case VariantShatranj:
   case VariantCourier:
+  case VariantMakruk:
     flags &= ~F_ALL_CASTLE_OK;
     break;
   default:
@@ -490,6 +491,13 @@ ChessSquare ShatranjArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatra
         BlackFerz, BlackAlfil, BlackKnight, BlackRook }
 };
 
+ChessSquare makrukArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatranj Q and P) */
+    { WhiteRook, WhiteKnight, WhiteMan, WhiteKing,
+        WhiteFerz, WhiteMan, WhiteKnight, WhiteRook },
+    { BlackRook, BlackKnight, BlackMan, BlackFerz,
+        BlackKing, BlackMan, BlackKnight, BlackRook }
+};
+
 
 #if (BOARD_SIZE>=10)
 ChessSquare ShogiArray[2][BOARD_SIZE] = {
@@ -875,6 +883,7 @@ InitBackEnd1()
       case VariantAtomic:     /* should work except for win condition */
       case Variant3Check:     /* should work except for win condition */
       case VariantShatranj:   /* should work except for all win conditions */
+      case VariantMakruk:     /* should work except for daw countdown */
       case VariantBerolina:   /* might work if TestLegality is off */
       case VariantCapaRandom: /* should work */
       case VariantJanus:      /* should work */
@@ -4196,7 +4205,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY)
       case BlackPromotionChancellor:
       case WhitePromotionArchbishop:
       case BlackPromotionArchbishop:
-        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)
+        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
             sprintf(user_move, "%c%c%c%c=%c\n",
                 AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,
                PieceToChar(WhiteFerz));
@@ -4679,6 +4688,12 @@ InitPosition(redraw)
       nrCastlingRights = 0;
       SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k"); 
       break;
+    case VariantMakruk:
+      pieces = makrukArray;
+      nrCastlingRights = 0;
+      startedFromSetupPosition = TRUE;
+      SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk"); 
+      break;
     case VariantTwoKings:
       pieces = twoKingsArray;
       break;
@@ -4792,6 +4807,7 @@ InitPosition(redraw)
 
     pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
     if(pawnRow < 1) pawnRow = 1;
+    if(gameInfo.variant == VariantMakruk) pawnRow = 2;
 
     /* User pieceToChar list overrules defaults */
     if(appData.pieceToCharTable != NULL)
@@ -4977,6 +4993,8 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
     if(gameInfo.variant == VariantShogi) {
         promotionZoneSize = 3;
         highestPromotingPiece = (int)WhiteFerz;
+    } else if(gameInfo.variant == VariantMakruk) {
+        promotionZoneSize = 3;
     }
 
     // next weed out all moves that do not touch the promotion zone at all
@@ -5020,7 +5038,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
     }
 
     // we either have a choice what to promote to, or (in Shogi) whether to promote
-    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier) {
+    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) {
        *promoChoice = PieceToChar(BlackFerz);  // no choice
        return FALSE;
     }
@@ -7375,6 +7393,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
      char *ep;
 {
   ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
+  int promoRank = gameInfo.variant == VariantMakruk ? 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 */
@@ -7421,7 +7440,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
     }
 
   /* [HGM] In Shatranj and Courier all promotions are to Ferz */
-  if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier)
+  if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier || gameInfo.variant == VariantMakruk)
        && promoChar != 0) promoChar = PieceToChar(WhiteFerz);
          
   if (fromX == toX && fromY == toY) return;
@@ -7472,7 +7491,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
         board[toY][toX+1] = board[fromY][BOARD_LEFT];
         board[fromY][BOARD_LEFT] = EmptySquare;
     } else if (board[fromY][fromX] == WhitePawn
-               && toY == BOARD_HEIGHT-1
+               && toY >= BOARD_HEIGHT-promoRank
                && gameInfo.variant != VariantXiangqi
                ) {
        /* white pawn promotion */
@@ -7536,13 +7555,13 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)
        board[fromY][0] = EmptySquare;
        board[toY][2] = BlackRook;
     } else if (board[fromY][fromX] == BlackPawn
-              && toY == 0
+              && toY < promoRank
                && gameInfo.variant != VariantXiangqi
                ) {
        /* black pawn promotion */
-       board[0][toX] = CharToPiece(ToLower(promoChar));
-       if (board[0][toX] == EmptySquare) {
-           board[0][toX] = BlackQueen;
+       board[toY][toX] = CharToPiece(ToLower(promoChar));
+       if (board[toY][toX] == EmptySquare) {
+           board[toY][toX] = BlackQueen;
        }
         if(gameInfo.variant==VariantBughouse ||
            gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */
@@ -11391,7 +11410,8 @@ EditPositionMenuEvent(selection, x, y)
       case BlackQueen:
         if(gameInfo.variant == VariantShatranj ||
            gameInfo.variant == VariantXiangqi  ||
-           gameInfo.variant == VariantCourier    )
+           gameInfo.variant == VariantCourier  ||
+           gameInfo.variant == VariantMakruk     )
             selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);
         goto defaultlabel;
 
@@ -13747,7 +13767,7 @@ PositionToFEN(move, overrideCastling)
   }
 
   if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
-     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { 
+     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) { 
     /* En passant target square */
     if (move > backwardMostMove) {
         fromX = moveList[move - 1][0] - AAA;
@@ -14017,7 +14037,7 @@ ParseFEN(board, blackPlaysFirst, fen)
 
     /* read e.p. field in games that know e.p. capture */
     if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
-       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { 
+       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) { 
       if(*p=='-') {
         p++; FENepStatus = EP_NONE;
       } else {
index 0f50acd..e98d93f 100644 (file)
--- a/common.h
+++ b/common.h
@@ -294,6 +294,7 @@ typedef enum {
     VariantSuper,
     VariantGreat,
     VariantTwilight,
+    VariantMakruk,
     VariantUnknown       /* Catchall for other unknown variants */
 } VariantClass;
 
@@ -336,6 +337,7 @@ typedef enum {
   "super",\
   "great",\
   "twilight",\
+  "makruk",\
   "unknown" \
 }
 
diff --git a/moves.c b/moves.c
index 319a332..75b9434 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -260,6 +260,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
 {
     int rf, ff;
     int i, j, d, s, fs, rs, rt, ft, m;
+    int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1;
 
     for (rf = 0; rf < BOARD_HEIGHT; rf++) 
       for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
@@ -303,7 +304,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               }
               if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {
                  callback(board, flags,
-                          rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                          rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotionQueen : NormalMove,
                           rf, ff, rf + 1, ff, closure);
              }
              if (rf == 1 && board[2][ff] == EmptySquare &&
@@ -318,7 +319,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||
                       BlackPiece(board[rf + 1][ff + s]))) {
                      callback(board, flags, 
-                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                              rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotionQueen : NormalMove,
                               rf, ff, rf + 1, ff + s, closure);
                  }
                  if (rf == BOARD_HEIGHT-4) {
@@ -353,7 +354,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               }
              if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
                  callback(board, flags, 
-                          rf == 1 ? BlackPromotionQueen : NormalMove,
+                          rf <= promoRank ? BlackPromotionQueen : NormalMove,
                           rf, ff, rf - 1, ff, closure);
              }
              if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
@@ -368,7 +369,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||
                       WhitePiece(board[rf - 1][ff + s]))) {
                      callback(board, flags, 
-                              rf == 1 ? BlackPromotionQueen : NormalMove,
+                              rf <= promoRank ? BlackPromotionQueen : NormalMove,
                               rf, ff, rf - 1, ff + s, closure);
                  }
                  if (rf == 3) {
@@ -608,6 +609,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
 
             /* Shogi Pawn and Silver General: first the Pawn move,    */
             /* then the General continues like a Ferz                 */
+            case WhiteMan:
+                if(gameInfo.variant != VariantMakruk) goto commoner;
             case SHOGI WhitePawn:
             case SHOGI WhiteFerz:
                   if (rf < BOARD_HEIGHT-1 &&
@@ -617,6 +620,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               if(piece != SHOGI WhitePawn) goto finishSilver;
               break;
 
+            case BlackMan:
+                if(gameInfo.variant != VariantMakruk) goto commoner;
             case SHOGI BlackPawn:
             case SHOGI BlackFerz:
                   if (rf > 0 &&
@@ -644,8 +649,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
            case WhiteSilver:
            case BlackSilver:
                m++; // [HGM] superchess: use for Centaur
-            case WhiteMan:
-            case BlackMan:
+            commoner:
             case SHOGI WhiteKing:
             case SHOGI BlackKing:
            case WhiteKing:
index 788c93c..d3585c7 100755 (executable)
--- a/parser.l
+++ b/parser.l
@@ -317,7 +317,7 @@ extern void CopyBoard P((Board to, Board from));
     if (currentMoveString[4] == NULLCHAR &&\r
         (result == WhitePromotionKnight || result == BlackPromotionKnight ||\r
          result == WhitePromotionQueen  || result == BlackPromotionQueen)) {\r
-        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)\r
+        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)\r
             currentMoveString[4] = PieceToChar(BlackFerz);\r
         else if(gameInfo.variant == VariantGreat)\r
             currentMoveString[4] = PieceToChar(BlackMan);\r
@@ -505,7 +505,7 @@ extern void CopyBoard P((Board to, Board from));
          result == WhitePromotionKnight || result == BlackPromotionKnight)) {\r
         currentMoveString[4] = PieceToChar(BlackQueen);\r
        // [HGM] shatranj: take care of variants without Queen\r
-       if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)\r
+       if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)\r
             currentMoveString[4] = PieceToChar(BlackFerz);\r
        if(gameInfo.variant == VariantGreat)\r
             currentMoveString[4] = PieceToChar(BlackMan);\r
index 81a8f79..801f04f 100644 (file)
@@ -82,6 +82,8 @@ atomic</td><td>Capturing piece explodes (ICC wild 27)
 </td></tr><tr><td>\r
 <font color="#008000">knightmate</font></td><td><font color="#008000">King moves a Knight, and vice versa</font>\r
 </td></tr><tr><td>\r
+<font color="#3333ff">makruk</font></td><td><font color="#3333ff">Thai Chess (shatranj-like, pawns promote on 6th rank)</font>\r
+</td></tr><tr><td>\r
 <font color="#3333ff">super</font></td><td><font color="#3333ff">Superchess, a shuffle variant with B+N, R+N, K+N and Q+N compound</font>\r
 </td></tr><tr><td>\r
 <font color="#3333ff">great</font></td><td><font color="#3333ff">Great Shatranj, whithout sliders, on 10x8 board (legality testing off!)</font>\r
index 744509d..1dfcbf5 100644 (file)
 #define OPT_Variant3Check               1526\r
 #define OPT_VariantGreat                1527\r
 #define OPT_VariantTwilight             1528\r
+#define OPT_VariantMakruk               1529\r
 #define IDC_Files                       1550\r
 #define IDC_Ranks                       1551\r
 #define IDC_Holdings                    1552\r
index c61067b..1c17817 100644 (file)
@@ -673,6 +673,8 @@ BEGIN
                     84,50,10\r
     CONTROL         "&fairy",OPT_VariantFairy,"Button",BS_AUTORADIOBUTTON,70,\r
                     94,50,10\r
+    CONTROL         "&makruk",OPT_VariantMakruk,"Button",BS_AUTORADIOBUTTON,70,\r
+                    104,50,10\r
     CONTROL         "&gothic",OPT_VariantGothic,"Button",BS_AUTORADIOBUTTON,134,14,\r
                     50,10\r
     CONTROL         "&capablanca",OPT_VariantCapablanca,"Button",BS_AUTORADIOBUTTON,134,\r
index c7c6e6f..379a8d6 100644 (file)
@@ -773,7 +773,8 @@ VariantWhichRadio(HWND hDlg)
          (IsDlgButtonChecked(hDlg, OPT_VariantGreat) ? VariantGreat :\r
          (IsDlgButtonChecked(hDlg, OPT_VariantGiveaway) ? VariantGiveaway :\r
          (IsDlgButtonChecked(hDlg, OPT_VariantTwilight) ? VariantTwilight :\r
-          VariantNormal ))))))))))))))))))))))))))));\r
+         (IsDlgButtonChecked(hDlg, OPT_VariantMakruk) ? VariantMakruk :\r
+          VariantNormal )))))))))))))))))))))))))))));\r
 }\r
 \r
 LRESULT CALLBACK\r
@@ -872,6 +873,9 @@ NewVariantDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     case VariantTwilight:\r
       CheckDlgButton(hDlg, OPT_VariantTwilight, TRUE);\r
       break;\r
+    case VariantMakruk:\r
+      CheckDlgButton(hDlg, OPT_VariantMakruk, TRUE);\r
+      break;\r
     default: ;\r
     }\r
 \r
index bd56944..57e9fe4 100644 (file)
@@ -2210,6 +2210,7 @@ berolina      Pawns capture straight ahead, and move diagonal
 cylinder      Pieces wrap around the board edge
 knightmate    King moves as Knight, and vice versa 
 super         Superchess (shuffle variant with 4 exo-pieces)
+makruk        Thai Chess (shatranj-like, P promotes on 6th rank)
 fairy         A catchall variant in which all piece types 
               known to XBoard can participate (8x8)
 unknown       Catchall for other unknown variants
index f662257..8a7e546 100644 (file)
@@ -908,6 +908,7 @@ struct NewVarButton buttonDesc[] = {
     {N_("berolina"),          "#FFFFFF", 0, VariantBerolina},
     {N_("cylinder"),          "#FFFFFF", 0, VariantCylinder},
     {N_("shatranj"),          "#FFFFFF", 0, VariantShatranj},
+    {N_("makruk"),            "#FFFFFF", 0, VariantMakruk},
     {N_("atomic"),            "#FFFFFF", 0, VariantAtomic},
     {N_("two kings"),         "#FFFFFF", 0, VariantTwoKings},
     {N_("3-checks"),          "#FFFFFF", 0, Variant3Check},