diff options
Diffstat (limited to 'fw')
| -rw-r--r-- | fw/snake.c | 196 |
1 files changed, 87 insertions, 109 deletions
@@ -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); } } |
