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 }