reindent some functions
[xboard.git] / backend.c
index 2574673..6095cc6 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -356,6 +356,7 @@ PosFlags(index)
   case VariantNoCastle:
   case VariantShatranj:
   case VariantCourier:
+  case VariantMakruk:
     flags &= ~F_ALL_CASTLE_OK;
     break;
   default:
@@ -489,10 +490,10 @@ ChessSquare  KnightmateArray[2][BOARD_FILES] = {
 };
 
 ChessSquare fairyArray[2][BOARD_FILES] = { /* [HGM] Queen side differs from King side */
-    { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen,
+    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,
         WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },
-    { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen,
-       BlackKing, BlackBishop, BlackKnight, BlackRook }
+    { BlackLance, BlackAlfil, BlackMarshall, BlackAngel,
+       BlackKing, BlackMarshall, BlackAlfil, BlackLance }
 };
 
 ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */
@@ -502,6 +503,13 @@ ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatr
         BlackFerz, BlackAlfil, BlackKnight, BlackRook }
 };
 
+ChessSquare makrukArray[2][BOARD_FILES] = { /* [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_FILES>=10)
 ChessSquare ShogiArray[2][BOARD_FILES] = {
@@ -888,6 +896,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 */
@@ -1083,198 +1092,267 @@ InitBackEnd2()
 void
 InitBackEnd3 P((void))
 {
-    GameMode initialMode;
-    char buf[MSG_SIZ];
-    int err;
-
-    InitChessProgram(&first, startedFromSetupPosition);
-
-
-    if (appData.icsActive) {
-#ifdef WIN32
-        /* [DM] Make a console window if needed [HGM] merged ifs */
-        ConsoleCreate();
-#endif
-       err = establish();
-       if (err != 0) {
-           if (*appData.icsCommPort != NULLCHAR) {
-               sprintf(buf, _("Could not open comm port %s"),
-                       appData.icsCommPort);
-           } else {
-               snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
-                       appData.icsHost, appData.icsPort);
+  GameMode initialMode;
+  char buf[MSG_SIZ];
+  int err;
+  
+  InitChessProgram(&first, startedFromSetupPosition);
+  
+  
+  if (appData.icsActive) 
+    {
+      err = establish();
+      if (err != 0) 
+       {
+         if (*appData.icsCommPort != NULLCHAR) 
+           {
+             sprintf(buf, _("Could not open comm port %s"),
+                     appData.icsCommPort);
            }
-           DisplayFatalError(buf, err, 1);
-           return;
+         else 
+           {
+             snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
+                      appData.icsHost, appData.icsPort);
+           }
+         DisplayFatalError(buf, err, 1);
+         return;
        }
-       SetICSMode();
-       telnetISR =
-         AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
-       fromUserISR =
-         AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
-    } else if (appData.noChessProgram) {
-       SetNCPMode();
-    } else {
-       SetGNUMode();
+      SetICSMode();
+      telnetISR =
+       AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
+      fromUserISR =
+       AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
     }
-
-    if (*appData.cmailGameName != NULLCHAR) {
-       SetCmailMode();
-       OpenLoopback(&cmailPR);
-       cmailISR =
-         AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+  else if (appData.noChessProgram) 
+    {
+      SetNCPMode();
+    } 
+  else 
+    {
+      SetGNUMode();
     }
-
-    ThawUI();
-    DisplayMessage("", "");
-    if (StrCaseCmp(appData.initialMode, "") == 0) {
+  
+  if (*appData.cmailGameName != NULLCHAR) 
+    {
+      SetCmailMode();
+      OpenLoopback(&cmailPR);
+      cmailISR =
+       AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+    }
+  
+  ThawUI();
+  DisplayMessage("", "");
+  if (StrCaseCmp(appData.initialMode, "") == 0) 
+    {
       initialMode = BeginningOfGame;
-    } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) 
+    {
       initialMode = TwoMachinesPlay;
-    } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) 
+    {
       initialMode = AnalyzeFile;
-    } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) 
+    {
       initialMode = AnalyzeMode;
-    } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) 
+    {
       initialMode = MachinePlaysWhite;
-    } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) 
+    {
       initialMode = MachinePlaysBlack;
-    } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) 
+    {
       initialMode = EditGame;
-    } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) 
+    {
       initialMode = EditPosition;
-    } else if (StrCaseCmp(appData.initialMode, "Training") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "Training") == 0) 
+    {
       initialMode = Training;
-    } else {
+    } 
+  else 
+    {
       sprintf(buf, _("Unknown initialMode %s"), appData.initialMode);
       DisplayFatalError(buf, 0, 2);
       return;
     }
-
-    if (appData.matchMode) {
-       /* Set up machine vs. machine match */
-       if (appData.noChessProgram) {
-           DisplayFatalError(_("Can't have a match with no chess programs"),
-                             0, 2);
-           return;
+  
+  if (appData.matchMode) 
+    {
+      /* Set up machine vs. machine match */
+      if (appData.noChessProgram) 
+       {
+         DisplayFatalError(_("Can't have a match with no chess programs"),
+                           0, 2);
+         return;
        }
-       matchMode = TRUE;
-       matchGame = 1;
-       if (*appData.loadGameFile != NULLCHAR) {
-           int index = appData.loadGameIndex; // [HGM] autoinc
-           if(index<0) lastIndex = index = 1;
-           if (!LoadGameFromFile(appData.loadGameFile,
-                                 index,
-                                 appData.loadGameFile, FALSE)) {
-               DisplayFatalError(_("Bad game file"), 0, 1);
-               return;
+      matchMode = TRUE;
+      matchGame = 1;
+      if (*appData.loadGameFile != NULLCHAR) 
+       {
+         int index = appData.loadGameIndex; // [HGM] autoinc
+         if(index<0) lastIndex = index = 1;
+         if (!LoadGameFromFile(appData.loadGameFile,
+                               index,
+                               appData.loadGameFile, FALSE)) 
+           {
+             DisplayFatalError(_("Bad game file"), 0, 1);
+             return;
            }
-       } else if (*appData.loadPositionFile != NULLCHAR) {
-           int index = appData.loadPositionIndex; // [HGM] autoinc
-           if(index<0) lastIndex = index = 1;
-           if (!LoadPositionFromFile(appData.loadPositionFile,
-                                     index,
-                                     appData.loadPositionFile)) {
-               DisplayFatalError(_("Bad position file"), 0, 1);
-               return;
+       } 
+      else if (*appData.loadPositionFile != NULLCHAR) 
+       {
+         int index = appData.loadPositionIndex; // [HGM] autoinc
+         if(index<0) lastIndex = index = 1;
+         if (!LoadPositionFromFile(appData.loadPositionFile,
+                                   index,
+                                   appData.loadPositionFile)) 
+           {
+             DisplayFatalError(_("Bad position file"), 0, 1);
+             return;
            }
        }
-       TwoMachinesEvent();
-    } else if (*appData.cmailGameName != NULLCHAR) {
-       /* Set up cmail mode */
-       ReloadCmailMsgEvent(TRUE);
-    } else {
-       /* Set up other modes */
-       if (initialMode == AnalyzeFile) {
-         if (*appData.loadGameFile == NULLCHAR) {
-           DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
-           return;
-         }
+      TwoMachinesEvent();
+    } 
+  else if (*appData.cmailGameName != NULLCHAR) 
+    {
+      /* Set up cmail mode */
+      ReloadCmailMsgEvent(TRUE);
+    } 
+  else 
+    {
+      /* Set up other modes */
+      if (initialMode == AnalyzeFile) 
+       {
+         if (*appData.loadGameFile == NULLCHAR) 
+           {
+             DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
+             return;
+           }
        }
-       if (*appData.loadGameFile != NULLCHAR) {
-           (void) LoadGameFromFile(appData.loadGameFile,
-                                   appData.loadGameIndex,
-                                   appData.loadGameFile, TRUE);
-       } else if (*appData.loadPositionFile != NULLCHAR) {
-           (void) LoadPositionFromFile(appData.loadPositionFile,
-                                       appData.loadPositionIndex,
-                                       appData.loadPositionFile);
-            /* [HGM] try to make self-starting even after FEN load */
-            /* to allow automatic setup of fairy variants with wtm */
-            if(initialMode == BeginningOfGame && !blackPlaysFirst) {
-                gameMode = BeginningOfGame;
-                setboardSpoiledMachineBlack = 1;
-            }
-            /* [HGM] loadPos: make that every new game uses the setup */
-            /* from file as long as we do not switch variant          */
-            if(!blackPlaysFirst) {
-                startedFromPositionFile = TRUE;
-                CopyBoard(filePosition, boards[0]);
+      if (*appData.loadGameFile != NULLCHAR) 
+       {
+         (void) LoadGameFromFile(appData.loadGameFile,
+                                 appData.loadGameIndex,
+                                 appData.loadGameFile, TRUE);
+       } 
+      else if (*appData.loadPositionFile != NULLCHAR) 
+       {
+         (void) LoadPositionFromFile(appData.loadPositionFile,
+                                     appData.loadPositionIndex,
+                                     appData.loadPositionFile);
+         /* [HGM] try to make self-starting even after FEN load */
+         /* to allow automatic setup of fairy variants with wtm */
+         if(initialMode == BeginningOfGame && !blackPlaysFirst) 
+           {
+             gameMode = BeginningOfGame;
+             setboardSpoiledMachineBlack = 1;
             }
+         /* [HGM] loadPos: make that every new game uses the setup */
+         /* from file as long as we do not switch variant          */
+         if(!blackPlaysFirst) 
+           {
+             startedFromPositionFile = TRUE;
+             CopyBoard(filePosition, boards[0]);
+           }
        }
-       if (initialMode == AnalyzeMode) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
-           return;
-         }
+      if (initialMode == AnalyzeMode) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
+             return;
+           }
          AnalyzeModeEvent();
-       } else if (initialMode == AnalyzeFile) {
+       } 
+      else if (initialMode == AnalyzeFile) 
+       {
          appData.showThinking = TRUE; // [HGM] thinking: moved out of ShowThinkingEvent
          ShowThinkingEvent();
          AnalyzeFileEvent();
          AnalysisPeriodicEvent(1);
-       } else if (initialMode == MachinePlaysWhite) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("MachineWhite mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == MachinePlaysWhite) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("MachineWhite mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          MachineWhiteEvent();
-       } else if (initialMode == MachinePlaysBlack) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("MachineBlack mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == MachinePlaysBlack) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("MachineBlack mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          MachineBlackEvent();
-       } else if (initialMode == TwoMachinesPlay) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("TwoMachines mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == TwoMachinesPlay) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("TwoMachines mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          TwoMachinesEvent();
-       } else if (initialMode == EditGame) {
+       } 
+      else if (initialMode == EditGame) 
+       {
          EditGameEvent();
-       } else if (initialMode == EditPosition) {
+       } 
+      else if (initialMode == EditPosition) 
+       {
          EditPositionEvent();
-       } else if (initialMode == Training) {
-         if (*appData.loadGameFile == NULLCHAR) {
-           DisplayFatalError(_("Training mode requires a game file"), 0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == Training) 
+       {
+         if (*appData.loadGameFile == NULLCHAR) 
+           {
+             DisplayFatalError(_("Training mode requires a game file"), 0, 2);
+             return;
+           }
          TrainingEvent();
        }
     }
+  
+  return;
 }
 
 /*
@@ -3704,16 +3782,16 @@ ParseBoard12(string)
     if(moveNum == 0 || gameInfo.variant != VariantFischeRandom)
     { int i, j; ChessSquare wKing = WhiteKing, bKing = BlackKing;
 
-        for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)
+        for(i=BOARD_LEFT, j=NoRights; i<BOARD_RGHT; i++)
             if(board[0][i] == WhiteRook) j = i;
         initialRights[0] = boards[moveNum][CASTLING][0] = (castle_ws == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
-        for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)
+        for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--)
             if(board[0][i] == WhiteRook) j = i;
         initialRights[1] = boards[moveNum][CASTLING][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
-        for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)
+        for(i=BOARD_LEFT, j=NoRights; i<BOARD_RGHT; i++)
             if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;
         initialRights[3] = boards[moveNum][CASTLING][3] = (castle_bs == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
-        for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)
+        for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--)
             if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;
         initialRights[4] = boards[moveNum][CASTLING][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
 
@@ -3723,6 +3801,11 @@ ParseBoard12(string)
         for(k=BOARD_LEFT; k<BOARD_RGHT; k++)
             if(board[BOARD_HEIGHT-1][k] == bKing)
                 initialRights[5] = boards[moveNum][CASTLING][5] = k;
+        if(gameInfo.variant == VariantTwoKings) {
+            // In TwoKings looking for a King does not work, so always give castling rights to a King on e1/e8
+            if(board[0][4] == wKing) initialRights[2] = boards[moveNum][CASTLING][2] = 4;
+            if(board[BOARD_HEIGHT-1][4] == bKing) initialRights[5] = boards[moveNum][CASTLING][5] = 4;
+        }
     } else { int r;
         r = boards[moveNum][CASTLING][0] = initialRights[0];
         if(board[0][r] != WhiteRook) boards[moveNum][CASTLING][0] = NoRights;
@@ -4192,7 +4275,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));
@@ -4780,6 +4863,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;
@@ -4891,6 +4980,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)
@@ -5077,6 +5167,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
@@ -5120,7 +5212,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;
     }
@@ -7577,6 +7669,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
      Board board;
 {
   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 */
@@ -7623,7 +7716,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
     }
 
   /* [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;
@@ -7674,7 +7767,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
         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 */
@@ -7738,13 +7831,13 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
        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 */
@@ -10994,76 +11087,84 @@ MachineWhiteEvent()
 void
 MachineBlackEvent()
 {
-    char buf[MSG_SIZ];
-   char *bookHit = NULL;
-
-    if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
-       return;
-
-
-    if (gameMode == PlayFromGameFile ||
-       gameMode == TwoMachinesPlay  ||
-       gameMode == Training         ||
-       gameMode == AnalyzeMode      ||
-       gameMode == EndOfGame)
-        EditGameEvent();
-
-    if (gameMode == EditPosition) 
-        EditPositionDone(TRUE);
-
-    if (WhiteOnMove(currentMove)) {
-       DisplayError(_("It is not Black's turn"), 0);
-       return;
+  char buf[MSG_SIZ];
+  char *bookHit = NULL;
+  
+  if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
+    return;
+  
+  
+  if (gameMode == PlayFromGameFile 
+      || gameMode == TwoMachinesPlay  
+      || gameMode == Training     
+      || gameMode == AnalyzeMode
+      || gameMode == EndOfGame)
+    EditGameEvent();
+  
+  if (gameMode == EditPosition) 
+    EditPositionDone(TRUE);
+  
+  if (WhiteOnMove(currentMove)) 
+    {
+      DisplayError(_("It is not Black's turn"), 0);
+      return;
     }
-
-    if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
-      ExitAnalyzeMode();
-
-    if (gameMode == EditGame || gameMode == AnalyzeMode ||
-       gameMode == AnalyzeFile)
-       TruncateGame();
-
-    ResurrectChessProgram();   /* in case it isn't running */
-    gameMode = MachinePlaysBlack;
-    pausing = FALSE;
-    ModeHighlight();
-    SetGameInfo();
-    sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
-    DisplayTitle(buf);
-    if (first.sendName) {
+  
+  if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
+    ExitAnalyzeMode();
+  
+  if (gameMode == EditGame || gameMode == AnalyzeMode 
+      || gameMode == AnalyzeFile)
+    TruncateGame();
+  
+  ResurrectChessProgram();     /* in case it isn't running */
+  gameMode = MachinePlaysBlack;
+  pausing  = FALSE;
+  ModeHighlight();
+  SetGameInfo();
+  sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
+  DisplayTitle(buf);
+  if (first.sendName) 
+    {
       sprintf(buf, "name %s\n", gameInfo.white);
       SendToProgram(buf, &first);
     }
-    if (first.sendTime) {
-      if (first.useColors) {
-       SendToProgram("white\n", &first); /*gnu kludge*/
-      }
+  if (first.sendTime) 
+    {
+      if (first.useColors) 
+       {
+         SendToProgram("white\n", &first); /*gnu kludge*/
+       }
       SendTimeRemaining(&first, FALSE);
     }
-    if (first.useColors) {
+  if (first.useColors) 
+    {
       SendToProgram("black\n", &first); // [HGM] book: 'go' sent separately
     }
-    bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
-    SetMachineThinkingEnables();
-    first.maybeThinking = TRUE;
-    StartClocks();
-
-    if (appData.autoFlipView && flipView) {
+  bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
+  SetMachineThinkingEnables();
+  first.maybeThinking = TRUE;
+  StartClocks();
+  
+  if (appData.autoFlipView && flipView) 
+    {
       flipView = !flipView;
       DrawPosition(FALSE, NULL);
       DisplayBothClocks();       // [HGM] logo: clocks might have to be exchanged;
     }
-    if(bookHit) { // [HGM] book: simulate book reply
-       static char bookMove[MSG_SIZ]; // a bit generous?
-
-       programStats.nodes = programStats.depth = programStats.time =
-       programStats.score = programStats.got_only_move = 0;
-       sprintf(programStats.movelist, "%s (xbook)", bookHit);
-
-       strcpy(bookMove, "move ");
-       strcat(bookMove, bookHit);
-       HandleMachineMove(bookMove, &first);
+  if(bookHit) 
+    { // [HGM] book: simulate book reply
+      static char bookMove[MSG_SIZ]; // a bit generous?
+      
+      programStats.nodes = programStats.depth = programStats.time 
+       = programStats.score = programStats.got_only_move = 0;
+      sprintf(programStats.movelist, "%s (xbook)", bookHit);
+      
+      strcpy(bookMove, "move ");
+      strcat(bookMove, bookHit);
+      HandleMachineMove(bookMove, &first);
     }
+  return;
 }
 
 
@@ -11598,7 +11699,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;
 
@@ -14023,7 +14125,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;
@@ -14198,10 +14300,12 @@ ParseFEN(board, blackPlaysFirst, fen)
     }   /* assume possible unless obviously impossible */
     if(initialRights[0]!=NoRights && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights;
     if(initialRights[1]!=NoRights && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights;
-    if(initialRights[2]!=NoRights && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights;
+    if(initialRights[2]!=NoRights && board[castlingRank[2]][initialRights[2]] != WhiteUnicorn
+                                 && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights;
     if(initialRights[3]!=NoRights && board[castlingRank[3]][initialRights[3]] != BlackRook) board[CASTLING][3] = NoRights;
     if(initialRights[4]!=NoRights && board[castlingRank[4]][initialRights[4]] != BlackRook) board[CASTLING][4] = NoRights;
-    if(initialRights[5]!=NoRights && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
+    if(initialRights[5]!=NoRights && board[castlingRank[5]][initialRights[5]] != BlackUnicorn
+                                 && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights;
     FENrulePlies = 0;
 
     while(*p==' ') p++;
@@ -14216,12 +14320,18 @@ ParseFEN(board, blackPlaysFirst, fen)
              (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&
              ( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||
              ( *p >= 'A' && *p < 'A' + gameInfo.boardWidth)   ) {
-        char c = *p++; int whiteKingFile=-1, blackKingFile=-1;
+        char c = *p++; int whiteKingFile=NoRights, blackKingFile=NoRights;
 
         for(i=BOARD_LEFT; i<BOARD_RGHT; i++) {
             if(board[BOARD_HEIGHT-1][i] == BlackKing) blackKingFile = i;
             if(board[0             ][i] == WhiteKing) whiteKingFile = i;
         }
+        if(gameInfo.variant == VariantTwoKings || gameInfo.variant == VariantKnightmate)
+            whiteKingFile = blackKingFile = BOARD_WIDTH >> 1; // for these variant scanning fails
+        if(whiteKingFile == NoRights || board[0][whiteKingFile] != WhiteUnicorn
+                                     && board[0][whiteKingFile] != WhiteKing) whiteKingFile = NoRights;
+        if(blackKingFile == NoRights || board[BOARD_HEIGHT-1][blackKingFile] != BlackUnicorn
+                                     && board[BOARD_HEIGHT-1][blackKingFile] != BlackKing) blackKingFile = NoRights;
         switch(c) {
           case'K':
               for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--);
@@ -14229,7 +14339,7 @@ ParseFEN(board, blackPlaysFirst, fen)
               board[CASTLING][2] = whiteKingFile;
               break;
           case'Q':
-              for(i=BOARD_LEFT; board[0][i]!=WhiteRook && i<whiteKingFile; i++);
+              for(i=BOARD_LEFT;  i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
               board[CASTLING][1] = i != whiteKingFile ? i : NoRights;
               board[CASTLING][2] = whiteKingFile;
               break;
@@ -14239,7 +14349,7 @@ ParseFEN(board, blackPlaysFirst, fen)
               board[CASTLING][5] = blackKingFile;
               break;
           case'q':
-              for(i=BOARD_LEFT; board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
+              for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
               board[CASTLING][4] = i != blackKingFile ? i : NoRights;
               board[CASTLING][5] = blackKingFile;
           case '-':
@@ -14271,6 +14381,8 @@ ParseFEN(board, blackPlaysFirst, fen)
               }
         }
       }
+      for(i=0; i<nrCastlingRights; i++)
+        if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
     if (appData.debugMode) {
         fprintf(debugFP, "FEN castling rights:");
         for(i=0; i<nrCastlingRights; i++)
@@ -14283,7 +14395,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++; board[EP_STATUS] = EP_NONE;
       } else {