#include 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; #define GRID_W 20 #define GRID_H 10 #define MAX_LEN 10 #define OVF_PER_FRAME 20 #define DIR_UP 0 #define DIR_DOWN 1 #define DIR_LEFT 2 #define DIR_RIGHT 3 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; static volatile __near uint8_t ovf_count; void isr(void) __interrupt(0) { if (INTCON & 0x04) { ovf_count++; INTCON &= ~(uint8_t)0x04; } } 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; } static void uart_puts(const char *s) { while (*s) uart_send((uint8_t)*s++); } static uint8_t uart_recv(void) { if (UART_STATUS & 0b00000010) return 0; return UART_RX; } /* Simplified WASD handler */ static void handle_input(void) { uint8_t c; while (!(UART_STATUS & 0x02)) { c = UART_RX; /* 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, 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; } static void print_uint8(uint8_t v) { uint8_t started = 0; if (v >= 200) { uart_send('2'); v -= 200; started = 1; } else if (v >= 100) { uart_send('1'); v -= 100; started = 1; } { uint8_t t = '0'; while (v >= 10) { v -= 10; t++; } if (started || t != '0') uart_send(t); } uart_send(v + '0'); } uint8_t food_ch = '*'; static void render(void) { uint8_t x, y, i; 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 = food_ch; else { for (i = 0; i < snake_len; i++) { if (snake_x[i] == x && snake_y[i] == y) { ch = (i == 0) ? 'O' : 'o'; break; } } } uart_send(ch); } uart_puts("|\r\n"); } uart_send('+'); for (x = 0; x < GRID_W; x++) uart_send('-'); uart_puts("+\r\nScore: "); print_uint8(score); uart_puts(" \r\n"); } static uint8_t update(void) { uint8_t nx, ny, i; 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; } 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(); } 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; return 1; } void main(void) { uint8_t alive; TRISA &= ~0x01; PORTA = 0x00; OPTION_REG = 0x07; TMR0 = 0; INTCON = 0xa0; while (1) { 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(); /* \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; if (food_ch == '*') food_ch = '+'; else food_ch = '*'; alive = update(); render(); PORTA ^= 0x01; } /* Game Over: Show Cursor (\x1B[?25h) */ uart_puts("\r\n--- GAME OVER ---\r\nScore: "); print_uint8(score); uart_puts("\r\nPress any key to restart\r\n\x1B[?25h"); while (uart_recv() == 0); } }