Implement S-Chess
[capablanca.git] / lasker-2.2.3 / src / algcheck.c
index 065a859..aa7d5af 100644 (file)
@@ -106,9 +106,9 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
       case 'r':
        if ((tmp[j] < '0') || (tmp[j] > '9')) // [HGM] also match 0- and 9-rank
          goto nomatch;
-       if (ltr == ALG_UNKNOWN)\r
-         ltr = tmp[j] - '0'; // [HGM] allow 0-rank for Xiangqi, correct later\r
-       else\r
+       if (ltr == ALG_UNKNOWN)
+         ltr = tmp[j] - '0'; // [HGM] allow 0-rank for Xiangqi, correct later
+       else
          lfr = tmp[j] - '0';
        break;
       case 'p':
@@ -199,6 +199,7 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
     matchVal = i;
 nomatch:;
   }
+
   if (matchVal != -1)
     return MS_ALG;
   else
@@ -221,11 +222,35 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
        if (s == NULL) {
                return;
        }
+       if(gs->promoType == 3) { // handle Shogi promotions
+               piece = gs->board[mt->fromFile][mt->fromRank];
+               if(colorval(piece) == WHITE && mt->fromRank < gs->ranks - gs->ranks/3
+                                           && mt->toRank   < gs->ranks - gs->ranks/3 ) return;
+               if(colorval(piece) == BLACK && mt->fromRank >= gs->ranks/3
+                                           && mt->toRank   >= gs->ranks/3 ) return;
+                switch(piecetype(piece)) {
+                   case PAWN:
+                   case LANCE:
+                   case HONORABLEHORSE:
+                   case SILVER:
+                       if(s[1] != '+' && s[1] != '^' && s[1] != 'G' && s[1] != 'g') return;
+                       piece = GOLD; break;
+                   case BISHOP:
+                       if(s[1] != '+' && s[1] != '^' && s[1] != 'H' && s[1] != 'h') return;
+                       piece = DRAGONHORSE; break;
+                   case ROOK:
+                       if(s[1] != '+' && s[1] != '^' && s[1] != 'D' && s[1] != 'd') return;
+                       piece = DRAGONKING; break;
+                   default: return; // others do not promote, so ignore
+               }
+               mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]);
+               return;
+       }
 
        if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) {
                return;
        }
-       if (mt->toRank != gs->ranks-1 && mt->toRank != 0) {
+       if (mt->toRank < gs->ranks - gs->promoZone && mt->toRank >= gs->promoZone) {
                return;
        }
 
@@ -236,18 +261,18 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
        case 'q':
                piece = QUEEN;
                break;
-       case 'c':\r
-               if(!gs->capablancaPieces) return; // [HGM] should make variant-dependent piece mask\r
-               piece = MARSHALL;\r
-               break;\r
-       case 'a':\r
-               if(!gs->capablancaPieces) return;\r
-               piece = CARDINAL;\r
-               break;\r
-       case 'm':\r
-               if(!gs->royalKnight) return; // [HGM] only in knightmate\r
-               piece = MAN;\r
-               break;\r
+       case 'c':
+               if(!gs->capablancaPieces) return; // [HGM] should make variant-dependent piece mask
+               piece = MARSHALL;
+               break;
+       case 'a':
+               if(!gs->capablancaPieces) return;
+               piece = CARDINAL;
+               break;
+       case 'm':
+               if(!gs->royalKnight) return; // [HGM] only in knightmate
+               piece = MAN;
+               break;
        case 'r':
                piece = ROOK;
                break;
@@ -255,7 +280,7 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
                piece = BISHOP;
                break;
        case 'n':
-               if(gs->royalKnight) return; // [HGM] not in knightmate\r
+               if(gs->royalKnight) return; // [HGM] not in knightmate
                piece = KNIGHT;
                break;
        // Superchess promotons: filtered out later by promoType
@@ -271,18 +296,22 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
        case 'v':
                piece = CENTAUR;
                break;
-       case 'e':\r
-               piece = EMPRESS;
+       case 'e':
+               piece = gs->drops == 2 ? SELEPHANT : EMPRESS; // for Seirawan
                break;
        case 's':
                piece = PRINCESS;
                break;
+       case 'h':
+               if(gs->drops != 2) return;
+               piece = HAWK;
+               break;
        default:
                return;
        }
-
        i = colorval(gs->board[mt->fromFile][mt->fromRank]) == WHITE ? 0 : 1;
-       if(piece >= WOODY && (gs->promoType != 2 || gs->holding[i][piece-1] == 0)) return;
+       if(gs->promoType == 2 && gs->holding[i][piece-1] == 0) return; // only if piece was captured
+       if(piece >= WOODY && piece < KING && (gs->promoType != 2 || gs->promoZone == 3)) return; // reserved for Superchess
 
        mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]);
 }
@@ -297,14 +326,13 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     d_printf( "CHESSD: Shouldn't try to algebraicly parse non-algabraic move string.\n");
     return MOVE_ILLEGAL;
   }
-  \r
-  // [HGM] check if move does not stray off board\r
-  if(gs->ranks < 10) { \r
-    if(tr == 0 || fr == 0) return MOVE_ILLEGAL; // used nonexistent 0-rank\r
-    if(tr != ALG_UNKNOWN) tr--; if(fr != ALG_UNKNOWN) fr--; // shift to lowest rank = 1\r
-  }\r
-  if(tr >= gs->ranks || fr >= gs->ranks || tf >= gs->files || ff >= gs->files)\r
-    return MOVE_ILLEGAL;\r
+  // [HGM] check if move does not stray off board
+  if(gs->ranks < 10) { 
+    if(tr == 0 || fr == 0) return MOVE_ILLEGAL; // used nonexistent 0-rank
+    if(tr != ALG_UNKNOWN) tr--; if(fr != ALG_UNKNOWN) fr--; // shift to lowest rank = 1
+  }
+  if(tr >= gs->ranks || fr >= gs->ranks || tf >= gs->files || ff >= gs->files)
+    return MOVE_ILLEGAL;
 
   // [HGM] resolve ambiguity in piece, type based on variant
   switch(piece) {
@@ -347,7 +375,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
       if(strstr(gs->variant, "great")) piece = MASTODON;
       break;
   }
-\r
+
   /* Resolve ambiguities in to-ness */
   if (tf == ALG_UNKNOWN) {
          d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
@@ -406,7 +434,6 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
                    // note that the interpretation Bxc4 is matched last, and has set piece to BISHOP
                    continue;
            }
-
            if (legal_andcheck_move(gs, f, r, tf, tr)) {
                    if ((piecetype(gs->board[f][r]) == PAWN) && (f != tolower(mstr[0]) - 'a')) {
                            continue;
@@ -498,14 +525,14 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
     piece = piecetype(gs->board[mt->fromFile][mt->fromRank]);
   }
 
-  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile > mt->toRank)) { // [HGM] castle: K ends right of R\r
-    strcpy(mStr, "O-O");\r
-    goto check;\r
-  }\r
-  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile < mt->toRank)) { // [HGM] castle: K ends left of R\r
-    strcpy(mStr, "O-O-O");\r
-    goto check;\r
-  }\r
+  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile > mt->toRank)) { // [HGM] castle: K ends right of R
+    strcpy(mStr, "O-O");
+    goto check;
+  }
+  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile < mt->toRank)) { // [HGM] castle: K ends left of R
+    strcpy(mStr, "O-O-O");
+    goto check;
+  }
   strcpy(mStr, "");
   switch (piece) {
   case PAWN:
@@ -528,16 +555,16 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
     break;
   case ALFIL2:
   case AMAZON:
-  case CARDINAL:\r
-    strcpy(mStr, "A");\r
-    break;\r
+  case CARDINAL:
+    strcpy(mStr, "A");
+    break;
   case CANNON:
-  case MARSHALL:\r
-    strcpy(mStr, "C");\r
-    break;\r
-  case MAN:\r
-    strcpy(mStr, "M");\r
-    break;\r
+  case MARSHALL:
+    strcpy(mStr, "C");
+    break;
+  case MAN:
+    strcpy(mStr, "M");
+    break;
   case FERZ:
   case QUEEN:
     strcpy(mStr, "Q");
@@ -602,8 +629,8 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
   /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */
   if (piece != PAWN) {
     ambig = r_ambig = f_ambig = 0;
-    for (r = 0; r < gs->ranks; r++)\r
-      for (f = 0; f < gs->files; f++) {\r
+    for (r = 0; r < gs->ranks; r++)
+      for (f = 0; f < gs->files; f++) {
        if ((gs->board[f][r] != NOPIECE) && iscolor(gs->board[f][r], gs->onMove)
            && (piecetype(gs->board[f][r]) == piece) &&
            ((f != mt->fromFile) || (r != mt->fromRank))) {
@@ -637,87 +664,89 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
          }
        }
       }
-    if (ambig > 0) {\r
-      /* Ambiguity in short notation, need to add file,rank or _both_ in\r
-         notation */\r
-      if (f_ambig == 0) {\r
-       sprintf(tmp, "%c", mt->fromFile + 'a');\r
-       strcat(mStr, tmp);\r
-      } else if (r_ambig == 0) {\r
-       sprintf(tmp, "%d", mt->fromRank + 1 - (gs->ranks > 9));\r
-       strcat(mStr, tmp);\r
-      } else {\r
-       sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks > 9));\r
-       strcat(mStr, tmp);\r
-      }\r
-    }\r
-  }\r
-  if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) ||\r
-      ((piece == PAWN) && (mt->fromFile != mt->toFile))) {\r
-    strcat(mStr, "x");\r
-  }\r
-  }\r
-  sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9));\r
-  strcat(mStr, tmp);\r
-
-  if ((piece == PAWN || gs->promoType == 3) && (mt->piecePromotionTo != NOPIECE)) {\r
-    strcat(mStr, "=");         /* = before promoting piece */\r
-    switch (piecetype(mt->piecePromotionTo)) {\r
-    case KNIGHT:\r
-      strcat(mStr, "N");\r
-      break;\r
-    case BISHOP:\r
-      strcat(mStr, "B");\r
-      break;\r
-    case ROOK:\r
-      strcat(mStr, "R");\r
-      break;\r
-    case CARDINAL:\r
-      strcat(mStr, "A");\r
-      break;\r
-    case MARSHALL:\r
-      strcat(mStr, "C");\r
-      break;\r
-    case MAN:\r
-      strcat(mStr, "M");\r
-      break;\r
-    case QUEEN:\r
-      strcat(mStr, "Q");\r
-      break;\r
-    case FERZ2:\r
-      strcat(mStr, "F");\r
-      break;\r
-    case WOODY:\r
-      strcat(mStr, "W");\r
-      break;\r
-    case EMPRESS:\r
-      strcat(mStr, "E");\r
-      break;\r
-    case CENTAUR:\r
-      strcat(mStr, "V");\r
-      break;\r
-    case PRINCESS:\r
-      strcat(mStr, "S");\r
-      break;\r
-    case SQUIRREL:\r
-      strcat(mStr, "O");\r
-      break;\r
-    case MASTODON:\r
-      strcat(mStr, "G");\r
-      break;\r
-    case GOLD: // [HGM] Shogi promotions: avoid use of '+'\r
-      strcat(mStr, "G");\r
-      break;\r
-    case DRAGONHORSE:\r
-      strcat(mStr, "H");\r
-      break;\r
-    case DRAGONKING:\r
-      strcat(mStr, "D");\r
-      break;\r
-    default:\r
-      break;\r
-    }\r
-  }\r
+    if (ambig > 0) {
+      /* Ambiguity in short notation, need to add file,rank or _both_ in
+         notation */
+      if (f_ambig == 0) {
+       sprintf(tmp, "%c", mt->fromFile + 'a');
+       strcat(mStr, tmp);
+      } else if (r_ambig == 0) {
+       sprintf(tmp, "%d", mt->fromRank + 1 - (gs->ranks > 9));
+       strcat(mStr, tmp);
+      } else {
+       sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks > 9));
+       strcat(mStr, tmp);
+      }
+    }
+  }
+  if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) ||
+      ((piece == PAWN) && (mt->fromFile != mt->toFile))) {
+    strcat(mStr, "x");
+  }
+  }
+  sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9));
+  strcat(mStr, tmp);
+
+  if ((piece == PAWN || gs->promoType == 3) && (mt->piecePromotionTo != NOPIECE)) {
+    strcat(mStr, "=");         /* = before promoting piece */
+    switch (piecetype(mt->piecePromotionTo)) {
+    case KNIGHT:
+      strcat(mStr, "N");
+      break;
+    case BISHOP:
+      strcat(mStr, "B");
+      break;
+    case ROOK:
+      strcat(mStr, "R");
+      break;
+    case CARDINAL:
+      strcat(mStr, "A");
+      break;
+    case MARSHALL:
+      strcat(mStr, "C");
+      break;
+    case MAN:
+      strcat(mStr, "M");
+      break;
+    case QUEEN:
+      strcat(mStr, "Q");
+      break;
+    case FERZ2:
+      strcat(mStr, "F");
+      break;
+    case WOODY:
+      strcat(mStr, "W");
+      break;
+    case SELEPHANT:
+    case EMPRESS:
+      strcat(mStr, "E");
+      break;
+    case CENTAUR:
+      strcat(mStr, "V");
+      break;
+    case PRINCESS:
+      strcat(mStr, "S");
+      break;
+    case SQUIRREL:
+      strcat(mStr, "O");
+      break;
+    case MASTODON:
+      strcat(mStr, "G");
+      break;
+    case GOLD: // [HGM] Shogi promotions: avoid use of '+'
+      strcat(mStr, "G");
+      break;
+    case HAWK:
+    case DRAGONHORSE:
+      strcat(mStr, "H");
+      break;
+    case DRAGONKING:
+      strcat(mStr, "D");
+      break;
+    default:
+      break;
+    }
+  }
 check:;
   fakeMove = *gs;
   execute_move(&fakeMove, mt, 0);