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

tui_modes.c (12497B)


      1 /* tui_modes.c - los modos (Ecuaciones, Tabla, Grafico, Estadistica) en la terminal. */
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include "tuikit.h"
      5 #include "calc.h"
      6 #include "layout.h"
      7 #include "dmath.h"
      8 
      9 #define BG     RGB(18, 22, 30)
     10 #define PANEL  RGB(30, 36, 50)
     11 #define FG     RGB(236, 236, 236)
     12 #define DIM    RGB(130, 138, 156)
     13 #define ACC    RGB(255, 200, 60)
     14 #define RESC   RGB(140, 220, 255)
     15 #define SEL    RGB(48, 58, 80)
     16 #define ERRC   RGB(255, 100, 90)
     17 #define FCOL   RGB(120, 200, 255)
     18 #define GCOL   RGB(255, 140, 90)
     19 
     20 void draw_layout(const Layout *L, int y, int x, Color fg, Color bg, int x0, int w);
     21 void text(int y, int x, const char *s, Color fg, Color bg);
     22 void fill_row(int y, Color bg);
     23 void status(const Calc *c);
     24 void help(const char *s);
     25 const Metric *tui_metric(void);
     26 int  eq_cells(int type);
     27 const char *stat_type_name(int t);
     28 void graph_trace(Calc *c);
     29 extern int cur_y, cur_x;
     30 
     31 static Layout L_in;
     32 
     33 static void clear_all(void)
     34 {
     35     tk_attc(FG, BG, 0);
     36     for (int y = 0; y < LINES; y++) tk_fill(y, 0, COLS, " ");
     37 }
     38 
     39 static void val(const Calc *c, const Num *v, bool err, char *b, int n)
     40 {
     41     if (err || num_bad(v)) snprintf(b, n, "Error");
     42     else fmt_plain(v, &c->fmt, false, b, n);
     43 }
     44 
     45 /* caja de edicion con la entrada; devuelve las filas usadas */
     46 static int input_box(const Calc *c, const char *label, int y)
     47 {
     48     layout_expr(&c->in, tui_metric(), &L_in);
     49     int h = L_in.asc + L_in.desc;
     50     if (h < 1) h = 1;
     51     for (int k = 0; k < h + 2; k++) fill_row(y + k, PANEL);
     52     tk_attc(ACC, PANEL, 0);
     53     tk_fill(y, 0, COLS, "─");
     54     int x = 2;
     55     if (label) { text(y + 1 + L_in.asc - 1, 2, label, ACC, PANEL); x += tk_ulen(label) + 1; }
     56     int avail = COLS - x - 2, cx = L_in.gx[c->in.cur], sc = cx > avail - 1 ? cx - avail + 1 : 0;
     57     draw_layout(&L_in, y + 1, x - sc, FG, PANEL, x, avail);
     58     cur_y = y + 1 + L_in.gy[c->in.cur];
     59     cur_x = x - sc + cx;
     60     return h + 2;
     61 }
     62 
     63 static void cplx_text(const Calc *c, const Cplx *z, char *b, int n)
     64 {
     65     char re[48], im[48];
     66     fmt_plain(&z->re, &c->fmt, false, re, sizeof re);
     67     if (!z->im.v.m) { snprintf(b, n, "%s", re); return; }
     68     Num a = z->im;
     69     bool neg = a.v.neg;
     70     if (neg) a = num_neg(a);
     71     fmt_plain(&a, &c->fmt, false, im, sizeof im);
     72     bool one = a.exact && ex_is_int(&a.x) && a.x.a == 1;
     73     if (!z->re.v.m) snprintf(b, n, "%s%si", neg ? "-" : "", one ? "" : im);
     74     else snprintf(b, n, "%s %s %si", re, neg ? "-" : "+", one ? "" : im);
     75 }
     76 
     77 /* ------------------------------------------------------------ ecuaciones */
     78 
     79 static void eqn(Calc *c)
     80 {
     81     EqnState *q = &c->eq;
     82     static const char *const T[] = { "Sistema 2×2", "Sistema 3×3", "Polinomio de grado 2", "Polinomio de grado 3", "SOLVE" };
     83     clear_all();
     84     status(c);
     85     text(2, 2, T[q->type], ACC, BG);
     86     char b[160];
     87     if (q->type == EQ_SOLVE && q->phase == 0) {
     88         text(4, 2, "Ecuación con X (sin = es = 0). Busca cerca del valor actual de X.", DIM, BG);
     89         input_box(c, 0, 7);
     90         help("Enter resuelve   Esc borra / cambia el tipo");
     91         return;
     92     }
     93     if (q->phase == 0) {
     94         static const char *const F[] = { "a·x + b·y = c", "a·x + b·y + c·z = d", "a·x² + b·x + c = 0", "a·x³ + b·x² + c·x + d = 0" };
     95         text(4, 2, F[q->type], DIM, BG);
     96         int cols = q->type == EQ_SYS2 || q->type == EQ_POLY2 ? 3 : 4, rows = eq_cells(q->type) / cols, cw = 16;
     97         for (int j = 0; j < cols; j++) { char h[2] = { (char)('a' + j), 0 }; text(6, 4 + j * cw + cw - 3, h, ACC, BG); }
     98         for (int i = 0; i < rows; i++)
     99             for (int j = 0; j < cols; j++) {
    100                 int k = i * cols + j;
    101                 bool sel = k == q->sel;
    102                 tk_attc(FG, sel ? SEL : PANEL, 0);
    103                 tk_fill(7 + i, 4 + j * cw, cw - 1, " ");
    104                 val(c, &q->coef[k], false, b, sizeof b);
    105                 text(7 + i, 4 + j * cw + cw - 2 - tk_ulen(b), b, sel ? ACC : FG, sel ? SEL : PANEL);
    106             }
    107         if (q->editing) input_box(c, "=", 12);
    108         help(q->editing ? "Enter guarda   Esc cancela" : "Tipeá un valor   flechas   Enter resuelve   Esc tipo");
    109         return;
    110     }
    111     if (q->note[0]) { text(5, 2, q->note, ERRC, BG); help("Esc vuelve"); return; }
    112     if (q->type == EQ_SOLVE) {
    113         fmt_plain(&q->solve_x, &c->fmt, false, b, sizeof b);
    114         text(5, 2, "X = ", ACC, BG); text(5, 6, b, RESC, BG);
    115         fmt_plain(&q->solve_lr, &c->fmt, true, b, sizeof b);
    116         text(7, 2, "L-R = ", DIM, BG); text(7, 8, b, DIM, BG);
    117         help("Esc vuelve a la ecuación (X quedó guardado)");
    118         return;
    119     }
    120     static const char *const VN[] = { "x", "y", "z" };
    121     for (int i = 0; i < q->nsol; i++) {
    122         char nm[8];
    123         if (q->type <= EQ_SYS3) snprintf(nm, sizeof nm, "%s", VN[i]);
    124         else snprintf(nm, sizeof nm, "x%d", i + 1);
    125         cplx_text(c, &q->sol[i], b, sizeof b);
    126         Color bg = i == q->shown ? SEL : BG;
    127         tk_attc(FG, bg, 0);
    128         tk_fill(5 + i * 2, 1, COLS - 2, " ");
    129         text(5 + i * 2, 2, nm, ACC, bg);
    130         text(5 + i * 2, 6, "= ", DIM, bg);
    131         text(5 + i * 2, 8, b, RESC, bg);
    132     }
    133     if (q->type == EQ_POLY2 && q->nsol) {
    134         char x[48], y[48];
    135         fmt_plain(&q->sol[2].re, &c->fmt, false, x, sizeof x);
    136         fmt_plain(&q->sol[2].im, &c->fmt, false, y, sizeof y);
    137         snprintf(b, sizeof b, "%s: x = %s   y = %s", q->coef[0].v.neg ? "Máximo" : "Mínimo", x, y);
    138         text(11, 2, b, DIM, BG);
    139     }
    140     help("↑↓ elige   Tab decimal   Esc vuelve");
    141 }
    142 
    143 /* ------------------------------------------------------------ tabla */
    144 
    145 static void table(Calc *c)
    146 {
    147     TableState *t = &c->tb;
    148     clear_all();
    149     status(c);
    150     char b[96];
    151     if (t->phase < 2) {
    152         text(2, 2, t->phase == 0 ? "Tabla: f(x)" : "Tabla: g(x)", ACC, BG);
    153         text(4, 2, "Escribí la función con x. Enter sigue con el rango.", DIM, BG);
    154         input_box(c, t->phase == 0 ? "f(x)=" : "g(x)=", 7);
    155         help("Enter: rango   Esc borra");
    156         return;
    157     }
    158     int cols = t->use_g ? 3 : 2, cw = (COLS - 4) / cols;
    159     static const char *const H[] = { "x", "f(x)", "g(x)" };
    160     for (int j = 0; j < cols; j++) text(2, 2 + j * cw + cw - 1 - tk_ulen(H[j]), H[j], ACC, BG);
    161     int rows = LINES - 6;
    162     if (t->sel < t->top) t->top = t->sel;
    163     if (t->sel >= t->top + rows) t->top = t->sel - rows + 1;
    164     for (int r = t->top; r < t->rows && r < t->top + rows; r++) {
    165         int y = 3 + r - t->top;
    166         Color bg = r == t->sel ? SEL : BG;
    167         tk_attc(FG, bg, 0);
    168         tk_fill(y, 1, COLS - 2, " ");
    169         for (int j = 0; j < cols; j++) {
    170             const Num *v = j == 0 ? &t->x[r] : j == 1 ? &t->fx[r] : &t->gx[r];
    171             bool err = j == 1 ? t->ferr[r] : j == 2 ? t->gerr[r] : false;
    172             val(c, v, err, b, sizeof b);
    173             text(y, 2 + j * cw + cw - 1 - tk_ulen(b), b, err ? ERRC : j ? RESC : FG, bg);
    174         }
    175     }
    176     help("↑↓ recorre   Enter/Esc edita f(x)");
    177 }
    178 
    179 /* ------------------------------------------------------------ grafico */
    180 
    181 static void graph(Calc *c)
    182 {
    183     GraphState *g = &c->gr;
    184     clear_all();
    185     status(c);
    186     char b[160];
    187     if (g->phase < 2) {
    188         text(2, 2, g->phase == 0 ? "Gráfico: f(x)" : "Gráfico: g(x)", g->phase == 0 ? FCOL : GCOL, BG);
    189         text(4, 2, g->phase == 0 ? "Enter grafica.  ↓ agrega g(x)." : "Enter grafica.  ↑ vuelve a f(x).  Esc la saca.", DIM, BG);
    190         input_box(c, g->phase == 0 ? "f(x)=" : "g(x)=", 7);
    191         help("Enter grafica   w ventana (en el gráfico)");
    192         return;
    193     }
    194     int W = COLS < GRAPH_W ? COLS : GRAPH_W, Hc = LINES - 4, H = Hc * 2;
    195     if (g->w != W || g->h != H) { g->w = W; g->h = H; g->ready = false; }
    196     if (!g->ready) { graph_compute(c); graph_trace(c); }
    197     Surface *s = tk_pix_begin(W, Hc);
    198     if (!s) return;
    199     gfx_rect(s, 0, 0, W, H, BG);
    200     /* ejes */
    201     Dec xr = dec_sub(g->xmax, g->xmin), yr = dec_sub(g->ymax, g->ymin);
    202     int64_t v;
    203     if (dec_to_int(dec_round_int(dec_div(dec_mul_int(dec_neg(g->xmin), W - 1), xr)), &v) && v >= 0 && v < W) gfx_rect(s, (int)v, 0, 1, H, DIM);
    204     if (dec_to_int(dec_round_int(dec_div(dec_mul_int(g->ymax, H - 1), yr)), &v) && v >= 0 && v < H) gfx_rect(s, 0, (int)v, W, 1, DIM);
    205     for (int k = g->use_g ? 1 : 0; k >= 0; k--) {
    206         const int16_t *ys = k ? g->gy : g->fy;
    207         Color col = k ? GCOL : FCOL;
    208         for (int i = 0; i < W; i++) {
    209             if (ys[i] == INT16_MIN) continue;
    210             int y = ys[i];
    211             if (i && ys[i - 1] != INT16_MIN && ys[i - 1] - y < H && y - ys[i - 1] < H) {
    212                 int a = ys[i - 1] < y ? ys[i - 1] : y, bb = ys[i - 1] < y ? y : ys[i - 1];
    213                 if (a < 0) a = 0;
    214                 if (bb > H - 1) bb = H - 1;
    215                 if (a <= bb) gfx_rect(s, i, a, 1, bb - a + 1, col);
    216             } else if (y >= 0 && y < H) gfx_rect(s, i, y, 1, 1, col);
    217         }
    218     }
    219     const int16_t *ys = g->curve ? g->gy : g->fy;
    220     gfx_rect(s, g->tx, 0, 1, H, RGB(70, 70, 40));
    221     if (ys[g->tx] != INT16_MIN && ys[g->tx] >= 0 && ys[g->tx] < H) gfx_rect(s, g->tx - 1, ys[g->tx] - 1, 3, 3, ACC);
    222     tk_pix_blit(1, 0);
    223     Dec x = dec_add(g->xmin, dec_div_int(dec_mul_int(xr, g->tx), W - 1));
    224     Num xn = num_dec(dec_round_sig(x, 10));
    225     char xs[48], ys2[48];
    226     fmt_plain(&xn, &c->fmt, true, xs, sizeof xs);
    227     if (num_bad(&g->tval)) snprintf(ys2, sizeof ys2, "-");
    228     else fmt_plain(&g->tval, &c->fmt, true, ys2, sizeof ys2);
    229     fill_row(LINES - 2, PANEL);
    230     snprintf(b, sizeof b, "x = %s   %s = %s", xs, g->curve ? "g" : "f", ys2);
    231     text(LINES - 2, 2, b, g->curve ? GCOL : FCOL, PANEL);
    232     help("← → traza  ↑↓ curva  + - zoom  w ventana  Esc edita");
    233 }
    234 
    235 /* ------------------------------------------------------------ estadistica */
    236 
    237 static void stat(Calc *c)
    238 {
    239     StatState *t = &c->st;
    240     clear_all();
    241     status(c);
    242     char b[96];
    243     text(1, 2, stat_type_name(t->type), ACC, BG);
    244     if (t->phase == 1) {
    245         int rows = LINES - 4;
    246         for (int i = t->rtop; i < t->nres && i < t->rtop + rows; i++) {
    247             text(2 + i - t->rtop, 3, t->rlabel[i], ACC, BG);
    248             val(c, &t->rval[i], t->rerr[i], b, sizeof b);
    249             text(2 + i - t->rtop, 12, b, RESC, BG);
    250         }
    251         help("↑↓ recorre   Esc vuelve a los datos");
    252         return;
    253     }
    254     int cols = t->type == ST_1VAR ? 1 : 2, cw = 22;
    255     text(2, 8 + cw - 2, "x", ACC, BG);
    256     if (cols == 2) text(2, 8 + 2 * cw - 2, "y", ACC, BG);
    257     int rows = LINES - (t->editing ? 9 : 5);
    258     if (t->row < t->top) t->top = t->row;
    259     if (t->row >= t->top + rows) t->top = t->row - rows + 1;
    260     for (int r = t->top; r <= t->n && r < t->top + rows; r++) {
    261         int y = 3 + r - t->top;
    262         snprintf(b, sizeof b, "%3d", r + 1);
    263         text(y, 2, b, DIM, BG);
    264         for (int j = 0; j < cols; j++) {
    265             bool sel = r == t->row && j == t->col;
    266             Color bg = sel ? SEL : BG;
    267             tk_attc(FG, bg, 0);
    268             tk_fill(y, 7 + j * cw, cw - 1, " ");
    269             if (r < t->n) {
    270                 val(c, j ? &t->y[r] : &t->x[r], false, b, sizeof b);
    271                 text(y, 7 + j * cw + cw - 2 - tk_ulen(b), b, FG, bg);
    272             }
    273         }
    274     }
    275     if (t->editing) input_box(c, "=", LINES - 5);
    276     help(t->editing ? "Enter guarda   Esc cancela" : "Tipeá valores   Supr borra la fila   Enter resultados   Esc tipo");
    277 }
    278 
    279 static void matrix(Calc *c)
    280 {
    281     MatState *t = &c->mt;
    282     const MVal *m = t->target < 4 ? &t->m[t->target] : &t->v[t->target - 4];
    283     clear_all();
    284     status(c);
    285     char b[96];
    286     snprintf(b, sizeof b, "%s%c  (%d×%d)", t->target < 4 ? "Mat" : "Vct", 'A' + t->target % 4, m->r, m->c);
    287     text(2, 2, b, ACC, BG);
    288     int cw = 16;
    289     for (int i = 0; i < m->r; i++)
    290         for (int j = 0; j < m->c; j++) {
    291             int k = i * m->c + j;
    292             bool sel = k == t->sel;
    293             tk_attc(FG, sel ? SEL : PANEL, 0);
    294             tk_fill(4 + i, 4 + j * cw, cw - 1, " ");
    295             val(c, mv_get(m, i, j), false, b, sizeof b);
    296             text(4 + i, 4 + j * cw + cw - 2 - tk_ulen(b), b, sel ? ACC : FG, sel ? SEL : PANEL);
    297         }
    298     if (t->editing) input_box(c, "=", 10);
    299     help(t->editing ? "Enter guarda   Esc cancela" : "Tipeá un valor   flechas   = otra   Enter/Esc a las cuentas");
    300 }
    301 
    302 void tui_modes_paint(Calc *c)
    303 {
    304     switch (c->mode) {
    305     case MODE_EQN: eqn(c); break;
    306     case MODE_TABLE: table(c); break;
    307     case MODE_GRAPH: graph(c); break;
    308     case MODE_STAT: stat(c); break;
    309     case MODE_MATRIX: matrix(c); break;
    310     }
    311 }