juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

notation.c (4522B)


      1 /* notation.c - jugadas en UCI ("e2e4", "e7e8q") y SAN ("Nbd7", "exd6", "O-O", "e8=Q+"). */
      2 #include <string.h>
      3 #include "chess.h"
      4 
      5 static const char PROMO_CH[] = "  nbrq";      /* por tipo de pieza */
      6 static const char SAN_CH[] = "  NBRQK";
      7 
      8 int move_uci(Move m, char *buf, int n)
      9 {
     10     char t[6];
     11     int k = 0;
     12     t[k++] = (char)('a' + FILE_OF(MFROM(m)));
     13     t[k++] = (char)('1' + RANK_OF(MFROM(m)));
     14     t[k++] = (char)('a' + FILE_OF(MTO(m)));
     15     t[k++] = (char)('1' + RANK_OF(MTO(m)));
     16     if (MIS_PROMO(m)) t[k++] = PROMO_CH[MPROMO(m)];
     17     t[k] = 0;
     18     return str_put(buf, n, 0, t);
     19 }
     20 
     21 static int parse_sq(const char *s)
     22 {
     23     if (s[0] < 'a' || s[0] > 'h' || s[1] < '1' || s[1] > '8') return -1;
     24     return SQ(s[0] - 'a', s[1] - '1');
     25 }
     26 
     27 Move move_from_uci(const Pos *p, const char *s)
     28 {
     29     int from = parse_sq(s), to = from >= 0 ? parse_sq(s + 2) : -1;
     30     if (from < 0 || to < 0) return MOVE_NONE;
     31     int promo = 0;
     32     if (s[4] && s[4] != ' ') {
     33         const char *q = strchr(PROMO_CH + 2, s[4] | 0x20);
     34         if (!q) return MOVE_NONE;
     35         promo = (int)(q - PROMO_CH);
     36         if (s[5] && s[5] != ' ') return MOVE_NONE;
     37     }
     38     MoveList l;
     39     pos_legal(p, &l);
     40     for (int i = 0; i < l.n; i++) {
     41         Move m = l.m[i];
     42         if (MFROM(m) != from || MTO(m) != to) continue;
     43         if (MIS_PROMO(m) ? MPROMO(m) == promo : !promo) return m;
     44     }
     45     return MOVE_NONE;
     46 }
     47 
     48 int move_san(const Pos *p, Move m, char *buf, int n)
     49 {
     50     char t[12];
     51     int k = 0, from = MFROM(m), to = MTO(m), fl = MFLAG(m);
     52     int type = PTYPE(p->sq[from]);
     53     if (fl == MF_OO) k = str_put(t, sizeof t, 0, "O-O");
     54     else if (fl == MF_OOO) k = str_put(t, sizeof t, 0, "O-O-O");
     55     else {
     56         if (type == PAWN) {
     57             if (MIS_CAPTURE(m)) t[k++] = (char)('a' + FILE_OF(from));
     58         } else {
     59             t[k++] = SAN_CH[type];
     60             /* desambiguar con otras piezas iguales que llegan al mismo lugar */
     61             MoveList l;
     62             pos_legal(p, &l);
     63             bool same_file = false, same_rank = false, other = false;
     64             for (int i = 0; i < l.n; i++) {
     65                 int f2 = MFROM(l.m[i]);
     66                 if (f2 == from || MTO(l.m[i]) != to || PTYPE(p->sq[f2]) != type) continue;
     67                 other = true;
     68                 if (FILE_OF(f2) == FILE_OF(from)) same_file = true;
     69                 if (RANK_OF(f2) == RANK_OF(from)) same_rank = true;
     70             }
     71             if (other) {
     72                 if (!same_file) t[k++] = (char)('a' + FILE_OF(from));
     73                 else if (!same_rank) t[k++] = (char)('1' + RANK_OF(from));
     74                 else { t[k++] = (char)('a' + FILE_OF(from)); t[k++] = (char)('1' + RANK_OF(from)); }
     75             }
     76         }
     77         if (MIS_CAPTURE(m)) t[k++] = 'x';
     78         t[k++] = (char)('a' + FILE_OF(to));
     79         t[k++] = (char)('1' + RANK_OF(to));
     80         if (MIS_PROMO(m)) { t[k++] = '='; t[k++] = SAN_CH[MPROMO(m)]; }
     81         t[k] = 0;
     82     }
     83     Pos q = *p;
     84     Undo u;
     85     pos_make(&q, m, &u);
     86     if (pos_in_check(&q)) {
     87         MoveList l;
     88         pos_legal(&q, &l);
     89         t[k++] = l.n ? '+' : '#';
     90         t[k] = 0;
     91     }
     92     return str_put(buf, n, 0, t);
     93 }
     94 
     95 /* compara SAN ignorando +#!? y la diferencia 0-0 / O-O */
     96 static void san_norm(const char *s, char *out, int n)
     97 {
     98     int k = 0;
     99     for (; *s && *s != ' ' && k < n - 1; s++) {
    100         char c = *s;
    101         if (c == '+' || c == '#' || c == '!' || c == '?') continue;
    102         if (c == '0') c = 'O';
    103         out[k++] = c;
    104     }
    105     out[k] = 0;
    106 }
    107 
    108 Move move_from_san(const Pos *p, const char *s)
    109 {
    110     while (*s == ' ') s++;
    111     Move m = move_from_uci(p, s);
    112     if (m) return m;
    113     char want[16], got[16], san[16];
    114     san_norm(s, want, sizeof want);
    115     if (!want[0]) return MOVE_NONE;
    116     MoveList l;
    117     pos_legal(p, &l);
    118     for (int i = 0; i < l.n; i++) {
    119         move_san(p, l.m[i], san, sizeof san);
    120         san_norm(san, got, sizeof got);
    121         if (!strcmp(want, got)) return l.m[i];
    122     }
    123     /* coronacion sin "=" (e8Q) o pieza de coronacion en minuscula */
    124     int wl = (int)strlen(want);
    125     if (wl >= 3 && strchr("NBRQnbrq", want[wl - 1]) && want[wl - 2] != '=') {
    126         char alt[16];
    127         memcpy(alt, want, (size_t)wl - 1);
    128         alt[wl - 1] = '=';
    129         alt[wl] = (char)(want[wl - 1] & ~0x20);
    130         alt[wl + 1] = 0;
    131         for (int i = 0; i < l.n; i++) {
    132             move_san(p, l.m[i], san, sizeof san);
    133             san_norm(san, got, sizeof got);
    134             if (!strcmp(alt, got)) return l.m[i];
    135         }
    136     }
    137     return MOVE_NONE;
    138 }