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

CHATGPT.md (7611B)


      1 # Contexto: programar juegos en C para la PicoCalc
      2 
      3 Pegá este documento entero al principio de la conversación.
      4 
      5 Sos mi ayudante para escribir programas en C para la **ClockworkPi PicoCalc**
      6 con una **Raspberry Pi Pico 1 (RP2040, Cortex-M0+, 133 MHz, 264 KB de RAM, sin
      7 FPU)**. Pantalla 320x320 color, teclado QWERTY, tarjeta SD.
      8 
      9 Uso un kit que ya resuelve todo el hardware (pantalla, teclado, SD, arranque
     10 desde el cargador de la SD, linker script para flash+200K). **Yo solo cambio
     11 `app/app.c`** (y a veces `app/app_config.h`). Todos los `.c` de `app/` se
     12 compilan solos.
     13 
     14 ## Reglas (importantes)
     15 
     16 1. **Solo usá la API de abajo** (`hal.h` y `gfx.h`) para pantalla, teclado y
     17    guardado. **No** uses el SDK de la Pico directamente para el LCD, el
     18    teclado, SPI, I2C ni la SD: ya están inicializados por `hal_init()` y
     19    tocarlos rompe todo. Nada de `printf` para mostrar cosas (sale por un
     20    puerto serie que no veo). No escribir la flash de la Pico.
     21 2. **No escribas `main()`**. El punto de entrada es `void app_main(void)`, que
     22    **primero** llama a `hal_init()` y después nunca retorna (bucle infinito).
     23 3. **`#include "hal.h"`** alcanza (ya incluye `gfx.h`, `input.h`, `str.h`, `<stdint.h>`,
     24    `<stdbool.h>`). Se puede usar `<string.h>`, `<stdlib.h>` y `snprintf` de
     25    `<stdio.h>`, pero preferí `str_put`/`str_int` (más livianos).
     26 4. **Dibujo por franjas**: `hal_draw(paint, ctx)` llama a `paint` **10 veces por
     27    cuadro**, una por cada franja de 32 filas (el recorte lo hace solo). Por eso
     28    `paint` tiene que dibujar la pantalla **entera** a partir del estado y **no
     29    modificar nada** (no mover cosas, no llamar a `rand`, no contar cuadros adentro
     30    de `paint`). La lógica va en el bucle de `app_main`.
     31 5. **Pila chica** (unos pocos KB): nada de arreglos grandes como variables
     32    locales; usá `static` o globales. Evitá `malloc`.
     33 6. **Sin FPU**: `float` funciona pero es lento; preferí enteros / punto fijo.
     34 7. Velocidad de pantalla: repintar la pantalla entera tarda ~100 ms (≈10 fps).
     35    `hal_draw` solo manda por SPI las franjas que cambiaron, así que un juego de
     36    acción anda bien si la mayor parte de la pantalla queda quieta. Llamá a
     37    `hal_draw` solo cuando algo cambió.
     38 8. Teclado: `hal_key()` devuelve **solo el momento en que se aprieta** una tecla
     39    (no hay "tecla sostenida" ni soltar). Lee como mucho una vez cada 15 ms.
     40    Devuelve `-1` si no hay nada y **`0` = "redibujá la pantalla"** (no es una
     41    tecla: tratalo como pedido de repintar).
     42 9. Todo el código C debe ser C11 que compile con `arm-none-eabi-gcc -Wall` sin
     43    warnings. Devolveme siempre `app.c` **completo**, no fragmentos.
     44 
     45 ## API: `hal.h`
     46 
     47 ```c
     48 void     hal_init(void);          /* llamar primero; muestra un log de arranque */
     49 uint32_t hal_ms(void);            /* milisegundos desde el arranque */
     50 void     hal_sleep(int ms);
     51 void     hal_draw(void (*paint)(Surface *s, void *ctx), void *ctx);  /* ver regla 4 */
     52 int      hal_key(void);           /* -1 nada, 0 redibujar, K_* o caracter ASCII */
     53 bool     hal_store_save(const char *data, int n);  /* guarda en la SD (hasta ~40 KB) */
     54 int      hal_store_load(char *buf, int max);       /* bytes leídos, 0 si no hay nada */
     55 int      hal_battery(void);       /* porcentaje, o -1 */
     56 uint32_t hal_random(void);        /* 32 bits al azar (hardware) */
     57 void     hal_log(const char *line);  /* diagnóstico: escribe en el .LOG de la SD
     58                                         y lo muestra en pantalla (tapa el juego) */
     59 void     hal_log_clear(void);
     60 void     app_main(void);          /* LA DEFINE LA APP */
     61 
     62 /* teclas especiales (el resto llegan como su caracter: 'a', 'A', '1', ' ', ...) */
     63 enum Key { K_UP = 0x100, K_DOWN, K_LEFT, K_RIGHT, K_OK /* Enter */, K_BACK /* Esc */,
     64            K_TAB, K_PLUS, K_MINUS, K_BKSP };
     65 ```
     66 
     67 ## API: `gfx.h` (dibujo, coordenadas en píxeles, 0,0 arriba a la izquierda)
     68 
     69 ```c
     70 typedef uint16_t Color;                        /* RGB565 */
     71 #define RGB(r, g, b) ...                       /* r,g,b de 0 a 255 */
     72 /* colores listos: C_BLACK C_WHITE C_RED C_TEXT C_DIM C_ACCENT C_OK C_ERR C_PANEL C_PANEL2 C_CURSOR */
     73 
     74 extern const Font font_small;   /* 5x7 px por letra */
     75 extern const Font font_normal;  /* 6x12 */
     76 extern const Font font_bold;    /* 6x13 */
     77 
     78 void gfx_rect(Surface *s, int x, int y, int w, int h, Color c);     /* rectángulo lleno */
     79 void gfx_frame(Surface *s, int x, int y, int w, int h, Color c);    /* borde de 1 px */
     80 void gfx_box(Surface *s, int x, int y, int w, int h, Color bg, Color border);
     81 void gfx_line(Surface *s, int x0, int y0, int x1, int y1, int thick, Color c);
     82 void gfx_disc(Surface *s, int cx, int cy, int r, Color c);          /* círculo lleno */
     83 void gfx_ring(Surface *s, int cx, int cy, int r, int thick, Color c);
     84 void gfx_poly16(Surface *s, const int32_t *xs, const int32_t *ys, int n, Color c);
     85         /* polígono convexo lleno; coordenadas en 1/16 de píxel (x*16) */
     86 int  gfx_text(Surface *s, const Font *f, int x, int y, const char *utf8, Color c);
     87         /* y = borde de arriba del texto; devuelve la x final */
     88 int  gfx_text_w(const Font *f, const char *utf8);                   /* ancho en px */
     89 int  gfx_text_center(Surface *s, const Font *f, int x, int y, int w, const char *t, Color c);
     90 void gfx_clip(Surface *s, int x, int y, int w, int h);  /* limita el dibujo a ese rect */
     91 void gfx_noclip(Surface *s);
     92 Color gfx_dim(Color c);                                  /* mitad de brillo */
     93 ```
     94 
     95 Texto sin stdio (`str.h`): escriben en `buf` desde `pos` y devuelven la nueva posición.
     96 
     97 ```c
     98 int str_put(char *buf, int n, int pos, const char *s);
     99 int str_int(char *buf, int n, int pos, long v);
    100 const char *str_scan_int(const char *s, long *out);   /* NULL si no hay número */
    101 /* ej: int p = str_put(b, sizeof b, 0, "Puntos: "); str_int(b, sizeof b, p, score); */
    102 ```
    103 
    104 Azar determinista (`rng.h`, incluir aparte): `Rng r; rng_seed(&r, hal_random(), 1);
    105 rng_below(&r, 6)` → 0..5.
    106 
    107 ## Esqueleto de un programa
    108 
    109 ```c
    110 #include "hal.h"
    111 
    112 typedef struct { int x, y, score; bool over; } Game;
    113 
    114 static void paint(Surface *s, void *ctx)   /* solo dibuja; ver regla 4 */
    115 {
    116     const Game *g = ctx;
    117     gfx_rect(s, 0, 0, 320, 320, C_BLACK);
    118     gfx_rect(s, g->x, g->y, 10, 10, C_OK);
    119 }
    120 
    121 void app_main(void)
    122 {
    123     static Game g;
    124     hal_init();
    125     g.x = 155; g.y = 155;
    126     bool dirty = true;
    127     uint32_t next_tick = hal_ms();
    128     for (;;) {
    129         int k = hal_key();
    130         if (k == 0) dirty = true;
    131         if (k == K_LEFT) { g.x -= 10; dirty = true; }
    132         /* ... */
    133         if ((int32_t)(hal_ms() - next_tick) >= 0) {   /* lógica a ritmo fijo */
    134             next_tick += 100;
    135             /* avanzar el juego */
    136             dirty = true;
    137         }
    138         if (dirty) { hal_draw(paint, &g); dirty = false; }
    139         hal_sleep(5);
    140     }
    141 }
    142 ```
    143 
    144 ## Guardar
    145 
    146 `hal_store_save` escribe en el archivo `.SAV` de la SD (definido en
    147 `app_config.h`, tiene que existir: lo crea el kit). Es un blob de bytes: guardá
    148 texto simple (`"record 1234"`) o una struct con un número de versión adelante.
    149 Guardá solo al terminar una partida o al salir, no en cada cuadro (la SD es lenta).
    150 
    151 ## Si algo falla
    152 
    153 - Error de compilación: te lo paso tal cual.
    154 - Si el programa se cuelga con **pantalla roja "CRASH (HardFault)"** muestra
    155   `pc` y `lr`: suele ser un puntero inválido, índice fuera de un arreglo o pila
    156   desbordada (arreglo local grande).
    157 - Pantalla quieta en el log azul de arranque: el programa se colgó antes del
    158   primer `hal_draw` (bucle infinito sin dibujar, o se quedó esperando algo).
    159 - Para depurar podés usar `hal_log("mensaje")`: queda en el `.LOG` de la SD.