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

sim.c (4563B)


      1 /* sim.c - partidas motor contra motor (con jugadas al azar mezcladas) que
      2  * verifican invariantes en cada jugada; perft y benchmark por consola. */
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <time.h>
      6 #include "../core/chess.h"
      7 #include "app.h"
      8 
      9 static uint32_t mono_ms(void)
     10 {
     11     struct timespec ts;
     12     clock_gettime(CLOCK_MONOTONIC, &ts);
     13     return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
     14 }
     15 
     16 static TTEntry tt[1 << 16];
     17 
     18 int app_sim(int n, uint64_t seed, int level)
     19 {
     20     chess_init();
     21     Engine e;
     22     engine_init(&e, tt, 1 << 16, mono_ms);
     23     Rng r;
     24     rng_seed(&r, seed, 3);
     25     int res[4] = { 0 }, errors = 0, stuck = 0;
     26     long plies = 0;
     27     static char pgn[65536];
     28     for (int k = 0; k < n; k++) {
     29         Game g;
     30         game_init(&g, 0, 0, false);
     31         SearchLimits lim;
     32         level_limits(level, &lim);
     33         lim.movetime = 0;
     34         lim.max_nodes = 3000;           /* rapido y determinista */
     35         int random_every = 3 + (int)rng_below(&r, 5);
     36         while (g.result == R_NONE && g.nply < MAX_PLY - 1) {
     37             Move m;
     38             if (rng_below(&r, (uint32_t)random_every) == 0) {
     39                 MoveList l;
     40                 pos_legal(&g.pos, &l);
     41                 m = l.m[rng_below(&r, (uint32_t)l.n)];
     42             } else {
     43                 SearchResult sr;
     44                 engine_search(&e, &g, &lim, &sr);
     45                 m = sr.best;
     46             }
     47             Act a = { ACT_MOVE, (int8_t)g.pos.side, m, 0 };
     48             if (game_check(&g, &a) != E_OK) { printf("partida %d: jugada ilegal del motor\n", k); errors++; break; }
     49             game_apply(&g, &a);
     50             if (g.pos.hash != pos_hash(&g.pos)) { printf("partida %d: hash incremental distinto\n", k); errors++; break; }
     51             if (g.result == R_NONE && game_can_claim(&g) && rng_below(&r, 4) == 0) {
     52                 Act c = { ACT_CLAIM, (int8_t)g.pos.side, 0, 0 };
     53                 game_apply(&g, &c);
     54             }
     55         }
     56         if (g.result == R_NONE) { stuck++; continue; }
     57         res[g.result]++;
     58         plies += g.nply;
     59         /* el PGN reproduce la misma posicion final */
     60         Game h;
     61         char err[80];
     62         if (game_pgn(&g, 0, pgn, sizeof pgn) < 0 || !game_from_pgn(&h, pgn, 0, err, sizeof err) ||
     63             h.pos.hash != g.pos.hash || h.nply != g.nply) {
     64             printf("partida %d: el PGN no reproduce la partida (%s)\n", k, err);
     65             errors++;
     66         }
     67     }
     68     printf("%d partidas: blancas %d, negras %d, tablas %d; %d trabadas, %d errores; %ld jugadas promedio\n",
     69            n, res[R_WHITE], res[R_BLACK], res[R_DRAW], stuck, errors, n ? plies / n : 0);
     70     return errors || stuck ? 1 : 0;
     71 }
     72 
     73 int app_perft(const char *fen, int depth)
     74 {
     75     Pos p;
     76     if (!pos_from_fen(&p, fen)) { fprintf(stderr, "FEN invalido\n"); return 1; }
     77     uint32_t t0 = mono_ms();
     78     MoveList l;
     79     pos_legal(&p, &l);
     80     uint64_t total = 0;
     81     for (int i = 0; i < l.n; i++) {
     82         Undo u;
     83         char s[8];
     84         pos_make(&p, l.m[i], &u);
     85         uint64_t c = depth > 1 ? perft(&p, depth - 1) : 1;
     86         pos_unmake(&p, l.m[i], &u);
     87         move_uci(l.m[i], s, sizeof s);
     88         printf("%s: %llu\n", s, (unsigned long long)c);
     89         total += c;
     90     }
     91     uint32_t ms = mono_ms() - t0;
     92     printf("\nnodos: %llu  (%u ms, %.1f Mnps)\n", (unsigned long long)total, ms, ms ? total / 1000.0 / ms : 0);
     93     return 0;
     94 }
     95 
     96 int app_bench(void)
     97 {
     98     static const char *FENS[] = {
     99         "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
    100         "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1",
    101         "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10",
    102         "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1",
    103     };
    104     static TTEntry big[1 << 20];
    105     Engine e;
    106     engine_init(&e, big, 1 << 20, mono_ms);
    107     uint64_t nodes = 0;
    108     uint32_t ms = 0;
    109     for (size_t i = 0; i < sizeof FENS / sizeof FENS[0]; i++) {
    110         Game g;
    111         Pos p;
    112         pos_from_fen(&p, FENS[i]);
    113         game_init(&g, &p, 0, false);
    114         SearchLimits lim;
    115         memset(&lim, 0, sizeof lim);
    116         lim.movetime = 2000;
    117         SearchResult r;
    118         engine_clear(&e);
    119         engine_search(&e, &g, &lim, &r);
    120         char s[8];
    121         move_uci(r.best, s, sizeof s);
    122         printf("pos %zu: %s  prof %d  score %d  %u nodos  %u ms\n", i + 1, s, r.depth, r.score, r.nodes, r.ms);
    123         nodes += r.nodes;
    124         ms += r.ms;
    125     }
    126     printf("total: %llu nodos en %u ms (%.0f knps)\n", (unsigned long long)nodes, ms, ms ? (double)nodes / ms : 0);
    127     return 0;
    128 }