Källkod

/*
 * snake.c
 *
 * Created: 2015-04-07 09:58:47
 * Author: Johanna Öjeling and Carl Bergman
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>


char display[8][128];

int points = 0;
int apple[2];
int alive = 1;

// Snake
int length = 3;
int snake[100][2];
int dir = 2; // 1=N, 2=E, 3=S, 4=W

// Other variables
int click = 0;

void main(void)
{	
	setDataDirection();
	resetHigh();
	startDisplay();
	startGame();
	
	play();
	
	while(1){}
}

void play() {
	clearDisplay();
	setupSnake();
	createApple();
	setupBoard();
	writeSnake();
	writeScore();
	
	while(alive) {
		move();
		_delay_ms(500);
	}
}

void restart() {
	length = 3;
	dir = 2;
	points = 0;
	alive = 1;
	play();
}

void move() {
	
	int newPos[2];
	newPos[0] = getNextX();
	newPos[1] = getNextY();
	if (newPos[0] == apple[0] && newPos[1] == apple[1]) {

		// förläng ormen
		length++;
		for (int i = length - 1; i > 0; i--) {
			snake[i][0] = snake[i-1][0];
			snake[i][1] = snake[i-1][1];
		}
		
		// Set the head of the snake
		snake[0][0] = newPos[0];
		snake[0][1] = newPos[1];
		
		createApple();
		
		points++;
		writeScore();
		
	} else if (newPos[0] > 62 || newPos[0] < 1 || newPos[1] > 62 || newPos[1] < 1 || selfCollision() == 1) {
		alive = 0;
	} else {
	
		// Save last position in snake temporarily
		int last[2];
		last[0] = snake[length - 1][0];
		last[1] = snake[length - 1][1];
	
		// Move snake forward (start from the rear)
		for (int i = length - 1; i > 0; i--) {
			snake[i][0] = snake[i-1][0];
			snake[i][1] = snake[i-1][1];
		}
	
		// Set the head of the snake
		snake[0][0] = newPos[0];
		snake[0][1] = newPos[1];
	
		// Erase the snake at the position that the snake
		// just left.
		erase(last[0], last[1]);
	}
	
	drawSnake();
}

int selfCollision() {
	
	int head[2];
	head[0] = snake[0][0];
	head[1] = snake[0][1];
	
	for (int i = 1; i < length; i++) {
		if (head[0] == snake[i][0] && head[1] == snake[i][1]) {
			return 1;
		}
	}
	
	return 0;
}

void createApple() {
	int newApple[2];
	
	do {
		newApple[0] = getInt(64);
		newApple[1] = getInt(64);
	} while (validateApple(newApple) == 0);
	
	apple[0] = newApple[0];
	apple[1] = newApple[1];
	
	draw(apple[0], apple[1]);
}

int getNextX() {
	
	int x;
	
	switch (dir) {
		case 1:
			x = snake[0][0] + 1;		
			break;
		case 2:
			x = snake[0][0];
			break;
		case 3:
			x = snake[0][0] - 1;
			break;
		case 4:
			x = snake[0][0];
			break;
	}
	
	return x;
}

int getNextY() {
	
	int y;
	
	switch (dir) {
		case 1:
			y = snake[0][1];
			break;
		case 2:
			y = snake[0][1] - 1;
			break;
		case 3:
			y = snake[0][1];
			break;
		case 4:
			y = snake[0][1] + 1;
			break;
	}
	
	return y;
}

int validateApple (int newApple[]) {
	for (int i = 0; i < length; i++) {
		if (snake[i][0] == newApple[0] && snake[i][1] == newApple[1]) {
			return 0;
		}
	}
	if (newApple[0] > 62 || newApple[0] < 1 || newApple[1] > 62 || newApple[1] < 1) {
		return 0;
	}
	return 1;
}

void drawSnake() {
	for (int i = 0; i < length; i++) {
		draw(snake[i][0], snake[i][1]);
	}
}

void setupSnake() {
	
	snake[0][0] = 32;
	snake[0][1] = 30;
	
	snake[1][0] = 32;
	snake[1][1] = 31;
	
	snake[2][0] = 32;
	snake[2][1] = 32;
	
	drawSnake();
	
}

void writeScore() {
	
	int startX = 3;
	int startY = 67;
	
	int tempPoints = points;
	int nDigits = floor(log10(abs(points))) + 1;
	
	if (points == 0) {
		nDigits = 1;
	}
	
	for (int i = 0; i < nDigits; i++) {
		writeInt(startX, startY + i * 8, tempPoints % 10);
		tempPoints = tempPoints / 10;
	}
}

void setDataDirection() {
	DDRA |= 0b11111111;
	DDRB |= 0b11111111;
}

void resetHigh () {
	PORTA |= (1<<2);
}

void resetLow () {
	PORTA &= ~(1<<2);
}

void eHigh () {
	PORTA |= (1<<5);
}

void eLow () {
	PORTA &= ~(1<<5);
}

void rsHigh () {
	PORTA |= (1<<4);
}

void rsLow () {
	PORTA &= ~(1<<4);
}

void rwHigh () {
	PORTA |= (1<<3);
}

void rwLow () {
	PORTA &= ~(1<<3);
}

void selectChip1 () {
	PORTA &= ~(1<<1);
	PORTA |= (1<<0);
}

void selectChip2 () {
	PORTA &= ~(1<<0);
	PORTA |= (1<<1);
}

void startDisplay () {
	
	eLow();
	rsLow();
	rwLow();
	
	// Set data
	PORTB |= 0b00111111;
	
	PORTA |= (1<<0);
	PORTA |= (1<<1);
	
	eHigh();
	eLow();
}

void endDisplay () {
	
	rsLow();
	rwLow();
	
	// Set data
	PORTB |= 0b00111110;
	
	eHigh();
	eLow();
}

void startGame() {
	// Enable interrupt for buttons
	PIND = 0b00000000;
	DDRD = 0b10001011;
	GICR = 0b01000000;
	MCUCR = 0b00000011;
	sei();
}

void setupBoard() {
	// Draw the edge of the board.
	for (int i = 0; i < 64; i++) {
		draw(0, i);
		draw(63, i);
		draw(i, 0);
		draw(i, 63);
	}
}

void setX(int x) {
	
	rsLow();
	rwLow();
	
	PORTB = 0b10111000 | (x/8);
	
	eHigh();
	eLow();
}

void setY(int y) {	
	
	rsLow();
	rwLow();
	
	PORTB = 0b01000000 | y;
	
	eHigh();
	eLow();
}

void draw(int x, int y) {
	
	int newY;
	
	if (y < 64) {
		selectChip1();
		newY = y;
	} else {
		selectChip2();
		newY = y - 64;
	}
	
	setY(newY);
	setX(x);
	
	rsHigh();
	rwLow();
	
	display[x/8][y] = display[x/8][y] | (1<<(x%8));
	PORTB = display[x/8][y];
	
	eHigh();
	eLow();
}

void erase(int x, int y) {
	
	int newY;
	
	if (y < 64) {
		selectChip1();
		newY = y;
	} else {
		selectChip2();
		newY = y - 64;
	}
	
	setY(newY);
	setX(x);
	
	rsHigh();
	rwLow();
	
	display[x/8][y] = display[x/8][y] & ~(1<<(x%8));
	PORTB = display[x/8][y];
	
	eHigh();
	eLow();
}

void clearDisplay() {
	for (int c = 0; c < 128; c++) {		
		for (int r = 0; r < 64; r++) {
			erase(r,c);			
		}
	}	
}

int getInt (int limit) {
    int divisor = RAND_MAX/(limit+1);
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval > limit);

    return retval;
}

void writeInt (int x, int y, int n) {
	
	if (n >= 0 && n <= 9) {
		for (int r = x; r < x + 10; r++) {
			for (int c = y; c < y + 6; c++) {
				draw(r, c);
			}
		}
		
		switch (n) {
			case 0:
				for (int r = x + 2; r < x +8; r++) {
					erase(r, y + 2);
					erase(r, y + 3);
				}
			break;
			case 1:
				for (int r = x; r < x + 10; r++) {
					erase(r, y + 2);
					erase(r, y + 3);
					erase(r, y + 4);
					erase(r, y + 5);
				}
			break;
			case 2:				
					erase(x + 2, y);
					erase(x + 2, y + 1);
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					
					erase(x + 3, y);
					erase(x + 3, y + 1);
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					erase(x + 6, y + 4);
					erase(x + 6, y + 5);
					
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
					erase(x + 7, y + 4);
					erase(x + 7, y + 5);
			break;
			case 3:				
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					erase(x + 2, y + 4);
					erase(x + 2, y + 5);
					
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					erase(x + 3, y + 4);
					erase(x + 3, y + 5);
					
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					erase(x + 6, y + 4);
					erase(x + 6, y + 5);
					
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
					erase(x + 7, y + 4);
					erase(x + 7, y + 5);
			break;
			case 4:
				for (int r = x; r < x + 4; r++) {
					for (int c = y + 2; c < y + 6; c++) {
						erase(r, c);
					}	
				}
				erase(x + 6, y + 2);
				erase(x + 6, y + 3);
				erase(x + 7, y + 2);
				erase(x + 7, y + 3);
				erase(x + 8, y + 2);
				erase(x + 8, y + 3);
				erase(x + 9, y + 2);
				erase(x + 9, y + 3);
			break;
			case 5:				
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					erase(x + 2, y + 4);
					erase(x + 2, y + 5);
					
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					erase(x + 3, y + 4);
					erase(x + 3, y + 5);
					
					erase(x + 6, y);
					erase(x + 6, y + 1);
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					
					erase(x + 7, y);
					erase(x + 7, y + 1);
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
			break;
			case 6:					
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					
					erase(x + 6, y);
					erase(x + 6, y + 1);
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					
					erase(x + 7, y);
					erase(x + 7, y + 1);
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
			break;
			case 7:
				for (int r = x; r < x +8; r++) {
					erase(r, y + 2);
					erase(r, y + 3);
					erase(r, y + 4);
					erase(r, y + 5);
				}
			break;
			case 8:					
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
			break;
			case 9:				
					erase(x + 2, y + 2);
					erase(x + 2, y + 3);
					erase(x + 2, y + 4);
					erase(x + 2, y + 5);
					
					erase(x + 3, y + 2);
					erase(x + 3, y + 3);
					erase(x + 3, y + 4);
					erase(x + 3, y + 5);
					
					erase(x + 6, y + 2);
					erase(x + 6, y + 3);
					
					erase(x + 7, y + 2);
					erase(x + 7, y + 3);
			break;
		}
	}

}

void writeSnake() {
	int x = 49;
	int y = 67;
	
	// S
	y = y + 12;
	for (int r = 0; r < 12; r++) {
		for (int c = 0; c < 10; c++) {
			draw(x + r, y + c);
		}
	}
	for (int i = 0; i < 8; i++) {
		erase(x+2, y+2+i);
		erase(x+3, y+2+i);	
		erase(x+4, y+2+i);
		erase(x+7, y+i);	
		erase(x+8, y+i);	
		erase(x+9, y+i);	
	}

	// N
	y = y + 12;
	for (int r = 0; r < 12; r++) {
		for (int c = 0; c < 10; c++) {
			draw(x + r, y + c);
		}
	}
	for (int r = 0; r < 7; r++) {
		for (int c = r; c < 7; c++) {
			erase(x+r, y+c+1);
			erase(x+11-r, y+8-c);
		}
		//erase(x+11, y+r+2);
		//erase(x, y+r+2);
	}

	// A
	y = y + 12;
	for (int r = 0; r < 12; r++) {
		for (int c = 0; c < 10; c++) {
			draw(x + r, y + c);
		}
	}
	for (int c = 0; c < 6; c++) {
		for (int r = 0; r < 5; r++) {
			erase(x+r, y+2+c);
		}
		for (int r = 0; r < 3; r++) {
			erase(x+7+r, y+2+c);
		}
	}

	// K
	y = y + 12;
	for (int r = 0; r < 12; r++) {
		for (int c = 0; c < 10; c++) {
			erase(x + r, y + c);
		}
	}
	for (int i = 0; i < 6; i++) {
		for (int j = i; j < 3 + i; j++) {
			draw(x + i, y + j);
			draw(x + 11 - i, y + j);
		}
	}
	for (int i = 0; i < 12; i++) {
		draw(x + i, y + 9);
		draw(x + i, y + 8);
	}

	// E
	for (int r = 0; r < 12; r++) {
		for (int c = 0; c < 10; c++) {
			draw(x + r, y + c);
		}
	}
	for (int i = 0; i < 8; i++) {
		erase(x + 2, y + i);
		erase(x + 3, y + i);
		erase(x + 4, y + i);
		
		erase(x + 7, y + i);
		erase(x + 8, y + i);
		erase(x + 9, y + i);
	}
	erase(x+5, y);
	erase(x+5, y+1);
	erase(x+6, y);
	erase(x+6, y+1);

}

// Buttons
ISR(INT0_vect) {
	
	if (click == 1) {
		return;
	}
	
	click = 1;	
	cli(); // Disable interrupt
	
	_delay_ms(200);
	
	switch(PIND) {
	
		case 0b00010100: // Right button pressed
			if (dir == 4) {
				dir = 1;
			} else {
				dir++;
			}
		break;
		
		case 0b00100100: // Left button pressed
			if (dir == 1) {
				dir = 4;
			} else {
				dir--;	
			}
		break;
		
		case 0b01000100: // Reset button pressed
			sei(); // Enable interrupt
			click = 0;
			restart();
		break;
	}
	
	sei(); // Enable interrupt
	
	click = 0;
}