Check-in modifications made by HGM so far
[capablanca.git] / lasker-2.2.3 / src / algcheck.c
old mode 100644 (file)
new mode 100755 (executable)
index 32bdba1..d043445
@@ -96,7 +96,7 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
     for (j = len - 1; j >= 0; j--) {
       switch (alg_list[i][j]) {
       case 'f':
-       if ((tmp[j] < 'a') || (tmp[j] > 'h'))
+       if ((tmp[j] < 'a') || (tmp[j] > 'l')) // [HGM] upto l-file
          goto nomatch;
        if (ltf == ALG_UNKNOWN)
          ltf = tmp[j] - 'a';
@@ -104,12 +104,12 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
          lff = tmp[j] - 'a';
        break;
       case 'r':
-       if ((tmp[j] < '1') || (tmp[j] > '8'))
+       if ((tmp[j] < '0') || (tmp[j] > '9')) // [HGM] also match 0- and 9-rank
          goto nomatch;
-       if (ltr == ALG_UNKNOWN)
-         ltr = tmp[j] - '1';
-       else
-         lfr = tmp[j] - '1';
+       if (ltr == ALG_UNKNOWN)\r
+         ltr = tmp[j] - '0'; // [HGM] allow 0-rank for Xiangqi, correct later\r
+       else\r
+         lfr = tmp[j] - '0';
        break;
       case 'p':
        if (isupper(tmp[j]))
@@ -118,8 +118,32 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
          c = tmp[j];
        if (c == 'k')
          lpiece = KING;
+       else if (c == 'e')   // [HGM] note that som piece indicators are ambiguous,
+         lpiece = ELEPHANT; //       and their true meaning depends on the variant,
+       else if (c == 'v')   //       which we do not know at this point.
+         lpiece = CENTAUR;
+       else if (c == 's')
+         lpiece = SILVER;
+       else if (c == 'g')
+         lpiece = GOLD;
+       else if (c == 'l')
+         lpiece = LANCE;
+       else if (c == 'f')
+         lpiece = FERZ;
+       else if (c == 'h')
+         lpiece = HORSE;
+       else if (c == 'w')
+         lpiece = WAZIR;
+       else if (c == 'o')
+         lpiece = SQUIRREL;
        else if (c == 'q')
          lpiece = QUEEN;
+       else if (c == 'c')
+         lpiece = MARSHALL;
+       else if (c == 'a')
+         lpiece = CARDINAL;
+       else if (c == 'm')
+         lpiece = MAN;
        else if (c == 'r')
          lpiece = ROOK;
        else if (c == 'b')
@@ -190,7 +214,7 @@ int alg_is_move(const char *mstr)
 static void add_promotion(struct game_state_t *gs, const char *mstr, struct move_t * mt)
 {
        char *s;
-       int piece;
+       int piece, i;
        s = strchr(mstr, '=');
        if (s == NULL) {
                return;
@@ -199,14 +223,29 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
        if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) {
                return;
        }
-       if (mt->toRank != 7 && mt->toRank != 0) {
+       if (mt->toRank != gs->ranks-1 && mt->toRank != 0) {
                return;
        }
 
        switch (tolower(s[1])) {
+       case 'f':
+               piece = FERZ2;
+               break;
        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 'r':
                piece = ROOK;
                break;
@@ -214,12 +253,35 @@ 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
                piece = KNIGHT;
                break;
+       // Superchess promotons: filtered out later by promoType
+       case 'g':
+               piece = MASTODON;
+               break;
+       case 'o':
+               piece = SQUIRREL;
+               break;
+       case 'w':
+               piece = WOODY;
+               break;
+       case 'v':
+               piece = CENTAUR;
+               break;
+       case 'e':\r
+               piece = EMPRESS;
+               break;
+       case 's':
+               piece = PRINCESS;
+               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;
+
        mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]);
 }
 
@@ -233,6 +295,56 @@ 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] resolve ambiguity in piece, type based on variant
+  switch(piece) {
+    case ELEPHANT:
+      if(strstr(gs->variant, "super"))   piece = EMPRESS; else
+      if(strstr(gs->variant, "great"))   piece = MODERNELEPHANT; else
+      if(strstr(gs->variant, "courier")) piece = ALFIL2;
+      break;
+    case CARDINAL:
+      if(strstr(gs->variant, "super")) piece = AMAZON; else
+      if(strstr(gs->variant, "xiangqi")) piece = MANDARIN;
+      break;
+    case MARSHALL:
+      if(strstr(gs->variant, "xiangqi")) piece = CANNON;
+      break;
+    case SILVER:
+      if(strstr(gs->variant, "super")) piece = PRINCESS;
+      if(strstr(gs->variant, "great")) piece = MAN2;
+      break;
+    case BISHOP:
+      if(strstr(gs->variant, "shatranj")) piece = ALFIL;
+      break;
+    case QUEEN:
+      if(strstr(gs->variant, "shatranj")) piece = FERZ;
+      break;
+    case WAZIR:
+      if(strstr(gs->variant, "super")) piece = WOODY;
+      break;
+    case KNIGHT:
+      if(strstr(gs->variant, "shogi")) piece = HONORABLEHORSE;
+      break;
+    case MAN:
+      if(strstr(gs->variant, "great")) piece = MINISTER;
+      break;
+    case HORSE:
+      if(strstr(gs->variant, "great")) piece = PRIESTESS;
+      break;
+    case GOLD:
+      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__);
@@ -250,7 +362,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     }
     /* Need to find pawn on ff that can take to tf and fill in ranks */
     for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
       if ((ff != ALG_UNKNOWN) && (ff != f))
        continue;
       if (piecetype(gs->board[f][r]) != piece)
@@ -286,25 +398,27 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     ff = ALG_UNKNOWN;
     fr = ALG_UNKNOWN;
     for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
-           if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != BISHOP)) {
+        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
+           if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != piece)) {
+                   // 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 != 1)) {
+                   if ((piecetype(gs->board[f][r]) == PAWN) && (f != tolower(mstr[0]) - 'a')) {
                            continue;
                    }
 
                    /* if its a lowercase 'b' then prefer the pawn move if there is one */
                    if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
-                       piecetype(gs->board[f][r]) == PAWN && mstr[0] == 'b') {
+                       piecetype(gs->board[f][r]) == PAWN && mstr[0] >= 'a') {
                            ff = f;
                            fr = r;
                            continue;
                    }
 
                    if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
-                       piecetype(gs->board[ff][fr]) == PAWN && mstr[0] == 'b') {
+                       piecetype(gs->board[ff][fr]) == PAWN && mstr[0] >= 'a') {
                            continue;
                    }
 
@@ -322,7 +436,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     if ((ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) {
       /* Need to find a piece that can go to tf, tr */
       for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-          NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+          NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
        if ((ff != ALG_UNKNOWN) && (ff != f))
          continue;
        if ((fr != ALG_UNKNOWN) && (fr != r))
@@ -381,20 +495,21 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
     piece = piecetype(gs->board[mt->fromFile][mt->fromRank]);
   }
 
-  if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 6))) {
-    strcpy(mStr, "O-O");
-    goto check;
-  }
-  if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 2))) {
-    strcpy(mStr, "O-O-O");
-    goto check;
-  }
+  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
   strcpy(mStr, "");
   switch (piece) {
   case PAWN:
     if (mt->fromFile == ALG_DROP) {
       strcpy(mStr,"P");
-    } else if (mt->fromFile != mt->toFile) {
+    } else if (mt->fromFile != mt->toFile 
+           || gs->board[mt->toFile][mt->toRank] != NOPIECE) { // [HGM] XQ: forward captures as "axa6"
       sprintf(tmp, "%c", mt->fromFile + 'a');
       strcpy(mStr, tmp);
     }
@@ -408,9 +523,68 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
   case ROOK:
     strcpy(mStr, "R");
     break;
+  case ALFIL2:
+  case AMAZON:
+  case CARDINAL:\r
+    strcpy(mStr, "A");\r
+    break;\r
+  case CANNON:
+  case MARSHALL:\r
+    strcpy(mStr, "C");\r
+    break;\r
+  case MAN:\r
+    strcpy(mStr, "M");\r
+    break;\r
+  case FERZ:
   case QUEEN:
     strcpy(mStr, "Q");
     break;
+  case EMPRESS:
+  case ELEPHANT:
+    strcpy(mStr, "E");
+    break;
+  case ALFIL:
+    strcpy(mStr, "B");
+    break;
+  case FERZ2:
+    strcpy(mStr, "F");
+    break;
+  case WOODY:
+  case WAZIR:
+    strcpy(mStr, "W");
+    break;
+  case SQUIRREL:
+    strcpy(mStr, "O");
+    break;
+  case CENTAUR:
+    strcpy(mStr, "V");
+    break;
+  case HORSE:
+    strcpy(mStr, "H");
+    break;
+  case HONORABLEHORSE:
+    strcpy(mStr, "N");
+    break;
+  case DRAGONKING:
+    strcpy(mStr, "J");
+    break;
+  case DRAGONHORSE:
+    strcpy(mStr, "I");
+    break;
+  case LANCE:
+    strcpy(mStr, "L");
+    break;
+  case PRINCESS:
+  case SILVER:
+    strcpy(mStr, "S");
+    break;
+  case MASTODON:
+  case GOLD:
+    strcpy(mStr, "G");
+    break;
+  case MANDARIN:
+    strcpy(mStr, "A");
+    break;
   case KING:
     strcpy(mStr, "K");
     break;
@@ -425,8 +599,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 < 8; r++)
-      for (f = 0; f < 8; f++) {
+    for (r = 0; r < gs->ranks; r++)\r
+      for (f = 0; f < gs->files; f++) {\r
        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))) {
@@ -460,48 +634,78 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
          }
        }
       }
-    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);
-       strcat(mStr, tmp);
-      } else {
-       sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1);
-       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);
-  strcat(mStr, tmp);
-
-  if ((piece == PAWN) && (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 QUEEN:
-      strcat(mStr, "Q");
-      break;
-    default:
-      break;
-    }
-  }
+    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
+\r
+  if ((piece == PAWN) && (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
+    default:\r
+      break;\r
+    }\r
+  }\r
 check:;
   fakeMove = *gs;
   execute_move(&fakeMove, mt, 0);