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

search.c (19540B)


      1 /* search.c - bot fuerte: ISMCTS (Monte Carlo sobre conjuntos de informacion).
      2  *
      3  * El bot no sabe que cartas de desarrollo tienen los demas ni el orden del
      4  * mazo. En cada iteracion se "determiniza": se sortean esas cartas entre las
      5  * que pueden ser (las que no tiene el bot ni se jugaron). Sobre esa version
      6  * se baja por un arbol unico (single-observer ISMCTS): en cada nodo se generan
      7  * movidas candidatas para quien tiene que actuar, se cuentan como "disponibles"
      8  * las que existen en esta determinizacion, se agrega una nueva o se elige con
      9  * UCB. Despues se juega el resto con el bot heuristico (bot_decide) hasta el
     10  * final o unos turnos, y el resultado (un puntaje 0..1 por jugador) se propaga
     11  * para arriba: cada nodo acumula el del jugador que hizo esa movida (max-n).
     12  *
     13  * El azar (dados, robos, mazo) se resuelve igual que en auth.c con el Rng de
     14  * la busqueda. Todo estatico: una busqueda a la vez. */
     15 #include <string.h>
     16 #include "catan.h"
     17 #include "bot_int.h"
     18 
     19 #ifndef SEARCH_NODES
     20 #define SEARCH_NODES 16384    /* hasta 32767 (indices de 16 bits); la Pico usa menos */
     21 #endif
     22 
     23 enum { MAXC = 48, MAXPATH = 96 };
     24 
     25 typedef struct {
     26     Move    m;
     27     int16_t child, next;      /* primer hijo, siguiente hermano (-1 = ninguno) */
     28     uint32_t visits, avail;
     29     float   score;            /* suma de puntajes del jugador m.p */
     30 } Node;
     31 
     32 typedef struct {
     33     Game    g;
     34     uint8_t deck[DECK_MAX];   /* se roba de deck[deck_n - 1], como en auth.c */
     35 } Det;
     36 
     37 static Node nodes[SEARCH_NODES];
     38 static int nnodes;
     39 
     40 /* ------------------------------------------------------------ determinizar */
     41 
     42 static int devs_held(const Player *pl)
     43 {
     44     int n = pl->dev_hidden;
     45     for (int d = 0; d < NDEV; d++) n += pl->dev[d] + pl->dev_new[d];
     46     return n;
     47 }
     48 
     49 /* Sortea las cartas ajenas y el mazo con lo que sabe "me". */
     50 static void determinize(Det *d, const Game *g, int me, Rng *rng)
     51 {
     52     d->g = *g;
     53     Game *s = &d->g;
     54     int pool[NDEV], knights = 0, held = 0;
     55     uint8_t cnt[NDEV];
     56     int total = dev_counts(&s->o, cnt);
     57     for (int k = 0; k < NDEV; k++) pool[k] = cnt[k];
     58     for (int p = 0; p < s->o.np; p++) {
     59         knights += s->p[p].knights;
     60         held += devs_held(&s->p[p]);
     61     }
     62     for (int k = 0; k < NDEV; k++) pool[k] -= s->p[me].dev[k] + s->p[me].dev_new[k];
     63     pool[D_KNIGHT] -= knights;
     64     /* progreso ya jugado: se sabe cuantas, no cuales (ni importa mucho) */
     65     int played = (total - s->deck_n) - held - knights;
     66     while (played-- > 0) {
     67         int tot = pool[D_ROADS] + pool[D_PLENTY] + pool[D_MONO];
     68         if (tot <= 0) break;
     69         int k = (int)rng_below(rng, (uint32_t)tot);
     70         int c = k < pool[D_ROADS] ? D_ROADS : k < pool[D_ROADS] + pool[D_PLENTY] ? D_PLENTY : D_MONO;
     71         pool[c]--;
     72     }
     73     uint8_t bag[DECK_MAX];
     74     int nb = 0;
     75     for (int k = 0; k < NDEV; k++)
     76         for (int i = 0; i < pool[k] && nb < DECK_MAX; i++) bag[nb++] = (uint8_t)k;
     77     for (int i = nb - 1; i > 0; i--) {
     78         int j = (int)rng_below(rng, (uint32_t)i + 1);
     79         uint8_t t = bag[i]; bag[i] = bag[j]; bag[j] = t;
     80     }
     81     int bi = 0;
     82     for (int p = 0; p < s->o.np; p++) {
     83         if (p == me) continue;
     84         Player *pl = &s->p[p];
     85         int nold = pl->dev_hidden, nnew = 0;
     86         for (int k = 0; k < NDEV; k++) { nold += pl->dev[k]; nnew += pl->dev_new[k]; }
     87         memset(pl->dev, 0, NDEV);
     88         memset(pl->dev_new, 0, NDEV);
     89         pl->dev_hidden = 0;
     90         for (int i = 0; i < nold; i++) pl->dev[bi < nb ? bag[bi++] : D_KNIGHT]++;
     91         for (int i = 0; i < nnew; i++) pl->dev_new[bi < nb ? bag[bi++] : D_KNIGHT]++;
     92     }
     93     for (int i = 0; i < s->deck_n; i++) d->deck[i] = bi < nb ? bag[bi++] : D_KNIGHT;
     94 }
     95 
     96 /* ------------------------------------------------------- aplicar con azar */
     97 
     98 static int random_card(Rng *rng, const uint8_t hand[NRES])
     99 {
    100     int n = res_total(hand);
    101     if (!n) return -1;
    102     int k = (int)rng_below(rng, (uint32_t)n);
    103     for (int r = 0; r < NRES; r++) {
    104         if (k < hand[r]) return r;
    105         k -= hand[r];
    106     }
    107     return -1;
    108 }
    109 
    110 /* Como auth_submit, sin validar: m tiene que ser legal. */
    111 static void sim_apply(Det *d, const Move *mv, Rng *rng)
    112 {
    113     Game *g = &d->g;
    114     Move m = *mv;
    115     switch (m.type) {
    116     case M_ROLL:
    117         m.r[0] = (uint8_t)(1 + rng_below(rng, 6));
    118         m.r[1] = (uint8_t)(1 + rng_below(rng, 6));
    119         m.r[2] = m.r[3] = 0;
    120         if (g->o.variant2p)
    121             do {
    122                 m.r[2] = (uint8_t)(1 + rng_below(rng, 6));
    123                 m.r[3] = (uint8_t)(1 + rng_below(rng, 6));
    124             } while (m.r[2] + m.r[3] == m.r[0] + m.r[1]);
    125         break;
    126     case M_ROBBER:
    127         m.c = (int16_t)(m.b >= 0 ? random_card(rng, g->p[m.b].res) : -1);
    128         break;
    129     case M_BUYDEV:
    130         m.a = g->deck_n ? d->deck[g->deck_n - 1] : D_KNIGHT;
    131         break;
    132     case M_TOKTRADE: {
    133         int r = game_rival(g, m.p);
    134         uint8_t hand[NRES] = { 0 };
    135         if (r >= 0) memcpy(hand, g->p[r].res, NRES);
    136         m.a = (int16_t)random_card(rng, hand);
    137         if (m.a >= 0) hand[m.a]--;
    138         m.b = (int16_t)random_card(rng, hand);
    139         break;
    140     }
    141     default:
    142         break;
    143     }
    144     game_apply(g, &m);
    145     int p = g->cur;
    146     if (g->winner < 0 && game_vp(g, p) >= g->o.vp_target) {
    147         Move w = { .type = M_WIN, .p = (int8_t)p };
    148         w.a = (int16_t)(g->p[p].dev[D_VP] + g->p[p].dev_new[D_VP]);
    149         game_apply(g, &w);
    150     }
    151 }
    152 
    153 /* Quien actua ahora: primero los que responden una oferta y los que descartan. */
    154 static int actor(const Game *g)
    155 {
    156     if (g->phase == PH_OVER || g->winner >= 0) return -1;
    157     for (int s = 0; s < g->o.np; s++)
    158         if (s != g->cur && game_needs(g, s)) return s;
    159     return game_needs(g, g->cur) ? g->cur : -1;
    160 }
    161 
    162 /* ------------------------------------------------------------ candidatas */
    163 
    164 typedef struct { Move m[MAXC]; int n; } Cands;
    165 
    166 static void add(Cands *c, const Game *g, int p, int type, int a, int b, int cc)
    167 {
    168     if (c->n >= MAXC) return;
    169     Move *m = &c->m[c->n];
    170     memset(m, 0, sizeof *m);
    171     m->type = (uint8_t)type; m->p = (int8_t)p;
    172     m->a = (int16_t)a; m->b = (int16_t)b; m->c = (int16_t)cc;
    173     if (game_check(g, m) != E_OK) return;
    174     for (int i = 0; i < c->n; i++)
    175         if (!memcmp(&c->m[i], m, sizeof *m)) return;
    176     c->n++;
    177 }
    178 
    179 /* Las k mejores segun score[] (de 0..n-1, >= minv), en orden. */
    180 static int top_k(const int *score, int n, int minv, int k, int *out)
    181 {
    182     int cnt = 0;
    183     while (cnt < k) {
    184         int best = -1;
    185         for (int i = 0; i < n; i++) {
    186             if (score[i] < minv) continue;
    187             bool used = false;
    188             for (int j = 0; j < cnt; j++) if (out[j] == i) used = true;
    189             if (!used && (best < 0 || score[i] > score[best])) best = i;
    190         }
    191         if (best < 0) break;
    192         out[cnt++] = best;
    193     }
    194     return cnt;
    195 }
    196 
    197 static void add_roads(Cands *c, const Game *g, int p)
    198 {
    199     int score[NEDGE], pick[3];
    200     bot_road_scores(g, p, score);
    201     int n = top_k(score, game_topo(g)->nedge, -999, 3, pick);
    202     for (int i = 0; i < n; i++) add(c, g, p, M_ROAD, pick[i], 0, 0);
    203     /* la que mas alarga el camino (pelea por el camino mas largo) */
    204     int cur = game_road_len(g, p), best = -1, bl = cur;
    205     if (cur >= 3) {
    206         Game t = *g;
    207         for (int e = 0; e < game_topo(g)->nedge; e++) {
    208             if (!game_can_road(g, p, e)) continue;
    209             t.eown[e] = (int8_t)p;
    210             int l = game_road_len(&t, p);
    211             t.eown[e] = -1;
    212             if (l > bl) { bl = l; best = e; }
    213         }
    214     }
    215     if (best >= 0) add(c, g, p, M_ROAD, best, 0, 0);
    216     if (!n && best < 0)       /* ninguna con sentido: alguna legal */
    217         for (int e = 0; e < game_topo(g)->nedge && c->n < MAXC; e++)
    218             if (game_can_road(g, p, e)) { add(c, g, p, M_ROAD, e, 0, 0); break; }
    219 }
    220 
    221 /* Navegantes: los 2 barcos que mejor llevan a un lugar (islas nuevas valen mas) */
    222 static void add_ships(Cands *c, const Game *g, int p)
    223 {
    224     if (!game_has_sea(g)) return;
    225     int score[NEDGE], pick[2];
    226     bot_ship_scores(g, p, score);
    227     int n = top_k(score, game_topo(g)->nedge, -999, 2, pick);
    228     for (int i = 0; i < n; i++) add(c, g, p, M_SHIP, pick[i], 0, 0);
    229 }
    230 
    231 static void add_main(Cands *c, const Game *g, int p)
    232 {
    233     const Player *pl = &g->p[p];
    234     add(c, g, p, M_END, 0, 0, 0);
    235     if (pl->cities && game_can_afford(g, p, COST_CITY))
    236         for (int v = 0; v < game_topo(g)->nvert; v++)
    237             if (game_can_city(g, p, v)) add(c, g, p, M_CITY, v, 0, 0);
    238     if (pl->settles && game_can_afford(g, p, COST_SETTLE)) {
    239         int score[NVERT], pick[4];
    240         for (int v = 0; v < game_topo(g)->nvert; v++)
    241             score[v] = game_can_settle(g, p, v, false) ? bot_vert_value(g, p, v) : -1;
    242         int n = top_k(score, game_topo(g)->nvert, 0, 4, pick);
    243         for (int i = 0; i < n; i++) add(c, g, p, M_SETTLE, pick[i], 0, 0);
    244     }
    245     if (pl->roads && game_can_afford(g, p, COST_ROAD)) add_roads(c, g, p);
    246     if (pl->ships && game_can_afford(g, p, COST_SHIP)) add_ships(c, g, p);
    247     add(c, g, p, M_BUYDEV, 0, 0, 0);
    248 
    249     if (!g->dev_played) {
    250         add(c, g, p, M_KNIGHT, 0, 0, 0);
    251         add(c, g, p, M_ROADS, 0, 0, 0);
    252         if (pl->dev[D_MONO])
    253             for (int r = 0; r < NRES; r++) {
    254                 int n = 0;
    255                 for (int q = 0; q < g->o.np; q++) if (q != p) n += g->p[q].res[r];
    256                 if (n >= 2) add(c, g, p, M_MONO, r, 0, 0);
    257             }
    258         if (pl->dev[D_PLENTY]) {
    259             static const uint8_t *const COSTS[4] = { COST_SETTLE, COST_CITY, COST_DEV, COST_ROAD };
    260             for (int k = 0; k < 4; k++) {
    261                 int a = -1, b = -1;
    262                 uint8_t have[NRES];
    263                 memcpy(have, pl->res, NRES);
    264                 for (int i = 0; i < 2; i++)
    265                     for (int r = 0; r < NRES; r++)
    266                         if (have[r] < COSTS[k][r]) {
    267                             if (a < 0) a = r; else b = r;
    268                             have[r]++;
    269                             break;
    270                         }
    271                 if (a < 0) continue;
    272                 if (b < 0) b = a;
    273                 add(c, g, p, M_PLENTY, a < b ? a : b, a < b ? b : a, 0);
    274             }
    275         }
    276     }
    277 
    278     /* banco: por cada recurso que falta para algo (tambien rutas y barcos: con una pila de
    279      * ladrillos y sin madera, antes no se le ocurria cambiar), dar el que mas sobra */
    280     static const uint8_t *const COSTS[5] = { COST_SETTLE, COST_CITY, COST_DEV, COST_ROAD, COST_SHIP };
    281     int ncosts = game_has_sea(g) && pl->ships ? 5 : 4;
    282     for (int want = 0; want < NRES; want++) {
    283         bool need = false;
    284         for (int k = 0; k < ncosts; k++) if (pl->res[want] < COSTS[k][want]) need = true;
    285         if (!need || !g->bank[want]) continue;
    286         int give = -1, spare = 0;
    287         for (int r = 0; r < NRES; r++) {
    288             if (r == want) continue;
    289             int s = pl->res[r] - game_bank_ratio(g, p, r);
    290             if (s >= 0 && (give < 0 || s > spare)) { give = r; spare = s; }
    291         }
    292         if (give >= 0) add(c, g, p, M_BANK, give, want, 1);
    293     }
    294 
    295     Move o;
    296     if (bot_offer(g, p, &o) && c->n < MAXC) c->m[c->n++] = o;
    297 
    298     if (g->o.variant2p) {
    299         add(c, g, p, M_TOKTRADE, 0, 0, 0);
    300         if (bot_robber_on_me(g, p)) add(c, g, p, M_TOKROBBER, 0, 0, 0);
    301     }
    302 }
    303 
    304 static void gen(const Game *g, int p, Rng *rng, Cands *c)
    305 {
    306     const Topo *t = game_topo(g);
    307     c->n = 0;
    308     if (g->offer.active && g->phase == PH_MAIN) {
    309         if (p != g->offer.from) {
    310             add(c, g, p, M_ACCEPT, 0, 0, 0);
    311             add(c, g, p, M_REJECT, 0, 0, 0);
    312             Move k;
    313             if (bot_counter(g, p, &k) && c->n < MAXC) c->m[c->n++] = k;
    314         } else {
    315             for (int q = 0; q < g->o.np; q++)
    316                 if (g->offer.resp[q] == 1 || g->offer.resp[q] == 2) add(c, g, p, M_CONFIRM, q, 0, 0);
    317             add(c, g, p, M_CANCEL, 0, 0, 0);
    318         }
    319         return;
    320     }
    321     switch (g->phase) {
    322     case PH_SETUP:
    323         if (g->setup_sub == 0) {
    324             int score[NVERT], pick[6];
    325             for (int v = 0; v < game_topo(g)->nvert; v++)
    326                 score[v] = game_can_settle(g, p, v, true) ? bot_vert_value(g, p, v) : -1;
    327             int n = top_k(score, game_topo(g)->nvert, 0, 6, pick);
    328             for (int i = 0; i < n; i++) add(c, g, p, M_SETTLE, pick[i], 0, 0);
    329         } else {
    330             for (int k = 0; k < 3; k++) {
    331                 int e = t->vert_edge[g->setup_v][k];
    332                 if (e >= 0) { add(c, g, p, M_ROAD, e, 0, 0); add(c, g, p, M_SHIP, e, 0, 0); }
    333             }
    334         }
    335         return;
    336     case PH_ROLL:
    337         add(c, g, p, M_ROLL, 0, 0, 0);
    338         add(c, g, p, M_KNIGHT, 0, 0, 0);
    339         if (g->o.variant2p && bot_robber_on_me(g, p)) add(c, g, p, M_TOKROBBER, 0, 0, 0);
    340         return;
    341     case PH_ROBBER: {
    342         int score[NHEX], pick[4];
    343         for (int h = 0; h < game_topo(g)->nhex; h++)
    344             score[h] = game_can_robber(g, p, h) ? bot_robber_score(g, p, h) : -1000000;
    345         int n = top_k(score, game_topo(g)->nhex, -999999, 4, pick);
    346         for (int i = 0; i < n; i++) add(c, g, p, M_ROBBER, pick[i], bot_robber_victim(g, p, pick[i]), 0);
    347         return;
    348     }
    349     case PH_ROADBUILD:
    350         add_roads(c, g, p);
    351         add_ships(c, g, p);
    352         if (!c->n) add(c, g, p, M_END, 0, 0, 0);
    353         return;
    354     case PH_MAIN: case PH_PAIRED:            /* add() descarta lo que no vale en la pareja */
    355         add_main(c, g, p);
    356         return;
    357     default:
    358         break;
    359     }
    360     /* descartes, devoluciones, neutrales: lo que diga la heuristica */
    361     Move m;
    362     if (bot_decide(g, p, rng, &m) && game_check(g, &m) == E_OK) c->m[c->n++] = m;
    363 }
    364 
    365 /* -------------------------------------------------------------- evaluacion */
    366 
    367 static float eval_player(const Game *g, int p)
    368 {
    369     const Player *pl = &g->p[p];
    370     int prod[NRES];
    371     int pips = bot_pips(g, p, prod), kinds = 0;
    372     for (int r = 0; r < NRES; r++) if (prod[r]) kinds++;
    373     int hand = hand_size(g, p);
    374     int devs = 0;
    375     for (int d = 0; d < NDEV; d++) if (d != D_VP) devs += pl->dev[d] + pl->dev_new[d];
    376     return (float)game_vp(g, p) + 0.05f * (float)pips + 0.1f * (float)kinds
    377          + 0.06f * (float)(hand > 7 ? 7 : hand) + 0.2f * (float)devs + 0.15f * (float)pl->knights;
    378 }
    379 
    380 /* Puntaje 0..1 por jugador: 1 al ganador; si no termino, softmax de eval. */
    381 static void reward(const Game *g, float out[MAXP])
    382 {
    383     int np = g->o.np;
    384     for (int p = 0; p < MAXP; p++) out[p] = 0;
    385     if (g->winner >= 0) { out[g->winner] = 1; return; }
    386     float e[MAXP], mx = -1e9f, sum = 0;
    387     for (int p = 0; p < np; p++) {
    388         if (g->p[p].neutral) { e[p] = -1e9f; continue; }
    389         e[p] = eval_player(g, p);
    390         if (e[p] > mx) mx = e[p];
    391     }
    392     for (int p = 0; p < np; p++) {
    393         if (g->p[p].neutral) continue;
    394         /* exp(x) aproximado sin libm: (1 + x/16)^16 */
    395         float x = 1.0f + (e[p] - mx) * 1.2f / 16.0f;
    396         if (x < 0) x = 0;
    397         for (int i = 0; i < 4; i++) x *= x;
    398         out[p] = x;
    399         sum += x;
    400     }
    401     if (sum > 0) for (int p = 0; p < np; p++) out[p] /= sum;
    402 }
    403 
    404 static void rollout(Det *d, Rng *rng, int horizon)
    405 {
    406     Game *g = &d->g;
    407     int end_turn = g->turn + horizon;
    408     for (int step = 0; step < 4000; step++) {
    409         if (horizon && g->turn >= end_turn) return;
    410         if (g->turn > 600) return;
    411         int s = actor(g);
    412         if (s < 0) return;
    413         Move m;
    414         if (!bot_decide(g, s, rng, &m) || game_check(g, &m) != E_OK) {
    415             memset(&m, 0, sizeof m);
    416             m.p = (int8_t)s;
    417             m.type = g->offer.active && s != g->offer.from ? M_REJECT : M_END;
    418             if (game_check(g, &m) != E_OK) return;
    419         }
    420         sim_apply(d, &m, rng);
    421     }
    422 }
    423 
    424 /* -------------------------------------------------------------------- arbol */
    425 
    426 static int new_node(int parent, const Move *m)
    427 {
    428     if (nnodes >= SEARCH_NODES) return -1;
    429     int i = nnodes++;
    430     Node *n = &nodes[i];
    431     n->m = *m;
    432     n->child = -1;
    433     n->visits = n->avail = 0;
    434     n->score = 0;
    435     if (parent >= 0) {
    436         n->next = nodes[parent].child;
    437         nodes[parent].child = (int16_t)i;
    438     } else {
    439         n->next = -1;
    440     }
    441     return i;
    442 }
    443 
    444 static int find_child(int parent, const Move *m)
    445 {
    446     for (int c = nodes[parent].child; c >= 0; c = nodes[c].next)
    447         if (!memcmp(&nodes[c].m, m, sizeof *m)) return c;
    448     return -1;
    449 }
    450 
    451 /* sqrt sin libm (Newton, alcanza para UCB) */
    452 static float fsqrt(float x)
    453 {
    454     if (x <= 0) return 0;
    455     float r = x > 1 ? x : 1;
    456     for (int i = 0; i < 12; i++) r = 0.5f * (r + x / r);
    457     return r;
    458 }
    459 
    460 /* ln aproximado sin libm */
    461 static float flog(float x)
    462 {
    463     int e = 0;
    464     while (x > 2) { x *= 0.5f; e++; }
    465     float y = (x - 1) / (x + 1), y2 = y * y;
    466     return 0.6931472f * (float)e + 2 * y * (1 + y2 / 3 + y2 * y2 / 5);
    467 }
    468 
    469 bool search_decide(const Game *g, int seat, Rng *rng, const SearchCfg *cfg, Move *out)
    470 {
    471     static Det root, d;
    472     static Cands c;
    473     if (!game_needs(g, seat)) return false;
    474     if (bot_offer_pending(g, seat)) return false;       /* esperando respuestas a su oferta */
    475 
    476     /* lo trivial o sin ramas utiles lo resuelve la heuristica */
    477     gen(g, seat, rng, &c);
    478     if (cfg->iters <= 0 || c.n <= 1) return bot_decide(g, seat, rng, out);
    479 
    480     nnodes = 0;
    481     Move none;
    482     memset(&none, 0, sizeof none);
    483     new_node(-1, &none);
    484     uint32_t t0 = cfg->now_ms ? cfg->now_ms() : 0;
    485 
    486     for (int it = 0; it < cfg->iters; it++) {
    487         if (cfg->now_ms && cfg->max_ms && (it & 15) == 15 && cfg->now_ms() - t0 >= cfg->max_ms) break;
    488         determinize(&root, g, seat, rng);
    489         d = root;
    490         int path[MAXPATH], plen = 0, node = 0;
    491         bool first = true;
    492         while (plen < MAXPATH) {
    493             int a = first ? seat : actor(&d.g);
    494             first = false;
    495             if (a < 0) break;
    496             gen(&d.g, a, rng, &c);
    497             if (c.n == 0) break;
    498             if (c.n == 1) { sim_apply(&d, &c.m[0], rng); continue; }
    499 
    500             int unexp[MAXC], nu = 0, kids[MAXC], nk = 0;
    501             for (int i = 0; i < c.n; i++) {
    502                 int ch = find_child(node, &c.m[i]);
    503                 if (ch >= 0) { nodes[ch].avail++; kids[nk++] = ch; }
    504                 else unexp[nu++] = i;
    505             }
    506             if (nu) {
    507                 const Move *m = &c.m[unexp[rng_below(rng, (uint32_t)nu)]];
    508                 int ch = new_node(node, m);
    509                 sim_apply(&d, m, rng);
    510                 if (ch >= 0) { nodes[ch].avail++; path[plen++] = ch; }
    511                 break;
    512             }
    513             if (!nk) break;
    514             int best = kids[0];
    515             float bs = -1;
    516             for (int i = 0; i < nk; i++) {
    517                 const Node *n = &nodes[kids[i]];
    518                 float u = n->score / (float)n->visits
    519                         + cfg->c_ucb * fsqrt(flog((float)n->avail) / (float)n->visits);
    520                 if (u > bs) { bs = u; best = kids[i]; }
    521             }
    522             sim_apply(&d, &nodes[best].m, rng);
    523             path[plen++] = best;
    524             node = best;
    525         }
    526         rollout(&d, rng, cfg->horizon);
    527         float r[MAXP];
    528         reward(&d.g, r);
    529         for (int i = 0; i < plen; i++) {
    530             Node *n = &nodes[path[i]];
    531             n->visits++;
    532             n->score += r[n->m.p];
    533         }
    534     }
    535 
    536     int best = -1;
    537     for (int ch = nodes[0].child; ch >= 0; ch = nodes[ch].next)
    538         if (best < 0 || nodes[ch].visits > nodes[best].visits) best = ch;
    539     if (best < 0) return bot_decide(g, seat, rng, out);
    540     *out = nodes[best].m;
    541     return game_check(g, out) == E_OK || bot_decide(g, seat, rng, out);
    542 }