summaryrefslogtreecommitdiffstats
path: root/fw/snake.c
diff options
context:
space:
mode:
authorVaino Kauppila <vaino@vke.fi>2026-04-21 01:38:41 +0300
committerVaino Kauppila <vaino@vke.fi>2026-04-21 01:38:41 +0300
commitfb4d34ef802c6b46a69f16ca72470938fdecf9b7 (patch)
treed602ad31f4cd14a23e3dddba40a202afcfc7afd6 /fw/snake.c
parentc9d20884c0a71eb80340f33e58aa73ad99f45ce2 (diff)
downloadvhdl_pic-fb4d34ef802c6b46a69f16ca72470938fdecf9b7.tar.gz
vhdl_pic-fb4d34ef802c6b46a69f16ca72470938fdecf9b7.zip
snake done. have to update linker file to support 8k prog memHEADmaster
Diffstat (limited to 'fw/snake.c')
-rw-r--r--fw/snake.c196
1 files changed, 87 insertions, 109 deletions
diff --git a/fw/snake.c b/fw/snake.c
index e99802b..6a3c15d 100644
--- a/fw/snake.c
+++ b/fw/snake.c
@@ -2,6 +2,7 @@
typedef unsigned char uint8_t;
+/* Mapped for emulator/simulator environment */
__sfr __at(0x70) UART_TX;
__sfr __at(0x71) UART_RX;
__sfr __at(0x72) UART_STATUS;
@@ -9,7 +10,7 @@ __sfr __at(0x72) UART_STATUS;
#define GRID_W 20
#define GRID_H 10
#define MAX_LEN 10
-#define OVF_PER_FRAME 10
+#define OVF_PER_FRAME 20
#define DIR_UP 0
#define DIR_DOWN 1
@@ -20,6 +21,7 @@ static __near uint8_t snake_x[MAX_LEN];
static __near uint8_t snake_y[MAX_LEN];
static __near uint8_t snake_len;
static __near uint8_t direction;
+static __near uint8_t last_moved_dir;
static __near uint8_t food_x;
static __near uint8_t food_y;
static __near uint8_t score;
@@ -32,6 +34,19 @@ void isr(void) __interrupt(0) {
}
}
+static uint8_t r_seed = 0xAA; // Seed must NEVER be 0
+
+static uint8_t get_random(void) {
+ // Standard 8-bit LFSR logic (similar to your assembly)
+ // If the LSB is 1, XOR with the polynomial mask
+ if (r_seed & 1) {
+ r_seed = (r_seed >> 1) ^ 0xB8;
+ } else {
+ r_seed = (r_seed >> 1);
+ }
+ return r_seed;
+}
+
static void uart_send(uint8_t b) {
while (UART_STATUS & 0x01);
UART_TX = b;
@@ -41,83 +56,51 @@ static void uart_puts(const char *s) {
while (*s) uart_send((uint8_t)*s++);
}
-// return 0 if EMPTY
static uint8_t uart_recv(void) {
- if (UART_STATUS & 0b00000010) // empty
- return 0;
+ if (UART_STATUS & 0b00000010) return 0;
return UART_RX;
}
-/* /\* Non-blocking state machine — drains the whole FIFO each frame. */
-/* * Handles both ESC [ x (CSI) and ESC O x (SS3) cursor key modes. */
-/* * Never blocks, so a stray ESC can't freeze the game. *\/ */
-/* static void handle_input(void) { */
-/* uint8_t c; */
-/* while (1) { */
-/* c = uart_recv(); */
-/* if (c == 0) { */
-/* return; */
-/* } */
-/* switch (input_state) { */
-/* case 0: */
-/* input_state = (c == 0x1B) ? 1 : 0; */
-/* break; */
-/* case 1: */
-/* input_state = (c == '[' || c == 'O') ? 2 : 0; */
-/* break; */
-/* case 2: */
-/* switch (c) { */
-/* case 'A': if (direction != DIR_DOWN) direction = DIR_UP; break; */
-/* case 'B': if (direction != DIR_UP) direction = DIR_DOWN; break; */
-/* case 'C': if (direction != DIR_LEFT) direction = DIR_RIGHT; break; */
-/* case 'D': if (direction != DIR_RIGHT) direction = DIR_LEFT; break; */
-/* } */
-/* input_state = 0; */
-/* break; */
-/* } */
-/* } */
-/* } */
-
-static uint8_t __near esc_state = 0;
-
-/* drains UART FIFO fully each frame */
-static void handle_input(void)
-{
+/* Simplified WASD handler */
+static void handle_input(void) {
uint8_t c;
-
- while (!(UART_STATUS & 0x02)) /* while not empty */
- {
+ while (!(UART_STATUS & 0x02)) {
c = UART_RX;
-
- if (esc_state == 0)
- {
- if (c == 0x1B) esc_state = 1;
- }
- else if (esc_state == 1)
- {
- esc_state = (c == '[' || c == 'O') ? 2 : 0;
- }
- else /* esc_state == 2 */
- {
- switch (c)
- {
- case 'A': if (direction != DIR_DOWN) direction = DIR_UP; break;
- case 'B': if (direction != DIR_UP) direction = DIR_DOWN; break;
- case 'C': if (direction != DIR_LEFT) direction = DIR_RIGHT; break;
- case 'D': if (direction != DIR_RIGHT) direction = DIR_LEFT; break;
- }
- esc_state = 0;
+ /* Handle both upper and lower case */
+ if (c == 'w' || c == 'W') {
+ if (last_moved_dir != DIR_DOWN) direction = DIR_UP;
+ } else if (c == 's' || c == 'S') {
+ if (last_moved_dir != DIR_UP) direction = DIR_DOWN;
+ } else if (c == 'a' || c == 'A') {
+ if (last_moved_dir != DIR_RIGHT) direction = DIR_LEFT;
+ } else if (c == 'd' || c == 'D') {
+ if (last_moved_dir != DIR_LEFT) direction = DIR_RIGHT;
}
}
}
static void place_food(void) {
- uint8_t x = ovf_count;
- uint8_t y = ovf_count;
- x += x; x += x; x += x; x -= ovf_count; x += 3; /* x = ovf*7 + 3 */
- y += y; y += y; y += ovf_count; y += 1; /* y = ovf*5 + 1 */
- while (x >= GRID_W) x -= GRID_W;
- while (y >= GRID_H) y -= GRID_H;
+ uint8_t x, y, i, overlap;
+
+ do {
+ overlap = 0;
+
+ // Get a random X and Y using the PRNG
+ x = get_random();
+ while (x >= GRID_W) x -= GRID_W;
+
+ y = get_random();
+ while (y >= GRID_H) y -= GRID_H;
+
+ /* Ensure food doesn't spawn inside the snake's body */
+ for (i = 0; i < snake_len; i++) {
+ if (snake_x[i] == x && snake_y[i] == y) {
+ overlap = 1;
+ break;
+ }
+ }
+ } while (overlap);
+
food_x = x;
food_y = y;
}
@@ -134,23 +117,20 @@ static void print_uint8(uint8_t v) {
uart_send(v + '0');
}
+uint8_t food_ch = '*';
+
static void render(void) {
uint8_t x, y, i;
-
- uart_puts("\x1B[H");
-
- /* top border */
+ uart_puts("\x1B[H"); /* Cursor to home */
uart_send('+');
for (x = 0; x < GRID_W; x++) uart_send('-');
uart_puts("+\r\n");
-
for (y = 0; y < GRID_H; y++) {
uart_send('|');
for (x = 0; x < GRID_W; x++) {
uint8_t ch = ' ';
- if (x == food_x && y == food_y) {
- ch = '*';
- } else {
+ if (x == food_x && y == food_y) ch = food_ch;
+ else {
for (i = 0; i < snake_len; i++) {
if (snake_x[i] == x && snake_y[i] == y) {
ch = (i == 0) ? 'O' : 'o';
@@ -162,87 +142,85 @@ static void render(void) {
}
uart_puts("|\r\n");
}
-
- /* bottom border */
uart_send('+');
for (x = 0; x < GRID_W; x++) uart_send('-');
- uart_puts("+\r\n");
-
- uart_puts("Score: ");
+ uart_puts("+\r\nScore: ");
print_uint8(score);
uart_puts(" \r\n");
}
-/* returns 1 if alive, 0 if dead */
static uint8_t update(void) {
uint8_t nx, ny, i;
-
- nx = snake_x[0];
- ny = snake_y[0];
+ last_moved_dir = direction;
+ nx = snake_x[0]; ny = snake_y[0];
switch (direction) {
- case DIR_UP: if (ny == 0) return 0; ny--; break;
- case DIR_DOWN: if (ny == GRID_H-1) return 0; ny++; break;
- case DIR_LEFT: if (nx == 0) return 0; nx--; break;
- case DIR_RIGHT: if (nx == GRID_W-1) return 0; nx++; break;
+ case DIR_UP: if (ny == 0) return 0; ny--; break;
+ case DIR_DOWN: if (ny == GRID_H-1) return 0; ny++; break;
+ case DIR_LEFT: if (nx == 0) return 0; nx--; break;
+ case DIR_RIGHT: if (nx == GRID_W-1) return 0; nx++; break;
}
-
- /* self-collision (exclude tail: it moves away this step) */
for (i = 0; i < snake_len - 1; i++) {
if (snake_x[i] == nx && snake_y[i] == ny) return 0;
}
-
if (nx == food_x && ny == food_y) {
if (snake_len < MAX_LEN) snake_len++;
score++;
place_food();
}
-
- /* shift body back, add new head */
for (i = snake_len - 1; i > 0; i--) {
snake_x[i] = snake_x[i-1];
snake_y[i] = snake_y[i-1];
}
- snake_x[0] = nx;
- snake_y[0] = ny;
-
+ snake_x[0] = nx; snake_y[0] = ny;
return 1;
}
void main(void) {
uint8_t alive;
-
+ TRISA &= ~0x01;
+ PORTA = 0x00;
OPTION_REG = 0x07;
TMR0 = 0;
INTCON = 0xa0;
while (1) {
- /* init */
- direction = DIR_RIGHT;
- snake_len = 3;
- score = 0;
+ direction = DIR_RIGHT;
+ last_moved_dir = DIR_RIGHT;
+ snake_len = 3;
+ score = 0;
snake_x[0] = 5; snake_y[0] = 5;
snake_x[1] = 4; snake_y[1] = 5;
snake_x[2] = 3; snake_y[2] = 5;
place_food();
- uart_puts("\x1B[2J\x1B[H");
+ /* \x1B[2J = Clear Screen
+ \x1B[H = Home Cursor
+ \x1B[?25l = Hide Cursor */
+ uart_puts("\x1B[2J\x1B[H\x1B[?25l");
alive = 1;
while (alive) {
+ /* High-frequency input polling during wait */
+ while (ovf_count < OVF_PER_FRAME) {
+ handle_input();
+ }
ovf_count = 0;
- while (ovf_count < OVF_PER_FRAME);
- handle_input();
+ if (food_ch == '*')
+ food_ch = '+';
+ else
+ food_ch = '*';
+
alive = update();
render();
PORTA ^= 0x01;
}
- uart_puts("\x1B[2J\x1B[H");
- uart_puts("GAME OVER score: ");
+ /* Game Over: Show Cursor (\x1B[?25h) */
+ uart_puts("\r\n--- GAME OVER ---\r\nScore: ");
print_uint8(score);
- uart_puts("\r\npress any key\r\n");
- while (uart_recv() == 0); /* wait for any byte */
- esc_state = 0;
+ uart_puts("\r\nPress any key to restart\r\n\x1B[?25h");
+
+ while (uart_recv() == 0);
}
}