• Jump To … +
    cnibbles.c nibbles.S start.S
  • cnibbles.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, ' ');
    				}
    			}
    		}
    	}
    }