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 }