bot.c (24640B)
1 /* bot.c - IA heuristica. Solo mira informacion publica + su propia mano. */ 2 #include <string.h> 3 #include "catan.h" 4 #include "bot_int.h" 5 6 static const int PIPS[13] = { 0, 0, 1, 2, 3, 4, 5, 0, 5, 4, 3, 2, 1 }; 7 8 static void production(const Game *g, int p, int prod[NRES]) 9 { 10 const Topo *t = game_topo(g); 11 memset(prod, 0, sizeof(int) * NRES); 12 for (int v = 0; v < game_topo(g)->nvert; v++) { 13 if (g->vown[v] != p) continue; 14 for (int k = 0; k < 3; k++) { 15 int h = t->vert_hex[v][k]; 16 if (h >= 0 && ter_res(g->terrain[h])) prod[g->terrain[h]] += PIPS[g->num[h]] * g->vlev[v]; 17 } 18 } 19 } 20 21 /* Valor de un vertice para p: pips ponderados, diversidad, puertos. 22 * prod = production(g, p) ya calculada (no depende de v). */ 23 static int vert_value_with(const Game *g, const int prod[NRES], int v) 24 { 25 const Topo *t = game_topo(g); 26 int score = 0, seen = 0; 27 for (int k = 0; k < 3; k++) { 28 int h = t->vert_hex[v][k]; 29 if (h < 0) continue; 30 if (g->terrain[h] == T_GOLD) { score += PIPS[g->num[h]] * 15; continue; } /* oro: lo que haga falta */ 31 if (!ter_res(g->terrain[h])) continue; 32 int r = g->terrain[h], w = 10; 33 if (prod[r] == 0) w += 4; /* recurso que no produzco */ 34 if (r == BRICK || r == LUMBER) w += 1; 35 score += PIPS[g->num[h]] * w; 36 if (h == g->robber) score -= PIPS[g->num[h]] * 4; 37 if (!(seen & (1 << r))) { seen |= 1 << r; score += 6; } 38 } 39 int port = t->vert_port[v]; 40 if (port >= 0) { 41 int kind = g->port[port]; 42 score += kind == PORT_ANY ? 6 : (prod[kind] >= 5 ? 14 : 4); 43 } 44 return score; 45 } 46 47 static int vert_value(const Game *g, int p, int v) 48 { 49 int prod[NRES]; 50 production(g, p, prod); 51 return vert_value_with(g, prod, v); 52 } 53 54 int bot_vert_value(const Game *g, int p, int v) { return vert_value(g, p, v); } 55 56 int bot_pips(const Game *g, int p, int prod[NRES]) 57 { 58 production(g, p, prod); 59 int n = 0; 60 for (int r = 0; r < NRES; r++) n += prod[r]; 61 return n; 62 } 63 64 static int best_settle_spot(const Game *g, int p, bool setup) 65 { 66 int best = -1, bs = -1, prod[NRES]; 67 production(g, p, prod); 68 for (int v = 0; v < game_topo(g)->nvert; v++) 69 if (game_can_settle(g, p, v, setup)) { 70 int s = vert_value_with(g, prod, v); 71 if (s > bs) { bs = s; best = v; } 72 } 73 return best; 74 } 75 76 /* Para cada arista e que p puede construir: el mejor lugar libre alcanzable 77 * (<=3 rutas) por un camino que empieza en e, como vert_value - 12*distancia. 78 * -1000 si no lleva a ningun lugar. */ 79 void bot_road_scores(const Game *g, int p, int score[NEDGE]) 80 { 81 const Topo *t = game_topo(g); 82 int8_t dist[NVERT]; 83 int16_t first[NVERT]; 84 uint8_t queue[NVERT]; 85 int qh = 0, qt = 0, prod[NRES]; 86 production(g, p, prod); 87 for (int e = 0; e < game_topo(g)->nedge; e++) score[e] = -1000; 88 for (int v = 0; v < game_topo(g)->nvert; v++) { dist[v] = -1; first[v] = -1; } 89 for (int v = 0; v < game_topo(g)->nvert; v++) { 90 if (g->vown[v] >= 0 && g->vown[v] != p) continue; 91 bool src = g->vown[v] == p; 92 for (int k = 0; k < 3 && !src; k++) { 93 int e = t->vert_edge[v][k]; 94 if (e >= 0 && g->eown[e] == p) src = true; 95 } 96 if (src) { dist[v] = 0; queue[qt++] = (uint8_t)v; } 97 } 98 while (qh < qt) { 99 int u = queue[qh++]; 100 if (dist[u] >= 3) continue; 101 if (dist[u] > 0 && g->vown[u] >= 0 && g->vown[u] != p) continue; 102 for (int k = 0; k < 3; k++) { 103 int e = t->vert_edge[u][k]; 104 if (e < 0 || g->eown[e] >= 0) continue; 105 int w = t->edge_v[e][0] == u ? t->edge_v[e][1] : t->edge_v[e][0]; 106 if (dist[w] >= 0) continue; 107 dist[w] = (int8_t)(dist[u] + 1); 108 first[w] = (int16_t)(dist[u] == 0 ? e : first[u]); 109 queue[qt++] = (uint8_t)w; 110 } 111 } 112 for (int v = 0; v < game_topo(g)->nvert; v++) { 113 if (dist[v] < 1 || first[v] < 0) continue; 114 bool free = g->vown[v] < 0; 115 for (int k = 0; k < 3 && free; k++) { 116 int u = t->vert_adj[v][k]; 117 if (u >= 0 && g->vown[u] >= 0) free = false; 118 } 119 if (!free) continue; 120 int s = vert_value_with(g, prod, v) - 12 * dist[v]; 121 if (s > score[first[v]] && game_can_road(g, p, first[v])) score[first[v]] = s; 122 } 123 } 124 125 /* vertice libre (y sin vecinos ocupados) que toca tierra: donde podria ir un pueblo */ 126 static bool free_land(const Game *g, int v) 127 { 128 const Topo *t = game_topo(g); 129 if (g->vown[v] >= 0) return false; 130 bool land = false; 131 for (int k = 0; k < 3; k++) { 132 int u = t->vert_adj[v][k], h = t->vert_hex[v][k]; 133 if (u >= 0 && g->vown[u] >= 0) return false; 134 if (h >= 0 && ter_land(g->terrain[h])) land = true; 135 } 136 return land; 137 } 138 139 /* Navegantes: igual que bot_road_scores pero por agua (hasta 5 barcos); los lugares en 140 * una isla donde todavia no cobro los 2 puntos valen mas. */ 141 void bot_ship_scores(const Game *g, int p, int score[NEDGE]) 142 { 143 const Topo *t = game_topo(g); 144 int8_t dist[NVERT]; 145 int16_t first[NVERT]; 146 uint8_t queue[NVERT]; 147 int qh = 0, qt = 0, prod[NRES]; 148 production(g, p, prod); 149 for (int e = 0; e < t->nedge; e++) score[e] = -1000; 150 if (!game_has_sea(g) || !g->p[p].ships) return; 151 for (int v = 0; v < t->nvert; v++) { dist[v] = -1; first[v] = -1; } 152 for (int v = 0; v < t->nvert; v++) { /* salen de edificios propios y barcos propios */ 153 bool src = g->vown[v] == p; 154 for (int k = 0; k < 3 && !src && g->vown[v] < 0; k++) { 155 int e = t->vert_edge[v][k]; 156 if (e >= 0 && g->eown[e] == p && g->ship[e]) src = true; 157 } 158 if (src) { dist[v] = 0; queue[qt++] = (uint8_t)v; } 159 } 160 while (qh < qt) { 161 int u = queue[qh++]; 162 if (dist[u] >= 5) continue; 163 if (dist[u] > 0 && g->vown[u] >= 0) continue; 164 for (int k = 0; k < 3; k++) { 165 int e = t->vert_edge[u][k]; 166 if (e < 0 || g->eown[e] >= 0) continue; 167 bool sea = false; 168 for (int s = 0; s < 2; s++) { int h = t->edge_hex[e][s]; if (h >= 0 && !ter_land(g->terrain[h]) && h != g->pirate) sea = true; } 169 if (!sea || t->edge_hex[e][0] == g->pirate || t->edge_hex[e][1] == g->pirate) continue; 170 int w = t->edge_v[e][0] == u ? t->edge_v[e][1] : t->edge_v[e][0]; 171 if (dist[w] >= 0) continue; 172 dist[w] = (int8_t)(dist[u] + 1); 173 first[w] = (int16_t)(dist[u] == 0 ? e : first[u]); 174 queue[qt++] = (uint8_t)w; 175 } 176 } 177 for (int v = 0; v < t->nvert; v++) { 178 if (dist[v] < 1 || first[v] < 0 || !free_land(g, v)) continue; /* lugar libre con tierra */ 179 int s = vert_value_with(g, prod, v) - 10 * dist[v]; 180 for (int k = 0; k < 3; k++) { 181 int h = t->vert_hex[v][k], r = h >= 0 ? t->region[h] : -1; 182 if (r >= 0 && r < 8 && !((g->p[p].isles >> r) & 1)) { s += 40; break; } 183 } 184 if (s > score[first[v]] && game_can_ship(g, p, first[v], false)) score[first[v]] = s; 185 } 186 } 187 188 static int ship_toward_spot_s(const Game *g, int p, int *best_score) 189 { 190 int score[NEDGE], best = -1, bs = -1000; 191 bot_ship_scores(g, p, score); 192 for (int e = 0; e < game_topo(g)->nedge; e++) 193 if (score[e] > bs) { bs = score[e]; best = e; } 194 if (best_score) *best_score = bs; 195 return best; 196 } 197 198 static int ship_toward_spot(const Game *g, int p) { return ship_toward_spot_s(g, p, 0); } 199 200 static int road_toward_spot_s(const Game *g, int p, int *best_score); 201 202 /* conviene ir por agua: el mejor destino en barco (las islas nuevas dan 2 puntos) le 203 * gana al mejor por tierra, o por tierra ya no queda nada */ 204 static bool ship_better(const Game *g, int p) 205 { 206 if (!game_has_sea(g) || !g->p[p].ships || !g->p[p].settles) return false; 207 int ss, rs; 208 if (ship_toward_spot_s(g, p, &ss) < 0) return false; 209 if (road_toward_spot_s(g, p, &rs) < 0 || !g->p[p].roads) return true; 210 return ss > rs + 10; 211 } 212 213 /* Primera arista del camino hacia el mejor lugar libre alcanzable (<=3 rutas). */ 214 static int road_toward_spot_s(const Game *g, int p, int *best_score) 215 { 216 int score[NEDGE], best = -1, bs = -1000; 217 bot_road_scores(g, p, score); 218 for (int e = 0; e < game_topo(g)->nedge; e++) 219 if (score[e] > bs) { bs = score[e]; best = e; } 220 if (best_score) *best_score = bs; 221 return best; 222 } 223 224 static int road_toward_spot(const Game *g, int p) { return road_toward_spot_s(g, p, 0); } 225 226 static int any_legal_road(const Game *g, int p, Rng *rng) 227 { 228 int cand[NEDGE], n = 0; 229 for (int e = 0; e < game_topo(g)->nedge; e++) 230 if (game_can_road(g, p, e)) cand[n++] = e; 231 return n ? cand[rng_below(rng, (uint32_t)n)] : -1; 232 } 233 234 /* Que esta juntando: 0 pueblo, 1 ciudad, 2 carta, 3 ruta */ 235 int bot_goal(const Game *g, int p, uint8_t cost[NRES]) 236 { 237 const Player *pl = &g->p[p]; 238 if (pl->settles > 0 && best_settle_spot(g, p, false) >= 0) { memcpy(cost, COST_SETTLE, NRES); return 0; } 239 if (ship_better(g, p)) { memcpy(cost, COST_SHIP, NRES); return 4; } /* Navegantes: a las islas */ 240 if (pl->cities > 0) 241 for (int v = 0; v < game_topo(g)->nvert; v++) 242 if (g->vown[v] == p && g->vlev[v] == 1) { memcpy(cost, COST_CITY, NRES); return 1; } 243 if (pl->roads > 0 && pl->settles > 0 && road_toward_spot(g, p) >= 0) { memcpy(cost, COST_ROAD, NRES); return 3; } 244 memcpy(cost, COST_DEV, NRES); 245 return 2; 246 } 247 248 void bot_pick_discard(const Game *g, int p, int n, uint8_t out[NRES]) 249 { 250 uint8_t cost[NRES], hand[NRES]; 251 bot_goal(g, p, cost); 252 memcpy(hand, g->p[p].res, NRES); 253 memset(out, 0, NRES); 254 while (n-- > 0) { 255 int best = -1, bs = -1000; 256 for (int r = 0; r < NRES; r++) { 257 if (!hand[r]) continue; 258 int s = hand[r] * 2 - (hand[r] <= cost[r] ? 5 : 0); 259 if (s > bs) { bs = s; best = r; } 260 } 261 if (best < 0) break; 262 hand[best]--; 263 out[best]++; 264 } 265 } 266 267 /* Cuanto le conviene a p poner el ladron en h (mas = peor para los rivales). */ 268 int bot_robber_score(const Game *g, int p, int h) 269 { 270 const Topo *t = game_topo(g); 271 int s = 0; 272 if (!ter_land(g->terrain[h])) { /* pirata: barcos ajenos alrededor */ 273 for (int k = 0; k < 6; k++) { 274 int e = t->hex_edge[h][k], o = g->eown[e]; 275 if (o < 0 || !g->ship[e]) continue; 276 s += o == p ? -60 : 8 * (3 + game_vp_public(g, o)); 277 } 278 return s - 1; /* a igualdad, mejor el ladron en tierra */ 279 } 280 for (int k = 0; k < 6; k++) { 281 int v = t->hex_vert[h][k], o = g->vown[v]; 282 if (o < 0) continue; 283 if (o == p) s -= 100; 284 else if (!g->p[o].neutral) s += PIPS[g->num[h]] * g->vlev[v] * (3 + game_vp_public(g, o)); 285 } 286 return s; 287 } 288 289 /* A quien robarle en h: el vecino con mas cartas (-1 nadie). */ 290 int bot_robber_victim(const Game *g, int p, int h) 291 { 292 const Topo *t = game_topo(g); 293 int most = 0, who = -1; 294 bool sea = !ter_land(g->terrain[h]); 295 for (int k = 0; k < 6; k++) { 296 int e = t->hex_edge[h][k]; 297 int o = sea ? (g->ship[e] ? g->eown[e] : -1) : g->vown[t->hex_vert[h][k]]; 298 if (o >= 0 && o != p && !g->p[o].neutral && hand_size(g, o) > most) { most = hand_size(g, o); who = o; } 299 } 300 return who; 301 } 302 303 static void pick_robber(const Game *g, int p, Move *m) 304 { 305 int best = -1, bs = -100000; 306 for (int h = 0; h < game_topo(g)->nhex; h++) { 307 if (!game_can_robber(g, p, h)) continue; 308 int s = bot_robber_score(g, p, h); 309 if (s > bs) { bs = s; best = h; } 310 } 311 m->type = M_ROBBER; 312 m->a = (int16_t)best; 313 m->b = (int16_t)(best >= 0 ? bot_robber_victim(g, p, best) : -1); 314 } 315 316 bool bot_robber_on_me(const Game *g, int p) 317 { 318 const Topo *t = game_topo(g); 319 for (int k = 0; k < 6; k++) 320 if (g->vown[t->hex_vert[g->robber][k]] == p) return true; 321 return false; 322 } 323 324 /* Cambio con el banco hacia lo que falta para el objetivo. */ 325 static bool bank_toward(const Game *g, int p, const uint8_t cost[NRES], Move *m) 326 { 327 const Player *pl = &g->p[p]; 328 for (int want = 0; want < NRES; want++) { 329 if (pl->res[want] >= cost[want] || !g->bank[want]) continue; 330 for (int give = 0; give < NRES; give++) { 331 if (give == want) continue; 332 int ratio = game_bank_ratio(g, p, give); 333 if (pl->res[give] >= cost[give] + ratio) { 334 m->type = M_BANK; m->a = (int16_t)give; m->b = (int16_t)want; m->c = 1; 335 return true; 336 } 337 } 338 } 339 return false; 340 } 341 342 /* Cuanto le sirve a p dar give y recibir get: lo que le falta para su objetivo vale triple. */ 343 static int trade_value(const Game *g, int p, const uint8_t give[NRES], const uint8_t get[NRES]) 344 { 345 uint8_t cost[NRES]; 346 bot_goal(g, p, cost); 347 int v = 0; 348 for (int r = 0; r < NRES; r++) { 349 v += get[r] * (g->p[p].res[r] < cost[r] ? 3 : 1); 350 v -= give[r] * (g->p[p].res[r] - give[r] < cost[r] ? 3 : 1); 351 } 352 return v; 353 } 354 355 /* 1 por 1: lo que mas le falta a p (y tiene "of") contra lo que mas le sobra. 356 * give/get desde p. false si no hay nada razonable. */ 357 static bool one_for_one(const Game *g, int p, int of, uint8_t give[NRES], uint8_t get[NRES]) 358 { 359 uint8_t cost[NRES]; 360 bot_goal(g, p, cost); 361 const Player *me = &g->p[p]; 362 int want = -1, ws = 0, put = -1, ps = 0; 363 for (int r = 0; r < NRES; r++) { 364 int need = cost[r] - me->res[r]; 365 bool has = false; 366 for (int q = 0; q < g->o.np; q++) 367 if (q != p && !g->p[q].neutral && (of < 0 || q == of) && g->p[q].res[r]) has = true; 368 if (need > ws && has) { ws = need; want = r; } 369 } 370 for (int r = 0; r < NRES; r++) { 371 int spare = me->res[r] - cost[r]; 372 if (r != want && spare > ps) { ps = spare; put = r; } 373 } 374 if (want < 0 || put < 0) return false; 375 memset(give, 0, NRES); 376 memset(get, 0, NRES); 377 give[put] = 1; 378 get[want] = 1; 379 return true; 380 } 381 382 /* Contraoferta a la oferta abierta (false: no tiene una mejor que proponer). */ 383 bool bot_counter(const Game *g, int p, Move *m) 384 { 385 const Offer *o = &g->offer; 386 if (!o->active || game_vp_public(g, o->from) >= 8) return false; 387 memset(m, 0, sizeof *m); 388 m->p = (int8_t)p; 389 m->type = M_COUNTER; 390 if (!one_for_one(g, p, o->from, m->r, m->r2)) return false; 391 if (!memcmp(m->r, o->get, NRES) && !memcmp(m->r2, o->give, NRES)) return false; /* es la misma */ 392 return trade_value(g, p, m->r, m->r2) > 0 && game_check(g, m) == E_OK; 393 } 394 395 static bool respond_offer(const Game *g, int p, Move *m) 396 { 397 const Offer *o = &g->offer; 398 bool ok = trade_value(g, p, o->get, o->give) > 0 && game_vp_public(g, o->from) < 8 && game_can_afford(g, p, o->get); 399 if (ok) { m->type = M_ACCEPT; return true; } 400 if (bot_counter(g, p, m)) return true; 401 m->type = M_REJECT; 402 return true; 403 } 404 405 /* Oferta propia de 1 por 1 a los que tienen lo que falta (una por turno). */ 406 bool bot_offer(const Game *g, int p, Move *m) 407 { 408 if (g->offers || g->offer.active) return false; 409 uint8_t give[NRES], get[NRES]; 410 if (!one_for_one(g, p, -1, give, get) || trade_value(g, p, give, get) <= 0) return false; 411 int mask = 0, want = 0; 412 for (int r = 0; r < NRES; r++) if (get[r]) want = r; 413 for (int q = 0; q < g->o.np; q++) 414 if (q != p && !g->p[q].neutral && g->p[q].res[want] && game_vp_public(g, q) < 8) mask |= 1 << q; 415 if (!mask) return false; 416 memset(m, 0, sizeof *m); 417 m->p = (int8_t)p; 418 m->type = M_OFFER; 419 m->a = (int16_t)mask; 420 memcpy(m->r, give, NRES); 421 memcpy(m->r2, get, NRES); 422 return game_check(g, m) == E_OK; 423 } 424 425 /* ¿falta que alguien conteste la oferta de p? */ 426 bool bot_offer_pending(const Game *g, int p) 427 { 428 if (!g->offer.active || g->offer.from != p) return false; 429 for (int q = 0; q < g->o.np; q++) 430 if (q != p && ((g->offer.tomask >> q) & 1) && !g->p[q].neutral && g->offer.resp[q] == 0) return true; 431 return false; 432 } 433 434 /* Cierra la oferta de p con la mejor respuesta (aceptacion o contraoferta) o la cancela. */ 435 bool bot_close_offer(const Game *g, int p, Move *m) 436 { 437 const Offer *o = &g->offer; 438 int best = -1, bv = 0; 439 for (int q = 0; q < g->o.np; q++) { 440 int v; 441 if (o->resp[q] == 1) v = trade_value(g, p, o->give, o->get); 442 else if (o->resp[q] == 2) v = trade_value(g, p, o->cget[q], o->cgive[q]); 443 else continue; 444 Move t = { .type = M_CONFIRM, .p = (int8_t)p, .a = (int16_t)q }; 445 if (v > bv && game_check(g, &t) == E_OK) { bv = v; best = q; } 446 } 447 memset(m, 0, sizeof *m); 448 m->p = (int8_t)p; 449 m->type = best >= 0 ? M_CONFIRM : M_CANCEL; 450 m->a = (int16_t)(best >= 0 ? best : 0); 451 return true; 452 } 453 454 static bool neutral_build(const Game *g, int p, Rng *rng, Move *m) 455 { 456 int rival = game_rival(g, p); 457 m->type = M_NEUTRAL; 458 if (g->neutral_need == NEED_SETTLE && game_neutral_possible(g, NEED_SETTLE)) { 459 int bs = -1, prod[NRES]; 460 if (rival >= 0) production(g, rival, prod); 461 for (int n = 0; n < g->o.np; n++) { 462 if (!g->p[n].neutral || !g->p[n].settles) continue; 463 for (int v = 0; v < game_topo(g)->nvert; v++) 464 if (game_can_settle(g, n, v, false)) { 465 int s = rival >= 0 ? vert_value_with(g, prod, v) : 0; /* bloquear al rival */ 466 if (s > bs) { bs = s; m->a = (int16_t)n; m->b = 1; m->c = (int16_t)v; } 467 } 468 } 469 return bs >= 0; 470 } 471 for (int n = 0; n < g->o.np; n++) { 472 if (!g->p[n].neutral || !g->p[n].roads) continue; 473 int e = any_legal_road(g, n, rng); 474 if (e >= 0) { m->a = (int16_t)n; m->b = 0; m->c = (int16_t)e; return true; } 475 } 476 return false; 477 } 478 479 static bool main_turn(const Game *g, int p, Rng *rng, Move *m) 480 { 481 const Player *pl = &g->p[p]; 482 uint8_t cost[NRES]; 483 484 if (g->offer.active && g->offer.from == p) { 485 if (bot_offer_pending(g, p)) return false; /* esperando respuestas */ 486 return bot_close_offer(g, p, m); 487 } 488 489 if (!g->dev_played && g->phase == PH_MAIN) { /* en el turno de pareja no hay cartas */ 490 if (pl->dev[D_KNIGHT] && (bot_robber_on_me(g, p) || 491 (pl->knights + 1 >= 3 && (g->army < 0 || (g->army != p && pl->knights + 1 > g->p[g->army].knights))))) { 492 m->type = M_KNIGHT; return true; 493 } 494 if (pl->dev[D_MONO]) { 495 int best = -1, bn = 3; 496 for (int r = 0; r < NRES; r++) { 497 int n = 0; 498 for (int q = 0; q < g->o.np; q++) if (q != p) n += g->p[q].res[r]; 499 if (n > bn) { bn = n; best = r; } 500 } 501 if (best >= 0) { m->type = M_MONO; m->a = (int16_t)best; return true; } 502 } 503 if (pl->dev[D_PLENTY]) { 504 bot_goal(g, p, cost); 505 int a = -1, b = -1; 506 uint8_t have[NRES]; 507 memcpy(have, pl->res, NRES); 508 for (int k = 0; k < 2; k++) 509 for (int r = 0; r < NRES; r++) 510 if (have[r] < cost[r] && g->bank[r] > (a == r ? 1 : 0)) { 511 if (a < 0) a = r; else b = r; 512 have[r]++; 513 break; 514 } 515 if (a >= 0) { 516 if (b < 0) b = a == GRAIN ? ORE : GRAIN; 517 m->type = M_PLENTY; m->a = (int16_t)a; m->b = (int16_t)b; 518 if (game_check(g, m) == E_OK) return true; 519 } 520 } 521 if (pl->dev[D_ROADS] && pl->roads >= 2 && road_toward_spot(g, p) >= 0) { m->type = M_ROADS; return true; } 522 } 523 524 if (pl->cities && game_can_afford(g, p, COST_CITY)) { 525 int best = -1, bs = -1; 526 for (int v = 0; v < game_topo(g)->nvert; v++) 527 if (game_can_city(g, p, v)) { 528 int s = vert_value(g, p, v); 529 if (s > bs) { bs = s; best = v; } 530 } 531 if (best >= 0) { m->type = M_CITY; m->a = (int16_t)best; return true; } 532 } 533 if (pl->settles && game_can_afford(g, p, COST_SETTLE)) { 534 int v = best_settle_spot(g, p, false); 535 if (v >= 0) { m->type = M_SETTLE; m->a = (int16_t)v; return true; } 536 } 537 int kind = bot_goal(g, p, cost); 538 if (kind == 3 && game_can_afford(g, p, COST_ROAD)) { 539 int e = road_toward_spot(g, p); 540 if (e >= 0) { m->type = M_ROAD; m->a = (int16_t)e; return true; } 541 } 542 if (kind == 4 && game_can_afford(g, p, COST_SHIP)) { 543 int e = ship_toward_spot(g, p); 544 if (e >= 0) { m->type = M_SHIP; m->a = (int16_t)e; return true; } 545 } 546 if (g->deck_n && game_can_afford(g, p, COST_DEV) && (kind == 2 || hand_size(g, p) > 7)) { 547 m->type = M_BUYDEV; return true; 548 } 549 if (g->o.variant2p && bot_robber_on_me(g, p) && pl->tokens >= game_token_cost(g, p) && 550 g->terrain[g->robber] != T_DESERT) { 551 m->type = M_TOKROBBER; return true; 552 } 553 if (bot_offer(g, p, m)) return true; 554 if (bank_toward(g, p, cost, m)) return true; 555 (void)rng; 556 m->type = M_END; 557 return true; 558 } 559 560 /* el oro: lo que falta para el objetivo */ 561 static bool pick_gold(const Game *g, int seat, Move *m) 562 { 563 const Player *pl = &g->p[seat]; 564 uint8_t cost[NRES], have[NRES]; 565 bot_goal(g, seat, cost); 566 memcpy(have, pl->res, NRES); 567 m->type = M_GOLD; 568 for (int i = 0; i < pl->gold; i++) { 569 int best = -1, bs = -100; 570 for (int r = 0; r < NRES; r++) { 571 if (m->r[r] >= g->bank[r]) continue; 572 int s = (have[r] < cost[r] ? 10 : 0) - have[r]; 573 if (s > bs) { bs = s; best = r; } 574 } 575 if (best < 0) break; 576 m->r[best]++; 577 have[best]++; 578 } 579 return true; 580 } 581 582 bool bot_decide(const Game *g, int seat, Rng *rng, Move *m) 583 { 584 memset(m, 0, sizeof *m); 585 m->p = (int8_t)seat; 586 if (!game_needs(g, seat)) return false; 587 const Player *pl = &g->p[seat]; 588 589 if (g->phase == PH_DISCARD) { 590 m->type = M_DISCARD; 591 bot_pick_discard(g, seat, pl->discard, m->r); 592 return true; 593 } 594 if (g->phase == PH_GOLD) return pick_gold(g, seat, m); /* le toca a cualquiera, no solo al del turno */ 595 if (seat != g->cur) return respond_offer(g, seat, m); 596 597 switch (g->phase) { 598 case PH_SETUP: 599 if (g->setup_sub == 0) { 600 m->type = M_SETTLE; 601 m->a = (int16_t)best_settle_spot(g, seat, true); 602 return m->a >= 0; 603 } else { 604 const Topo *t = game_topo(g); 605 int best = -1, bs = -1000; 606 for (int k = 0; k < 3; k++) { 607 int e = t->vert_edge[g->setup_v][k]; 608 Move tm = { .type = M_ROAD, .p = (int8_t)seat, .a = (int16_t)e }; 609 if (e < 0 || g->eown[e] >= 0 || game_check(g, &tm) != E_OK) continue; 610 int u = t->edge_v[e][0] == g->setup_v ? t->edge_v[e][1] : t->edge_v[e][0]; 611 int s = 0; 612 for (int j = 0; j < 3; j++) { 613 int w = t->vert_adj[u][j]; 614 if (w >= 0 && w != g->setup_v && game_can_settle(g, seat, w, true)) { 615 int val = vert_value(g, seat, w); 616 if (val > s) s = val; 617 } 618 } 619 if (s > bs) { bs = s; best = e; } 620 } 621 m->type = M_ROAD; 622 m->a = (int16_t)best; 623 return best >= 0; 624 } 625 case PH_ROLL: 626 if (pl->dev[D_KNIGHT] && !g->dev_played && bot_robber_on_me(g, seat)) { m->type = M_KNIGHT; return true; } 627 if (g->o.variant2p && bot_robber_on_me(g, seat) && pl->tokens >= game_token_cost(g, seat) && 628 g->terrain[g->robber] != T_DESERT) { m->type = M_TOKROBBER; return true; } 629 m->type = M_ROLL; 630 return true; 631 case PH_ROBBER: 632 pick_robber(g, seat, m); 633 return m->a >= 0; 634 case PH_ROADBUILD: { 635 int e = road_toward_spot(g, seat); 636 if (e < 0 && (e = ship_toward_spot(g, seat)) >= 0) { m->type = M_SHIP; m->a = (int16_t)e; return true; } 637 if (e < 0) e = any_legal_road(g, seat, rng); 638 if (e < 0) { m->type = M_END; return true; } 639 m->type = M_ROAD; m->a = (int16_t)e; 640 return true; 641 } 642 643 case PH_NEUTRAL: 644 return neutral_build(g, seat, rng, m); 645 case PH_GIVEBACK: 646 m->type = M_GIVEBACK; 647 bot_pick_discard(g, seat, g->give_back, m->r); 648 return true; 649 case PH_MAIN: case PH_PAIRED: /* pareja: lo que no vale lo filtra game_check */ 650 return main_turn(g, seat, rng, m); 651 } 652 return false; 653 }