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 }