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

auth.c (4134B)


      1 /* auth.c - la autoridad: valida, resuelve el azar, aplica y emite movidas. */
      2 #include <string.h>
      3 #include "catan.h"
      4 
      5 static void emit(Auth *a, const Move *m)
      6 {
      7     if (a->emit) a->emit(a->ctx, m);
      8 }
      9 
     10 static void apply_emit(Auth *a, const Move *m)
     11 {
     12     game_apply_u(&a->g, &a->undo, m);
     13     emit(a, m);
     14 }
     15 
     16 static int random_card(Auth *a, const uint8_t hand[NRES])
     17 {
     18     int n = res_total(hand);
     19     if (!n) return -1;
     20     int k = (int)rng_below(&a->rng, (uint32_t)n);
     21     for (int r = 0; r < NRES; r++) {
     22         if (k < hand[r]) return r;
     23         k -= hand[r];
     24     }
     25     return -1;
     26 }
     27 
     28 static void neutral_setup(Auth *a)
     29 {
     30     Game *g = &a->g;
     31     const Topo *t = game_topo(g);
     32     for (int round = 0; round < g->o.neutral_setup; round++)
     33         for (int n = 0; n < g->o.np; n++) {
     34             if (!g->p[n].neutral) continue;
     35             int cand[NVERT], nc = 0;
     36             for (int v = 0; v < t->nvert; v++)
     37                 if (game_can_settle(g, n, v, true)) cand[nc++] = v;
     38             if (!nc) continue;
     39             Move m = { .type = M_NEUTRAL, .p = (int8_t)n, .a = (int16_t)n, .b = 1 };
     40             m.c = (int16_t)cand[rng_below(&a->rng, (uint32_t)nc)];
     41             apply_emit(a, &m);
     42             int ec[3], ne = 0;
     43             for (int k = 0; k < 3; k++) {
     44                 int e = t->vert_edge[m.c][k];
     45                 if (e >= 0 && game_can_road(g, n, e)) ec[ne++] = e;
     46             }
     47             if (!ne) continue;
     48             Move r = { .type = M_NEUTRAL, .p = (int8_t)n, .a = (int16_t)n, .b = 0 };
     49             r.c = (int16_t)ec[rng_below(&a->rng, (uint32_t)ne)];
     50             apply_emit(a, &r);
     51         }
     52 }
     53 
     54 void board_make(Game *g, const Opts *o, Rng *game_rng)
     55 {
     56     int board = opts_board(o);
     57     Rng br;
     58     Rng *rng = game_rng;
     59     if (o->bseed) { rng_seed(&br, o->bseed, 0xB0A2D); rng = &br; }   /* el tablero que eligio quien crea */
     60     if (o->beginner && board == BOARD_CLASSIC) board_beginner(g);
     61     else board_random(g, board, rng);
     62     game_init(g, o);
     63 }
     64 
     65 void auth_new(Auth *a, const Opts *o, uint64_t seed, EmitFn fn, void *ctx)
     66 {
     67     memset(a, 0, sizeof *a);
     68     a->seed = seed;
     69     a->emit = fn;
     70     a->ctx = ctx;
     71     rng_seed(&a->rng, seed, 0xCA7A);
     72     board_make(&a->g, o, &a->rng);
     73 
     74     uint8_t COUNT[NDEV];
     75     int ndeck = dev_counts(o, COUNT);
     76     int k = 0;
     77     for (int d = 0; d < NDEV; d++)
     78         for (int i = 0; i < COUNT[d]; i++) a->deck[k++] = (uint8_t)d;
     79     for (int i = ndeck - 1; i > 0; i--) {
     80         int j = (int)rng_below(&a->rng, (uint32_t)i + 1);
     81         uint8_t tmp = a->deck[i]; a->deck[i] = a->deck[j]; a->deck[j] = tmp;
     82     }
     83     if (o->variant2p) neutral_setup(a);
     84 }
     85 
     86 int auth_submit(Auth *a, Move *m)
     87 {
     88     Game *g = &a->g;
     89     if (m->type == M_WIN || m->type == M_NONE || m->type >= M__COUNT) return E_ARGS;
     90     if (m->type == M_NEUTRAL && g->phase == PH_SETUP) return E_PHASE;
     91     int e = game_check(g, m);
     92     if (e) return e;
     93 
     94     switch (m->type) {
     95     case M_ROLL:
     96         m->r[0] = (uint8_t)(1 + rng_below(&a->rng, 6));
     97         m->r[1] = (uint8_t)(1 + rng_below(&a->rng, 6));
     98         m->r[2] = m->r[3] = 0;
     99         if (g->o.variant2p)
    100             do {
    101                 m->r[2] = (uint8_t)(1 + rng_below(&a->rng, 6));
    102                 m->r[3] = (uint8_t)(1 + rng_below(&a->rng, 6));
    103             } while (m->r[2] + m->r[3] == m->r[0] + m->r[1]);
    104         m->r[4] = 0;
    105         break;
    106     case M_ROBBER:
    107         m->c = (int16_t)(m->b >= 0 ? random_card(a, g->p[m->b].res) : -1);
    108         break;
    109     case M_BUYDEV:
    110         m->a = a->deck[g->deck_n - 1];
    111         break;
    112     case M_TOKTRADE: {
    113         int r = game_rival(g, m->p);
    114         uint8_t hand[NRES] = { 0 };
    115         if (r >= 0) memcpy(hand, g->p[r].res, NRES);
    116         m->a = (int16_t)random_card(a, hand);
    117         if (m->a >= 0) hand[m->a]--;
    118         m->b = (int16_t)random_card(a, hand);
    119         break;
    120     }
    121     default:
    122         break;
    123     }
    124     apply_emit(a, m);
    125 
    126     int p = g->cur;
    127     if (g->winner < 0 && game_vp(g, p) >= g->o.vp_target) {
    128         Move w = { .type = M_WIN, .p = (int8_t)p };
    129         w.a = (int16_t)(g->p[p].dev[D_VP] + g->p[p].dev_new[D_VP]);
    130         apply_emit(a, &w);
    131     }
    132     return E_OK;
    133 }