summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c312
1 files changed, 270 insertions, 42 deletions
diff --git a/main.c b/main.c
index ccc3cdc..b95e9cb 100644
--- a/main.c
+++ b/main.c
@@ -1,56 +1,284 @@
+#define _POSIX_C_SOURCE 202511L
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "wrmr.h"
#include "vui.h"
-int x = 0, y = 0;
+/* input buffer */
-int main(void) {
- vui_init();
+int inbuf[32] = { 0 };
+#define INBUF_MASK 0x1f
+u32 inbuf_start = 0, inbuf_end = 0;
+
+int pop_input(void) {
+ /*
+ int k = inbuf[inbuf_start];
+ inbuf[inbuf_start] = 0;
+ if (k) inbuf_start = (inbuf_start + 1) & INBUF_MASK;
+ return k;
+ */
+ if (inbuf_start == inbuf_end) return 0;
+ int k = inbuf[inbuf_start++];
+ inbuf_start &= INBUF_MASK;
+ return k;
+}
+
+void push_input(int i) {
+ inbuf[inbuf_end++] = i;
+ inbuf_end &= INBUF_MASK;
+}
- int x = 0, y = 0;
- int scroll_x = 0, scroll_y = 0;
+u32 poll_input_iter = 0;
+int poll_input(u32 ms) {
+ struct timespec start;
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ u64 n = start.tv_nsec + (ms * 1000000);
+ struct timespec stop = {
+ .tv_sec = start.tv_sec + n / 1000000000,
+ .tv_nsec = n % 1000000000
+ };
+ poll_input_iter = 0;
for (;;) {
- static int last_left = 0;
- int left = (COLS - (72 < COLS ? 72 : COLS - 2)) >> 1;
- int right = COLS - left;
- int top = 5;
- int bottom = LINES - 5;
-
- //vui_fill(' ', FG_WHITE | BG_BLUE);
- //vui_fill_rect(' ', FG_BLACK | BG_BLACK, left + 2, top + 1, right - left, bottom - top);
- //vui_fill_rect(' ', FG_BLACK | BG_WHITE, left, top, right - left, bottom - top);
-
- if (y < top) { scroll_y = top - y; }
- if (y > bottom) { scroll_y = bottom - y; }
-
- scroll_x += left - last_left;
- last_left = left;
-
- int sdx = scroll_x > 0 ? 1 : (scroll_x < 0 ? -1 : 0);
- sdx = scroll_x;
- int sdy = scroll_y > 0 ? 1 : (scroll_y < 0 ? -1 : 0);
- vui_scroll(sdx, sdy);
- x += sdx;
- y += sdy;
- scroll_x -= sdx;
- scroll_y -= sdy;
+ poll_input_iter++;
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ i64 ns_rem = (stop.tv_sec - now.tv_sec) * 1000000000 + (i64)stop.tv_nsec - (i64)now.tv_nsec;
+ i64 ms_rem = ns_rem / 1000000;
+ if (ns_rem < 1) break;
+ if (vui_wait_for_input(ms_rem)) push_input(vui_key());
+ else break;
+ }
+ return 0;
+}
- vui_blit();
+/* program */
+
+#define WIDTH 32
+#define HEIGHT 32
+
+typedef enum {
+ TILE_FLOOR,
+ TILE_SNK_ODD,
+ TILE_SNK_EVEN,
+ TILE_APPLE,
+ TILE_MAX
+} Tile;
+
+const VuiAttr tile_attr[TILE_MAX][2] = {
+ { FG_BLUE | BG_BLACK, FG_BLUE | BG_BLACK },
+ { FG_YELLOW | BG_BLACK, FG_BYELLOW | BG_BLACK },
+ { FG_GREEN | BG_BLACK, FG_BGREEN | BG_BLACK },
+ { FG_BGREEN | BG_BLACK, FG_BRED | BG_BLACK },
+};
+
+const VuiChar tile_chr[TILE_MAX][2] = {
+ { ' ', '.' },
+ { '[', ']' },
+ { '[', ']' },
+ { '`', 'o' }
+};
+
+Tile board[HEIGHT][WIDTH];
+
+typedef enum {
+ DIR_LEFT,
+ DIR_UP,
+ DIR_RIGHT,
+ DIR_DOWN
+} Dir;
+
+#define DIR_IS_Y(d) ((d)&1)
+#define DIR_IS_X(d) (~(d)&1)
+#define DIR_SIGN(d) ((d)&2 ? 1 : -1)
+#define DIR_FLIP(d) (((d) + 2) & 3)
+#define DIR_DX(d) (DIR_IS_X(d) * DIR_SIGN(d))
+#define DIR_DY(d) (DIR_IS_Y(d) * DIR_SIGN(d))
- int animating = !!scroll_x || !!scroll_y;
- if (animating && !vui_wait_for_input(50)) continue;
- VuiKey c = vui_key();
- if (c == KEY_INVALID || c == KEY_ESC) goto done;
- if (x >= right) {
- x = left;
+typedef struct {
+ i16 x, y;
+} SnkSeg;
+
+#define SNK_SEG_MAX (WIDTH * HEIGHT)
+
+typedef struct {
+ Dir dir;
+ u32 len;
+ SnkSeg seg[SNK_SEG_MAX];
+} Snake;
+
+Snake snk = { 0 };
+
+typedef struct {
+ i16 x, y;
+} Apple;
+
+#define APPLE_MAX 32
+Apple apple[APPLE_MAX];
+
+void replace_apple(u32 i) {
+ Apple *a = &apple[i];
+ do {
+ a->x = rand() % WIDTH;
+ a->y = rand() % HEIGHT;
+ } while (board[a->y][a->x] != TILE_FLOOR);
+}
+
+void place_apple(void) {
+ for (u32 i = 0; i < APPLE_MAX; i++) {
+ replace_apple(i);
+ }
+}
+
+void brd_clear(void) {
+ for (u32 y = 0; y < HEIGHT; y++) {
+ for (u32 x = 0; x < WIDTH; x++) {
+ board[y][x] = TILE_FLOOR;
+ }
+ }
+}
+
+void brd_draw(void) {
+ /*
+ u32 left = COLS / 2 - WIDTH;
+ u32 top = LINES / 2 - HEIGHT / 2;
+ */
+ u32 left = COLS / 2 - snk.seg->x * 2;
+ u32 top = LINES / 2 - snk.seg->y;
+
+ u32 right = left + WIDTH * 2;
+ u32 bottom = top + HEIGHT;
+ for (u32 y = 0; y < HEIGHT; y++) {
+ vui_chr(left - 1, top + y, u'❘');
+ vui_chr(right + 1, top + y, u'❘');
+ for (u32 x = 0; x < WIDTH; x++) {
+ Tile t = board[y][x];
+ vui_chra(left + 2 * x, top + y, tile_chr[t][0], tile_attr[t][0]);
+ vui_chra(left + 2 * x + 1, top + y, tile_chr[t][1], tile_attr[t][1]);
+ vui_puts(left + 2 * x, top - 1, "──");
+ vui_puts(left + 2 * x, bottom, "──");
+ }
+ }
+ vui_chr(left - 1, top - 1, u'┌');
+ vui_chr(right + 1, top - 1, u'┐');
+ vui_chr(left - 1, bottom, u'└');
+ vui_chr(right + 1, bottom, u'┘');
+ /*
+ u32 x = 0;
+ u32 y = 1;
+ for (u32 i = 0; i < sizeof inbuf / sizeof *inbuf; i++) {
+ int within = (i >= inbuf_start && i < inbuf_end);
+ if (inbuf_end < inbuf_start) {
+ within = i >= inbuf_start || i < inbuf_end;
+ }
+ VuiAttr a = within ? FG_BCYAN : FG_BBLACK;
+ if (i == inbuf_start) vui_chra(x, bottom + y - 1, 'v', FG_BCYAN);
+ if (i == inbuf_end) vui_chra(x + 1, bottom + y - 1, 'v', FG_BMAGENTA);
+ x += vui_aprintf(x, bottom + y, a, "%6X ", inbuf[i]);
+ if (x >= COLS - 24) {
+ x = 0;
y += 2;
}
- static unsigned i = 0;
- i++;
- int tx = x + vui_aprintf(x, y - 1, (i & 1 ? FG_WHITE : FG_CYAN) | BG_BLACK, "%02X", c);
- vui_chra(x++, y, c < 0x20 || c > KEY_UTF8_MAX || c == 0x7f ? 0xfffd : c, FG_BYELLOW | BG_BLUE);
- while (x < tx) vui_chra(x++, y, ' ', FG_BYELLOW | BG_BLUE);
}
-done:
+ */
+}
+
+void snk_draw(Snake *s) {
+ for (u32 i = 0; i < s->len; i++) {
+ board[s->seg[i].y][s->seg[i].x] = (i / 4) & 1 ? TILE_SNK_ODD : TILE_SNK_EVEN;
+ }
+}
+
+void apple_draw(void) {
+ for (u32 i = 0; i < APPLE_MAX; i++) {
+ board[apple[i].y][apple[i].x] = TILE_APPLE;
+ }
+}
+
+int alive, paused;
+
+void draw(void *ctx) {
+ (void)ctx;
+ vui_clear();
+
+ brd_clear();
+ snk_draw(&snk);
+ apple_draw();
+ brd_draw();
+
+ if (!alive) {
+ vui_puts(COLS/2 - 4, LINES/2, "YOU DIED!");
+ }
+ vui_printf(0, 0, "input polling iterations: %u", poll_input_iter);
+}
+
+void update(void) {
+ for (u32 i = 0; i < APPLE_MAX; i++) {
+ if (snk.seg[0].x == apple[i].x && snk.seg[0].y == apple[i].y) {
+ replace_apple(i);
+ snk.len++;
+ break;
+ }
+ }
+ memmove(snk.seg + 1, snk.seg, (SNK_SEG_MAX - 1) * sizeof(SnkSeg));
+
+ i16 x = snk.seg[0].x + DIR_DX(snk.dir);
+ i16 y = snk.seg[0].y + DIR_DY(snk.dir);
+
+ if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
+ alive = 0;
+ return;
+ }
+
+ for (u32 i = 1; i < snk.len; i++) {
+ if (snk.seg[i].x == x && snk.seg[i].y == y) {
+ alive = 0;
+ return;
+ }
+ }
+
+ snk.seg[0].x = x;
+ snk.seg[0].y = y;
+ vui_scroll(-DIR_DX(snk.dir) * 2, -DIR_DY(snk.dir));
+}
+
+void snk_chg_dir(Snake *s, Dir d) {
+ if (s->len < 2 || d != DIR_FLIP(s->dir)) {
+ s->dir = d;
+ }
+}
+
+int main(void) {
+ srand(time(NULL));
+ vui_init();
+ snk.dir = DIR_RIGHT;
+ snk.seg[snk.len++] = (SnkSeg) { 0, 0 };
+ alive = 1;
+ paused = 0;
+ vui_redraw_fn(draw);
+ place_apple();
+ while (alive) {
+ poll_input(30);
+ draw(NULL);
+ vui_blit();
+ switch (pop_input()) {
+ case 0: break;
+ case KEY_ESC: goto done;
+ case KEY_LEFT : case 'j': snk_chg_dir(&snk, DIR_LEFT); break;
+ case KEY_UP : case 'i': snk_chg_dir(&snk, DIR_UP); break;
+ case KEY_RIGHT: case 'l': snk_chg_dir(&snk, DIR_RIGHT); break;
+ case KEY_DOWN : case 'k': snk_chg_dir(&snk, DIR_DOWN); break;
+ case ' ': paused = !paused; break;
+ }
+ if (!paused) update();
+ }
+ draw(NULL);
+ vui_blit();
+ (void)vui_key();
+done:
vui_fini();
return 0;
}