chess.h (9557B)
1 /* chess.h - nucleo portable del ajedrez: reglas, notacion, partida, motor. 2 * 3 * Todo lo de core/ es C99 puro: sin malloc, sin stdio, sin sistema operativo. 4 * Compila igual para Linux, para el servidor y para el RP2040 de la PicoCalc. 5 * 6 * Modelo (igual que Catan): una partida = posicion inicial + log de acciones 7 * (jugadas, ofertas de tablas, abandono, deshacer, caida de bandera). Un nodo 8 * "autoridad" valida cada accion y le pone el tiempo usado; todos los demas 9 * aplican las acciones resueltas con game_apply(). Guardar, retomar, reconectar 10 * y jugar por correspondencia salen de lo mismo. */ 11 #ifndef CHESS_H 12 #define CHESS_H 13 14 #include <stdint.h> 15 #include <stdbool.h> 16 #include "rng.h" 17 #include "str.h" 18 #include "lang.h" 19 20 /* ------------------------------------------------------------------ piezas */ 21 22 enum { WHITE, BLACK }; 23 enum { EMPTY, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; 24 #define PIECE(color, type) ((uint8_t)((type) | ((color) << 3))) 25 #define PTYPE(p) ((p) & 7) 26 #define PCOLOR(p) ((p) >> 3) 27 28 /* casillas: a1 = 0, b1 = 1, ..., h8 = 63 */ 29 #define SQ(file, rank) ((rank) * 8 + (file)) 30 #define FILE_OF(s) ((s) & 7) 31 #define RANK_OF(s) ((s) >> 3) 32 33 enum { CASTLE_WK = 1, CASTLE_WQ = 2, CASTLE_BK = 4, CASTLE_BQ = 8 }; 34 35 typedef struct { 36 uint8_t sq[64]; 37 uint8_t side; /* quien mueve */ 38 uint8_t castle; /* CASTLE_* */ 39 int8_t ep; /* casilla de captura al paso (tras un avance doble) o -1 */ 40 uint8_t king[2]; 41 uint16_t halfmove; /* para la regla de 50/75 */ 42 uint16_t fullmove; 43 uint64_t hash; /* Zobrist; al paso solo cuenta si se puede capturar */ 44 } Pos; 45 46 /* ------------------------------------------------------------------ jugadas */ 47 48 /* Jugada en 16 bits: desde (6) | hasta (6) | bandera (4) */ 49 typedef uint16_t Move; 50 enum { 51 MF_QUIET, MF_DOUBLE, MF_OO, MF_OOO, MF_CAPTURE, MF_EP, 52 MF_PROMO = 8, /* 8..11: corona a N B R Q; +4 si ademas captura */ 53 }; 54 #define MOVE(from, to, flag) ((Move)((from) | ((to) << 6) | ((flag) << 12))) 55 #define MFROM(m) ((m) & 63) 56 #define MTO(m) (((m) >> 6) & 63) 57 #define MFLAG(m) ((m) >> 12) 58 #define MIS_CAPTURE(m) (MFLAG(m) == MF_CAPTURE || MFLAG(m) == MF_EP || MFLAG(m) >= 12) 59 #define MIS_PROMO(m) (MFLAG(m) >= MF_PROMO) 60 #define MPROMO(m) (KNIGHT + (MFLAG(m) & 3)) /* pieza de la coronacion */ 61 #define MOVE_NONE 0 62 63 #define MAX_MOVES 256 64 typedef struct { Move m[MAX_MOVES]; int n; } MoveList; 65 66 typedef struct { uint8_t cap, castle; int8_t ep; uint16_t half; uint64_t hash; } Undo; 67 68 void chess_init(void); /* tablas (idempotente) */ 69 void pos_start(Pos *p); 70 bool pos_from_fen(Pos *p, const char *fen); /* valida en serio */ 71 int pos_fen(const Pos *p, char *buf, int n); 72 uint64_t pos_hash(const Pos *p); /* calculado de cero (para chequear el incremental) */ 73 bool pos_attacked(const Pos *p, int sq, int by); 74 bool pos_in_check(const Pos *p); 75 int pos_gen(const Pos *p, Move *out, bool captures_only); /* pseudo-legales en out[MAX_MOVES] */ 76 void pos_moves(const Pos *p, MoveList *l); /* pseudo-legales */ 77 void pos_captures(const Pos *p, MoveList *l); /* capturas y coronaciones pseudo-legales */ 78 void pos_legal(const Pos *p, MoveList *l); 79 bool pos_is_legal(const Pos *p, Move m); 80 void pos_make(Pos *p, Move m, Undo *u); /* aplica (sin chequear legalidad) */ 81 void pos_unmake(Pos *p, Move m, const Undo *u); 82 void pos_null(Pos *p, Undo *u); /* pasar (para el motor) */ 83 void pos_unnull(Pos *p, const Undo *u); 84 bool pos_insufficient(const Pos *p); 85 uint64_t perft(Pos *p, int depth); 86 87 /* ------------------------------------------------------------------ notacion */ 88 89 int move_uci(Move m, char *buf, int n); /* "e2e4", "e7e8q" */ 90 Move move_from_uci(const Pos *p, const char *s); /* legal o MOVE_NONE */ 91 int move_san(const Pos *p, Move m, char *buf, int n); /* "Nbd7", "exd6", "O-O", "e8=Q+" */ 92 Move move_from_san(const Pos *p, const char *s); /* SAN o UCI; legal o MOVE_NONE */ 93 94 /* ------------------------------------------------------------------ partida */ 95 96 #define MAX_PLY 1000 97 98 enum Result { R_NONE, R_WHITE, R_BLACK, R_DRAW }; 99 enum Reason { 100 RS_NONE, RS_MATE, RS_RESIGN, RS_TIMEOUT, RS_STALEMATE, RS_REP5, RS_MOVE75, 101 RS_INSUFFICIENT, RS_AGREED, RS_REP3, RS_MOVE50, RS_TIMEOUT_DRAW, RS__COUNT 102 }; 103 104 /* Control de tiempo en ms. Sin reloj: todo 0. per_move > 0: correspondencia 105 * (cada jugada tiene per_move para hacerse, no se acumula). */ 106 typedef struct { int32_t base, inc, per_move; } TimeCtl; 107 108 /* Acciones del log */ 109 enum ActType { 110 ACT_MOVE, ACT_RESIGN, ACT_DRAW, ACT_DRAWOK, ACT_DRAWNO, ACT_CLAIM, 111 ACT_UNDO, ACT_UNDOOK, ACT_UNDONO, ACT_FLAG, ACT__COUNT 112 }; 113 typedef struct { 114 uint8_t type; 115 int8_t c; /* color de quien la hace */ 116 Move m; /* ACT_MOVE */ 117 int32_t ms; /* ACT_MOVE / ACT_FLAG: tiempo usado (lo pone la autoridad) */ 118 } Act; 119 120 enum Err { E_OK, E_TURN, E_ILLEGAL, E_ARGS, E_OVER, E_NOTHING, E_NOCLAIM, E_NOUNDO, E__COUNT }; 121 122 typedef struct Game { 123 Pos start, pos; 124 TimeCtl tc; 125 bool allow_undo; 126 int nply; 127 Move mv[MAX_PLY]; 128 int32_t spent[MAX_PLY]; /* ms usados en cada jugada */ 129 uint64_t hist[MAX_PLY + 1]; /* hash despues de cada jugada; hist[0] = inicial */ 130 uint8_t result, reason; 131 uint8_t draw_offer; /* 0 nada, 1 + color que ofrece */ 132 uint8_t undo_req; /* 0 nada, 1 + color que pide */ 133 } Game; 134 135 void game_init(Game *g, const Pos *start, const TimeCtl *tc, bool allow_undo); 136 int game_check(const Game *g, const Act *a); 137 void game_apply(Game *g, const Act *a); /* ya validada */ 138 int game_repetitions(const Game *g); /* veces que aparecio la posicion actual */ 139 bool game_can_claim(const Game *g); /* 3 repeticiones o 50 jugadas */ 140 int32_t game_clock(const Game *g, int color); /* ms restantes al inicio del turno actual */ 141 bool game_has_clock(const Game *g); 142 int game_undo_plies(const Game *g, int requester); /* cuantas jugadas se deshacen */ 143 144 /* formato de texto de las acciones: "<color> MOVE e2e4 1234", "<color> RESIGN", ... */ 145 int act_fmt(const Act *a, char *buf, int n); 146 bool act_parse(const char *s, Act *a); 147 bool act_resolve(const struct Game *g, Act *a); /* completa la jugada contra la posicion */ 148 /* cabecera: "C <base> <inc> <per_move> <undo> <FEN>" */ 149 int game_hdr_fmt(const Game *g, char *buf, int n); 150 bool game_hdr_parse(const char *s, Game *g); 151 152 /* PGN (sin stdio: todo en buffers) */ 153 typedef struct { char white[40], black[40], event[40], site[40], date[16], round[8]; } PgnTags; 154 int game_pgn(const Game *g, const PgnTags *t, char *buf, int n); 155 /* Importa un PGN (o una lista de jugadas SAN/UCI suelta). tags puede ser NULL. */ 156 bool game_from_pgn(Game *g, const char *pgn, PgnTags *tags, char *err, int errn); 157 const char *result_text(int result); /* "1-0", "0-1", "1/2-1/2", "*" */ 158 159 /* ------------------------------------------------------------------ aperturas */ 160 161 /* nombre de la apertura mas larga que coincide con las jugadas (o NULL) */ 162 const char *opening_name(const Move *mv, int n, const Pos *start, const char **eco); 163 /* jugada de libro al azar para seguir (MOVE_NONE si no hay) */ 164 Move book_move(const Move *mv, int n, const Pos *start, Rng *rng); 165 166 /* ------------------------------------------------------------------ puzzles */ 167 168 /* solucion: jugadas UCI separadas por espacio; las de lugar impar son del rival */ 169 typedef struct { const char *name[2]; const char *fen, *solution; } Puzzle; 170 extern const Puzzle PUZZLES[]; 171 extern const int NPUZZLES; 172 173 /* ------------------------------------------------------------------ motor */ 174 175 typedef struct { uint64_t key; Move move; int16_t score; int8_t depth; uint8_t flag; } TTEntry; 176 177 typedef struct { 178 int max_depth; /* 0 = sin limite */ 179 int32_t movetime; /* ms; 0 = sin limite */ 180 uint32_t max_nodes; /* 0 = sin limite */ 181 int noise; /* cp de margen para elegir al azar entre las mejores (niveles bajos) */ 182 bool use_book; 183 } SearchLimits; 184 185 typedef struct { 186 Move best; 187 int score; /* cp desde el lado que mueve; +-MATE-n */ 188 int depth; 189 uint32_t nodes; 190 uint32_t ms; 191 Move pv[16]; 192 int npv; 193 } SearchResult; 194 195 #define MATE 30000 196 #define MATE_IN(s) ((s) > MATE - 500 || (s) < -MATE + 500) 197 198 typedef struct { 199 TTEntry *tt; /* tabla de transposicion (la pone el que llama) */ 200 uint32_t tt_size; /* entradas, potencia de 2 */ 201 uint32_t (*now_ms)(void); /* reloj */ 202 bool (*poll)(void *ctx); /* se llama seguido: true = abortar */ 203 void *ctx; 204 Rng rng; 205 } Engine; 206 207 void engine_init(Engine *e, TTEntry *tt, uint32_t tt_size, uint32_t (*now_ms)(void)); 208 void engine_clear(Engine *e); 209 /* Busca la mejor jugada de la partida g (usa su historial para las repeticiones). */ 210 void engine_search(Engine *e, const Game *g, const SearchLimits *lim, SearchResult *r); 211 int evaluate(const Pos *p); /* cp desde el lado que mueve */ 212 213 /* niveles predefinidos: 0 facil .. 4 maximo */ 214 enum { LEVEL_COUNT = 5 }; 215 void level_limits(int level, SearchLimits *lim); 216 217 /* ------------------------------------------------------------------ textos */ 218 219 #include "strings.h" 220 const char *tr(int id); 221 const char *err_text(int e); 222 const char *reason_text(int r); 223 const char *piece_name(int type); 224 const char *color_name(int color); 225 226 #endif