194 lines
3.9 KiB
C
194 lines
3.9 KiB
C
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include "helpers.c"
|
|
|
|
#define WIDTH 60
|
|
#define HEIGHT 40
|
|
#define DEBUG false
|
|
|
|
unsigned int startLength = 0;
|
|
unsigned int startApples = 0;
|
|
|
|
unsigned int currentTick;
|
|
int snake[WIDTH*HEIGHT];
|
|
unsigned int snakeLength;
|
|
unsigned int snakeX;
|
|
unsigned int snakeY;
|
|
int snakeDirX;
|
|
int snakeDirY;
|
|
unsigned int numApples;
|
|
|
|
void spawnApple();
|
|
void tick();
|
|
void draw();
|
|
|
|
// start_game
|
|
// ==========
|
|
void start_game(int len, int n_apples)
|
|
{
|
|
if (startLength == 0)
|
|
startLength = len;
|
|
if (startApples == 0)
|
|
startApples = n_apples;
|
|
|
|
// Initialize variables
|
|
currentTick = 0;
|
|
snakeLength = len;
|
|
numApples = n_apples;
|
|
|
|
nib_init();
|
|
|
|
// Initialize the snake array
|
|
// Set every cell to a time value greater than the snake length
|
|
for (unsigned int i = 0; i < WIDTH*HEIGHT; ++i) {
|
|
snake[i] = snakeLength;
|
|
}
|
|
|
|
// Place the snake head in the middle
|
|
snakeX = WIDTH / 2;
|
|
snakeY = HEIGHT / 2;
|
|
snakeDirX = 0;
|
|
snakeDirY = -1;
|
|
|
|
// Place the initial snake segments, downwards or something
|
|
for (unsigned int i = 0; i < snakeLength; ++i) {
|
|
unsigned int x = snakeX % WIDTH;
|
|
unsigned int y = (snakeY + i) % HEIGHT;
|
|
snake[x + y*WIDTH] = i;
|
|
}
|
|
|
|
// Place apples
|
|
srand(time(0));
|
|
for (unsigned int i = 0; i < numApples; ++i) {
|
|
spawnApple();
|
|
}
|
|
|
|
while (true) {
|
|
tick();
|
|
draw();
|
|
}
|
|
}
|
|
|
|
// spawnApple
|
|
// ==========
|
|
void spawnApple()
|
|
{
|
|
unsigned int x = rand() % WIDTH;
|
|
unsigned int y = rand() % HEIGHT;
|
|
while (snake[x + y*WIDTH] < snakeLength) {
|
|
x = rand() % WIDTH;
|
|
y = rand() % HEIGHT;
|
|
}
|
|
snake[x + y*WIDTH] = -1;
|
|
}
|
|
|
|
// tick
|
|
// ====
|
|
void tick()
|
|
{
|
|
currentTick++;
|
|
// Increment cell times
|
|
// --------------------
|
|
for (unsigned int i = 0; i < WIDTH*HEIGHT; ++i) {
|
|
int val = snake[i];
|
|
|
|
if (val < 0) {
|
|
// Apple lifetime
|
|
/* snake[i]--; */
|
|
} else if (val >= 0 && val <= snakeLength) {
|
|
// Other cells
|
|
snake[i]++;
|
|
}
|
|
}
|
|
|
|
// Input
|
|
// -----
|
|
int key = nib_poll_kbd();
|
|
if (key == 'w' && snakeDirY != 1) {
|
|
snakeDirX = 0;
|
|
snakeDirY = -1;
|
|
}
|
|
if (key == 's' && snakeDirY != -1) {
|
|
snakeDirX = 0;
|
|
snakeDirY = 1;
|
|
}
|
|
if (key == 'a' && snakeDirX != 1) {
|
|
snakeDirX = -1;
|
|
snakeDirY = 0;
|
|
}
|
|
if (key == 'd' && snakeDirX != -1) {
|
|
snakeDirX = 1;
|
|
snakeDirY = 0;
|
|
}
|
|
|
|
// Move snake
|
|
// ----------
|
|
snakeX = (snakeX + snakeDirX + WIDTH) % WIDTH;
|
|
snakeY = (snakeY + snakeDirY + HEIGHT) % HEIGHT;
|
|
|
|
// Collision
|
|
// ---------
|
|
// On collision with self
|
|
int val = snake[snakeX + snakeY*WIDTH];
|
|
if (val < snakeLength && val >= 0) {
|
|
//nib_end();
|
|
start_game(startLength, startApples);
|
|
}
|
|
// ON collision with apple
|
|
if (val < 0) {
|
|
// Spawn a new apple somewhere
|
|
spawnApple();
|
|
// Increase our length!
|
|
snakeLength++;
|
|
}
|
|
|
|
// Update world
|
|
// ------------
|
|
snake[snakeX + snakeY*WIDTH] = 0;
|
|
}
|
|
|
|
// draw
|
|
// ====
|
|
void draw()
|
|
{
|
|
char body[] = "NIBBLES";
|
|
|
|
for (int y = -1; y <= HEIGHT; ++y) {
|
|
for (int x = -1; x <= WIDTH; ++x) {
|
|
// Draw a border outside the playing field
|
|
if (x == -1 || y == -1 || x == WIDTH || y == HEIGHT) {
|
|
unsigned int screenX = x + 1;
|
|
unsigned int screenY = y + 1;
|
|
nib_put_scr(screenX, screenY, '#');
|
|
} else {
|
|
int snakeVal = snake[x + y*WIDTH];
|
|
unsigned int screenX = x + 1;
|
|
unsigned int screenY = y + 1;
|
|
|
|
// If the `DEBUG` flag is set, draw the raw ASCII-value for debugging purposes
|
|
if (DEBUG) {
|
|
nib_put_scr(screenX, screenY, '0' + snakeVal);
|
|
continue;
|
|
}
|
|
|
|
// If the value is greater than `0` and less than `snakeLength`, it's part of the snake
|
|
if (snakeVal >= 0 && snakeVal < snakeLength) {
|
|
if (x == snakeX && y == snakeY) {
|
|
// Draw the head
|
|
nib_put_scr(screenX, screenY, '@');
|
|
} else {
|
|
// Draw the body
|
|
nib_put_scr(screenX, screenY, body[(snakeVal - 1) % 7]);
|
|
}
|
|
} else if (snakeVal < 0) {
|
|
// If the value is less than `0`, it's an apple
|
|
nib_put_scr(screenX, screenY, 'o');
|
|
} else {
|
|
// Otherwise it's empty.
|
|
nib_put_scr(screenX, screenY, ' ');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|