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

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