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

persist.c (8999B)


      1 /* persist.c - guardar y cargar el estado: texto "clave=valor" por linea.
      2  * Los numeros van como "a,b,r,d,p|decimal" (exacto + decimal). */
      3 #include <string.h>
      4 #include "calc.h"
      5 #include "str.h"
      6 
      7 static int put_kv(char *buf, int n, int p, const char *k, const char *v)
      8 {
      9     if (p < 0) return p;
     10     p = str_put(buf, n, p, k);
     11     p = str_put(buf, n, p, "=");
     12     p = str_put(buf, n, p, v);
     13     return str_put(buf, n, p, "\n");
     14 }
     15 
     16 static int put_ki(char *buf, int n, int p, const char *k, long v)
     17 {
     18     char b[24];
     19     str_int(b, sizeof b, 0, v);
     20     return put_kv(buf, n, p, k, b);
     21 }
     22 
     23 static void num_text(const Num *v, char *b, int n)
     24 {
     25     int p = 0;
     26     if (v->exact) {
     27         p = i64_text(b, n, p, v->x.a); p = str_put(b, n, p, ",");
     28         p = i64_text(b, n, p, v->x.b); p = str_put(b, n, p, ",");
     29         p = i64_text(b, n, p, v->x.r); p = str_put(b, n, p, ",");
     30         p = i64_text(b, n, p, v->x.d); p = str_put(b, n, p, ",");
     31         p = str_int(b, n, p, v->x.p);
     32     }
     33     p = str_put(b, n, p, "|");
     34     dec_to_text(v->v, b + p, n - p);
     35 }
     36 
     37 /* int64 sin stdio */
     38 static const char *scan_i64(const char *s, int64_t *out)
     39 {
     40     bool neg = *s == '-';
     41     if (neg || *s == '+') s++;
     42     if (*s < '0' || *s > '9') return 0;
     43     uint64_t v = 0;
     44     while (*s >= '0' && *s <= '9') v = v * 10 + (uint64_t)(*s++ - '0');
     45     *out = neg ? -(int64_t)v : (int64_t)v;
     46     return s;
     47 }
     48 
     49 static Num text_num(const char *s)
     50 {
     51     Num r = num_dec(dec_parse(strchr(s, '|') ? strchr(s, '|') + 1 : s, 0));
     52     if (*s != '|') {
     53         int64_t f[5];
     54         const char *p = s;
     55         for (int i = 0; i < 5 && p; i++) {
     56             p = scan_i64(p, &f[i]);
     57             if (p && i < 4) { if (*p != ',') p = 0; else p++; }
     58         }
     59         if (p) {
     60             Ex x = { f[0], f[1], f[2], f[3], (uint8_t)f[4] };
     61             if (ex_norm(&x)) r = num_ex(&x);
     62         }
     63     }
     64     return r;
     65 }
     66 
     67 int persist_save(const Calc *c, char *buf, int n)
     68 {
     69     char b[300];
     70     int p = 0;
     71     buf[0] = 0;
     72     p = put_kv(buf, n, p, "calc", "1");
     73     p = put_ki(buf, n, p, "ang", c->ang);
     74     p = put_ki(buf, n, p, "dec", c->dec_default);
     75     p = put_ki(buf, n, p, "fmt", c->fmt.mode);
     76     p = put_ki(buf, n, p, "fmtn", c->fmt.n);
     77     p = put_ki(buf, n, p, "mixed", c->fmt.mixed);
     78     p = put_ki(buf, n, p, "digits", c->fmt.digits);
     79     p = put_ki(buf, n, p, "mode", c->mode);
     80     p = put_ki(buf, n, p, "base", c->pg.base);
     81     p = put_ki(buf, n, p, "bits", c->pg.bits);
     82     for (int i = 0; i < NVARS; i++) {
     83         char k[8] = "var";
     84         k[3] = VAR_NAMES[i]; k[4] = 0;
     85         num_text(&c->vars[i], b, sizeof b);
     86         p = put_kv(buf, n, p, k, b);
     87     }
     88     num_text(&c->ans, b, sizeof b); p = put_kv(buf, n, p, "ans", b);
     89     if (c->ans_im.v.m) { num_text(&c->ans_im, b, sizeof b); p = put_kv(buf, n, p, "ansi", b); }
     90     for (int i = 0; i < NVARS; i++) {
     91         if (!c->vars_im[i].v.m) continue;
     92         char k[8] = "vari";
     93         k[4] = VAR_NAMES[i]; k[5] = 0;
     94         num_text(&c->vars_im[i], b, sizeof b);
     95         p = put_kv(buf, n, p, k, b);
     96     }
     97     num_text(&c->preans, b, sizeof b); p = put_kv(buf, n, p, "preans", b);
     98     for (int i = 0; i < c->nh; i++) {
     99         expr_to_text(&c->hist[i].in, b, sizeof b);
    100         p = put_kv(buf, n, p, "h", b);
    101         num_text(&c->hist[i].res, b, sizeof b);
    102         int q = (int)strlen(b);
    103         str_put(b, sizeof b, q, c->hist[i].err ? "|e" : "");
    104         p = put_kv(buf, n, p, "hr", b);
    105         if (c->hist[i].res_im.v.m || c->hist[i].polar) {
    106             num_text(&c->hist[i].res_im, b, sizeof b);
    107             p = put_kv(buf, n, p, c->hist[i].polar ? "hp" : "hi", b);
    108         }
    109     }
    110     /* matrices y vectores: "mA=filas,columnas;n;n;..." */
    111     for (int k = 0; k < 8; k++) {
    112         const MVal *m = k < 4 ? &c->mt.m[k] : &c->mt.v[k - 4];
    113         if (!m->r) continue;
    114         static char mb[1600];
    115         int q = str_int(mb, sizeof mb, 0, m->r);
    116         q = str_put(mb, sizeof mb, q, ",");
    117         q = str_int(mb, sizeof mb, q, m->c);
    118         for (int i = 0; i < m->r; i++)
    119             for (int j = 0; j < m->c; j++) {
    120                 num_text(mv_get(m, i, j), b, sizeof b);
    121                 q = str_put(mb, sizeof mb, q, ";");
    122                 q = str_put(mb, sizeof mb, q, b);
    123             }
    124         char key[3] = { k < 4 ? 'm' : 'v', (char)('A' + k % 4), 0 };
    125         p = put_kv(buf, n, p, key, mb);
    126     }
    127     /* estadistica */
    128     p = put_ki(buf, n, p, "stt", c->st.type);
    129     for (int i = 0; i < c->st.n; i++) {
    130         num_text(&c->st.x[i], b, sizeof b); p = put_kv(buf, n, p, "sx", b);
    131         num_text(&c->st.y[i], b, sizeof b); p = put_kv(buf, n, p, "sy", b);
    132     }
    133     expr_to_text(&c->tb.f, b, sizeof b); p = put_kv(buf, n, p, "tf", b);
    134     expr_to_text(&c->tb.g, b, sizeof b); p = put_kv(buf, n, p, "tg", b);
    135     expr_to_text(&c->gr.f, b, sizeof b); p = put_kv(buf, n, p, "gf", b);
    136     expr_to_text(&c->gr.g, b, sizeof b); p = put_kv(buf, n, p, "gg", b);
    137     return p < 0 ? (int)strlen(buf) : p;
    138 }
    139 
    140 void persist_load(Calc *c, const char *buf, int n)
    141 {
    142     static char line[320];
    143     const char *p = buf, *end = buf + n;
    144     int hcount = 0;
    145     while (p < end && *p) {
    146         int k = 0;
    147         while (p < end && *p && *p != '\n' && k < (int)sizeof line - 1) line[k++] = *p++;
    148         line[k] = 0;
    149         while (p < end && *p && *p != '\n') p++;
    150         if (p < end && *p == '\n') p++;
    151         char *eq = strchr(line, '=');
    152         if (!eq) continue;
    153         *eq = 0;
    154         const char *key = line, *val = eq + 1;
    155         long v = 0;
    156         bool num = str_scan_int(val, &v) != 0;
    157         if (!strcmp(key, "ang") && num && v >= 0 && v < 3) c->ang = (int)v;
    158         else if (!strcmp(key, "dec") && num) c->dec_default = v != 0;
    159         else if (!strcmp(key, "fmt") && num && v >= 0 && v <= FMT_ENG) c->fmt.mode = (uint8_t)v;
    160         else if (!strcmp(key, "fmtn") && num && v >= 0 && v <= 9) c->fmt.n = (uint8_t)v;
    161         else if (!strcmp(key, "mixed") && num) c->fmt.mixed = v != 0;
    162         else if (!strcmp(key, "digits") && num && (v == 10 || v == 12 || v == 15)) c->fmt.digits = (uint8_t)v;
    163         else if (!strcmp(key, "mode") && num && v >= 0 && v < NMODES) c->mode = (int)v;
    164         else if (!strcmp(key, "base") && num && (v == 2 || v == 8 || v == 10 || v == 16)) c->pg.base = (int)v;
    165         else if (!strcmp(key, "bits") && num && (v == 32 || v == 64 || v == 16 || v == 8)) c->pg.bits = (int)v;
    166         else if (!strncmp(key, "vari", 4) && key[4] && !key[5]) {
    167             const char *vn = strchr(VAR_NAMES, key[4]);
    168             if (vn) c->vars_im[vn - VAR_NAMES] = text_num(val);
    169         } else if (!strcmp(key, "ansi")) c->ans_im = text_num(val);
    170         else if ((!strcmp(key, "hi") || !strcmp(key, "hp")) && hcount > 0) {
    171             c->hist[hcount - 1].res_im = text_num(val);
    172             c->hist[hcount - 1].polar = key[1] == 'p';
    173         }
    174         else if (!strncmp(key, "var", 3) && key[3] && !key[4]) {
    175             const char *vn = strchr(VAR_NAMES, key[3]);
    176             if (vn) c->vars[vn - VAR_NAMES] = text_num(val);
    177         } else if ((key[0] == 'm' || key[0] == 'v') && key[1] >= 'A' && key[1] <= 'D' && !key[2]) {
    178             MVal *m = key[0] == 'm' ? &c->mt.m[key[1] - 'A'] : &c->mt.v[key[1] - 'A'];
    179             long r = 0, cc = 0;
    180             const char *q = str_scan_int(val, &r);
    181             if (!q || *q != ',' || !(q = str_scan_int(q + 1, &cc)) || r < 1 || r > MAT_N || cc < 1 || cc > MAT_N) continue;
    182             mv_zero(m, key[0] == 'm' ? MV_MAT : MV_VEC, (int)r, (int)cc);
    183             for (int i = 0; i < r * cc && *q == ';'; i++) {
    184                 q++;
    185                 static char one[300];
    186                 int l = 0;
    187                 while (q[l] && q[l] != ';' && l < (int)sizeof one - 1) { one[l] = q[l]; l++; }
    188                 one[l] = 0;
    189                 *mv_at(m, (int)(i / cc), (int)(i % cc)) = text_num(one);
    190                 q += l;
    191             }
    192         } else if (!strcmp(key, "ans")) c->ans = text_num(val);
    193         else if (!strcmp(key, "preans")) c->preans = text_num(val);
    194         else if (!strcmp(key, "h") && hcount < HIST_MAX) {
    195             if (expr_from_text(&c->hist[hcount].in, val)) hcount++;
    196         } else if (!strcmp(key, "hr") && hcount > 0) {
    197             Hist *h = &c->hist[hcount - 1];
    198             h->res = text_num(val);
    199             h->err = strstr(val, "|e") != 0;
    200             h->dec = 0;
    201             h->res_im = num_int(0);
    202             h->polar = 0;
    203         } else if (!strcmp(key, "stt") && num && v >= 0 && v < ST_NTYPES) c->st.type = (int)v;
    204         else if (!strcmp(key, "sx") && c->st.n < STAT_MAX) { c->st.x[c->st.n] = text_num(val); c->st.y[c->st.n] = num_int(0); c->st.n++; }
    205         else if (!strcmp(key, "sy") && c->st.n > 0) c->st.y[c->st.n - 1] = text_num(val);
    206         else if (!strcmp(key, "tf")) expr_from_text(&c->tb.f, val);
    207         else if (!strcmp(key, "tg")) expr_from_text(&c->tb.g, val);
    208         else if (!strcmp(key, "gf")) expr_from_text(&c->gr.f, val);
    209         else if (!strcmp(key, "gg")) expr_from_text(&c->gr.g, val);
    210     }
    211     c->nh = hcount;
    212     c->hsel = -1;
    213 }