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

export.c (10248B)


      1 /* export.c - la partida como texto legible (ver export.h). */
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <time.h>
      6 #include "export.h"
      7 #include "../core/ctrl.h"
      8 
      9 static const char *const COLOR_ES[] = { "rojo", "azul", "verde", "naranja", "blanco", "marrón" };
     10 static const char *const COLOR_EN[] = { "red", "blue", "green", "orange", "white", "brown" };
     11 
     12 static void putf(ExportPut put, void *ctx, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
     13 
     14 static void putf(ExportPut put, void *ctx, const char *fmt, ...)
     15 {
     16     char line[1024];
     17     va_list ap;
     18     va_start(ap, fmt);
     19     vsnprintf(line, sizeof line, fmt, ap);
     20     va_end(ap);
     21     put(ctx, line);
     22 }
     23 
     24 static void hex_name(const Game *g, int h, char *out, size_t n)
     25 {
     26     if (g->terrain[h] == T_SEA) snprintf(out, n, "~");
     27     else if (g->terrain[h] == T_DESERT) snprintf(out, n, "%s", terrain_name(T_DESERT));
     28     else snprintf(out, n, "%s %d", terrain_name(g->terrain[h]), g->num[h]);
     29 }
     30 
     31 static void port_name(const Game *g, int i, char *out, size_t n)
     32 {
     33     if (g->port[i] == PORT_ANY) snprintf(out, n, "3:1");
     34     else snprintf(out, n, "2:1 %s", res_name(g->port[i]));
     35 }
     36 
     37 /* " (junto a Bosque 8, Campo 5; puerto 3:1)" */
     38 static void where_vert(const Game *g, int v, char *out, size_t n)
     39 {
     40     const Topo *t = game_topo(g);
     41     int k = snprintf(out, n, " (%s ", g_lang ? "next to" : "junto a");
     42     bool first = true;
     43     for (int i = 0; i < 3; i++) {
     44         int h = t->vert_hex[v][i];
     45         if (h < 0 || k >= (int)n) continue;
     46         char hn[40];
     47         hex_name(g, h, hn, sizeof hn);
     48         k += snprintf(out + k, n - (size_t)k, "%s%s", first ? "" : ", ", hn);
     49         first = false;
     50     }
     51     if (t->vert_port[v] >= 0 && k < (int)n) {
     52         char pn[24];
     53         port_name(g, t->vert_port[v], pn, sizeof pn);
     54         k += snprintf(out + k, n - (size_t)k, "; %s %s", g_lang ? "port" : "puerto", pn);
     55     }
     56     if (k < (int)n) snprintf(out + k, n - (size_t)k, ")");
     57 }
     58 
     59 /* " (entre Bosque 8 y Campo 5)" o " (costa de Bosque 8)" */
     60 static void where_edge(const Game *g, int e, char *out, size_t n)
     61 {
     62     const Topo *t = game_topo(g);
     63     char a[40], b[40];
     64     hex_name(g, t->edge_hex[e][0], a, sizeof a);
     65     if (t->edge_hex[e][1] >= 0) {
     66         hex_name(g, t->edge_hex[e][1], b, sizeof b);
     67         snprintf(out, n, " (%s %s %s %s)", g_lang ? "between" : "entre", a, g_lang ? "and" : "y", b);
     68     } else {
     69         snprintf(out, n, " (%s %s)", g_lang ? "coast of" : "costa de", a);
     70     }
     71 }
     72 
     73 void export_header(const Game *g, const char *code, const char *const names[MAXP], const char *kinds,
     74                    ExportPut put, void *ctx)
     75 {
     76     bool en = g_lang;
     77     const Opts *o = &g->o;
     78     char buf[512];
     79     time_t now = time(0);
     80     char when[32];
     81     strftime(when, sizeof when, "%Y-%m-%d %H:%M", localtime(&now));
     82     putf(put, ctx, "# Catan%s%s", code ? " — " : "", code ? code : "");
     83     putf(put, ctx, "[%s \"%s\"]", en ? "Exported" : "Exportada", when);
     84     int k = 0;
     85     buf[0] = 0;
     86     for (int p = 0; p < o->np && k < (int)sizeof buf; p++) {
     87         const char *kind = g->p[p].neutral ? (en ? ", neutral" : ", neutral")
     88                          : kinds && kinds[p] == 'B' ? ", bot" : "";
     89         k += snprintf(buf + k, sizeof buf - (size_t)k, "%s%d %s (%s%s)", p ? " · " : "", p + 1,
     90                       names[p] ? names[p] : "?", (en ? COLOR_EN : COLOR_ES)[p], kind);
     91     }
     92     putf(put, ctx, "[%s \"%s\"]", en ? "Players" : "Jugadores", buf);
     93     static const char *const SCEN_ES[] = { "", "Navegantes: Nuevas costas", "Navegantes: Cuatro islas", "Navegantes: Archipiélago" };
     94     static const char *const SCEN_EN[] = { "", "Seafarers: New shores", "Seafarers: Four islands", "Seafarers: Archipelago" };
     95     int fam = game_topo(g)->family;
     96     char kind[96];
     97     if (o->scenario && o->scenario < SCEN__COUNT)
     98         snprintf(kind, sizeof kind, "%s, %s %s", (en ? SCEN_EN : SCEN_ES)[o->scenario], en ? "map" : "mapa", board_name(o->board));
     99     else if (fam == BF_LARGE)
    100         snprintf(kind, sizeof kind, "%s, %s %s", en ? "5-6 board, paired players" : "tablero 5-6, jugadores en pareja",
    101                  en ? "map" : "mapa", board_name(o->board));
    102     else if (o->beginner)
    103         snprintf(kind, sizeof kind, "%s", en ? "beginner board" : "tablero de principiante");
    104     else
    105         snprintf(kind, sizeof kind, "%s %s", en ? "random board, map" : "tablero al azar, mapa", board_name(o->board));
    106     snprintf(buf, sizeof buf, "%d %s · %s %d %s · %s%s%s",
    107              o->np, en ? "seats" : "asientos", en ? "to" : "a", o->vp_target, en ? "points" : "puntos", kind,
    108              o->variant2p ? (en ? " · 2-player variant" : " · variante para 2") : "",
    109              o->freeplay ? (en ? " · free play" : " · juego libre") : "");
    110     putf(put, ctx, "[%s \"%s\"]", en ? "Options" : "Opciones", buf);
    111     if (g->winner >= 0)
    112         snprintf(buf, sizeof buf, "%s %s %s %d %s, %s %d", en ? "over:" : "terminada:", names[g->winner],
    113                  en ? "won with" : "ganó con", game_vp(g, g->winner), tr(S_VP), en ? "turn" : "turno", g->turn + 1);
    114     else
    115         snprintf(buf, sizeof buf, "%s %d", en ? "in play, turn" : "en juego, turno", g->turn + 1);
    116     putf(put, ctx, "[%s \"%s\"]", en ? "State" : "Estado", buf);
    117 
    118     /* tablero por filas */
    119     const Topo *t = game_topo(g);
    120     putf(put, ctx, "%s", "");
    121     putf(put, ctx, "## %s", en ? "Board" : "Tablero");
    122     int row = -100;
    123     k = 0;
    124     buf[0] = 0;
    125     for (int h = 0; h <= t->nhex; h++) {
    126         if (h == t->nhex || t->r[h] != row) {
    127             if (buf[0]) putf(put, ctx, "%s", buf);
    128             if (h == t->nhex) break;
    129             row = t->r[h];
    130             k = snprintf(buf, sizeof buf, "%s %d:", en ? "Row" : "Fila", row - t->r[0] + 1);
    131         }
    132         char hn[40];
    133         hex_name(g, h, hn, sizeof hn);
    134         if (k < (int)sizeof buf)
    135             k += snprintf(buf + k, sizeof buf - (size_t)k, " %s%s", hn, h == g->robber ? "*" : h == g->pirate ? "P" : "");
    136     }
    137     k = snprintf(buf, sizeof buf, "%s:", en ? "Ports" : "Puertos");
    138     for (int i = 0; i < t->nport && k < (int)sizeof buf; i++) {
    139         char pn[24], hn[40];
    140         port_name(g, i, pn, sizeof pn);
    141         int e = t->port_edge[i], h = t->edge_hex[e][0];
    142         if (h >= 0 && !ter_land(g->terrain[h]) && t->edge_hex[e][1] >= 0) h = t->edge_hex[e][1];   /* el de tierra */
    143         hex_name(g, h, hn, sizeof hn);
    144         k += snprintf(buf + k, sizeof buf - (size_t)k, "%s %s (%s %s)", i ? "," : "", pn, en ? "by" : "junto a", hn);
    145     }
    146     putf(put, ctx, "%s", buf);
    147     putf(put, ctx, "(* = %s%s)", en ? "robber" : "ladrón", g->pirate < t->nhex ? (en ? ", P = pirate" : ", P = pirata") : "");
    148 }
    149 
    150 void export_game(const char *hdr, const char *const *moves, int nmoves, const char *code,
    151                  const char *const names[MAXP], const char *kinds, unsigned viewers, ExportPut put, void *ctx)
    152 {
    153     static Game g, end;
    154     static Undo u;
    155     bool en = g_lang;
    156     if (!hdr_parse(hdr, &end)) return;
    157     u.n = 0;
    158     for (int i = 0; i < nmoves; i++) {                /* el estado final, para la cabecera */
    159         Move m;
    160         if (move_parse(moves[i], &m)) game_apply_u(&end, &u, &m);
    161     }
    162     export_header(&end, code, names, kinds, put, ctx);      /* estado y ladron de ahora */
    163     hdr_parse(hdr, &g);
    164 
    165     putf(put, ctx, "%s", "");
    166     putf(put, ctx, "## %s", en ? "Game" : "Partida");
    167     putf(put, ctx, "### %s", en ? "Initial placement" : "Colocación inicial");
    168     u.n = 0;
    169     int turn = -1;
    170     for (int i = 0; i < nmoves; i++) {
    171         Move m;
    172         if (!move_parse(moves[i], &m)) continue;
    173         if (g.phase != PH_SETUP && g.turn != turn && m.type == M_ROLL) {
    174             turn = g.turn;
    175             putf(put, ctx, "### %s %d — %s", en ? "Turn" : "Turno", g.turn + 1, names[g.cur] ? names[g.cur] : "?");
    176         }
    177         uint8_t before[MAXP][NRES];
    178         for (int p = 0; p < MAXP; p++) memcpy(before[p], g.p[p].res, NRES);
    179         game_apply_u(&g, &u, &m);
    180         char line[400], where[160] = "";
    181         move_describe_for(&g, &m, names, viewers, line, sizeof line);
    182         if (m.type == M_SETTLE || m.type == M_CITY) where_vert(&g, m.a, where, sizeof where);
    183         else if (m.type == M_ROAD || m.type == M_SHIP) where_edge(&g, m.a, where, sizeof where);
    184         else if (m.type == M_NEUTRAL) {
    185             if (m.b == 1) where_vert(&g, m.c, where, sizeof where);
    186             else where_edge(&g, m.c, where, sizeof where);
    187         }
    188         putf(put, ctx, "  %s%s", line, where);
    189         if (m.type == M_END && g.phase == PH_PAIRED)
    190             putf(put, ctx, "  %s %s", names[g.cur] ? names[g.cur] : "?", tr(S_PLAYS_PAIRED));
    191         if (m.type == M_ROLL) {                       /* que produjo la tirada */
    192             char got[400];
    193             int k = 0;
    194             got[0] = 0;
    195             for (int p = 0; p < g.o.np && k < (int)sizeof got; p++)
    196                 for (int r = 0; r < NRES; r++) {
    197                     int d = g.p[p].res[r] - before[p][r];
    198                     if (d > 0 && k < (int)sizeof got)
    199                         k += snprintf(got + k, sizeof got - (size_t)k, "%s%s +%d %s", k ? ", " : "", names[p], d, res_name(r));
    200                 }
    201             if (got[0]) putf(put, ctx, "    → %s", got);
    202         }
    203     }
    204 
    205     if (end.winner >= 0) {
    206         putf(put, ctx, "%s", "");
    207         putf(put, ctx, "## %s", en ? "Final score" : "Puntos al final");
    208         for (int p = 0; p < end.o.np; p++) {
    209             const Player *pl = &end.p[p];
    210             if (pl->neutral) continue;
    211             putf(put, ctx, "  %s: %d %s (%d %s, %d %s%s%s, %d %s)", names[p], game_vp(&end, p), tr(S_VP),
    212                  MAX_SETTLES - pl->settles, en ? "settlements" : "pueblos", MAX_CITIES - pl->cities,
    213                  en ? "cities" : "ciudades", end.longest == p ? (en ? ", longest road" : ", camino más largo") : "",
    214                  end.army == p ? (en ? ", largest army" : ", ejército más grande") : "",
    215                  pl->dev[D_VP] + pl->dev_new[D_VP], en ? "VP cards" : "cartas de PV");
    216         }
    217     }
    218 
    219     putf(put, ctx, "%s", "");
    220     putf(put, ctx, "## %s", en ? "Moves (game format)" : "Movidas (formato del juego)");
    221     putf(put, ctx, "%s", hdr);
    222     for (int i = 0; i < nmoves; i++) putf(put, ctx, "%s", moves[i]);
    223 }