Files
nibbles/cnibbles.c
T

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, ' ');
}
}
}
}
}