

 This page uses content from Wikipedia. The original article was at Snake_(video_game). The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)


Snake is a game where the player maneuvers a line which grows in length every time the snake reaches a food source.



Task
Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake.

Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane.

The game ends when the snake attempts to eat himself.




// Snake
 
// The problem with implementing this task in C is, the language standard
// does not cover some details essential for interactive games:
// a nonblocking keyboard input, a positional console output,
// a and millisecond-precision timer: these things are all system-dependent.
 
// Therefore the program is split in two pieces, a system-independent
// game logic, and a system-dependent UI, separated by a tiny API:
char nonblocking_getch();
void positional_putch(int x, int y, char ch);
void millisecond_sleep(int n);
void init_screen();
void update_screen();
void close_screen();
 
// The implementation of a system-dependent part.
// Requires POSIX IEEE 1003.1-2008 compliant system and ncurses library.
#ifdef __linux__
#define _POSIX_C_SOURCE 200809L
#include <time.h> // nanosleep
#include <ncurses.h> // getch, mvaddch, and others
char nonblocking_getch() { return getch(); }
void positional_putch(int x, int y, char ch) { mvaddch(x, y, ch); }
void millisecond_sleep(int n) { 
	struct timespec t = { 0, n * 1000000 };
	nanosleep(&t, 0);
	// for older POSIX standards, consider usleep()
}
void update_screen() { refresh(); }
void init_screen() {
	initscr();
	noecho();
	cbreak();
	nodelay(stdscr, TRUE);
}
void close_screen() { endwin(); }
#endif
 
// An implementation for some other system...
#ifdef _WIN32
#error "not implemented"
#endif
 
// The game logic, system-independent
#include <time.h> // time
#include <stdlib.h> // rand, srand
 
#define w 80
#define h 40
 
int board[w * h];
int head;
enum Dir { N, E, S, W } dir;
int quit;
 
enum State { SPACE=0, FOOD=1, BORDER=2 };
// negative values denote the snake (a negated time-to-live in given cell)
 
// reduce a time-to-live, effectively erasing the tail
void age() {
        int i;
	for(i = 0; i < w * h; ++i)
		if(board[i] < 0)
			++board[i];
}
 
// put a piece of food at random empty position
void plant() {
	int r;
	do
		r = rand() % (w * h);
	while(board[r] != SPACE);
	board[r] = FOOD;
}
 
// initialize the board, plant a very first food item
void start(void) {
        int i;
	for(i = 0; i < w; ++i)
		board[i] = board[i + (h - 1) * w] = BORDER;
	for(i = 0; i < h; ++i)
		board[i * w] = board[i * w + w - 1] = BORDER;
	head = w * (h - 1 - h % 2) / 2; // screen center for any h
	board[head] = -5;
	dir = N;
	quit = 0;
	srand(time(0));
	plant();
}
 
void step() {
	int len = board[head];
	switch(dir) {
		case N: head -= w; break;
		case S: head += w; break;
		case W: --head; break;
		case E: ++head; break;
	}
	switch(board[head]) {
		case SPACE:
			board[head] = len - 1; // keep in mind len is negative
			age();
			break;
		case FOOD:
			board[head] = len - 1;
			plant();
			break;
		default:
			quit = 1;
	}
}
 
void show() {
	const char * symbol = " @.";
        int i;
	for(i = 0; i < w * h; ++i)
		positional_putch(i / w, i % w,
			board[i] < 0 ? '#' : symbol[board[i]]);
	update_screen();
}
 
int main (int argc, char * argv[]) {
	init_screen();
	start();
	do {
		show();
		switch(nonblocking_getch()) {
			case 'i': dir = N; break;
			case 'j': dir = W; break;
			case 'k': dir = S; break;
			case 'l': dir = E; break;
			case 'q': quit = 1; break;
		}
		step();
		millisecond_sleep(100); // beware, this approach
		// is not suitable for anything but toy projects like this
	}
	while(!quit);
	millisecond_sleep(999);
	close_screen();
	return 0;
}