C语言贪吃蛇游戏——双向链表数据结构实现

  采用了双向链表结点来模拟蛇身结点;

  通过C语言光标控制函数来打印地图、蛇身和食物;

/**************************
***************************
	贪吃蛇游戏
	C语言数据结构
	作者:Dew
	时间:2019年3月23日
	版本:1.0
***************************
**************************/


#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>

#define N 30
#define TRUE 1
#define FALSE 0
#define TIME 300

#define LEFT 37
#define UP 38
#define RIGHT 39
#define DOWN 40

void initMap();
void showGame();
void initSnake();
void control(int key);
void updateSnake(int next_head_x, int next_head_y);
void gotoxy(int x, int y); //光标控制
void gameRun();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
void createFood();
void addSnakeNode(int cur_tail_x, int cur_tail_y);
void crashTest(int head_x, int head_y);

struct snakeNode {
	int pos_x;
	int pos_y;
	snakeNode* pre;
	snakeNode* next;
};

struct foodNode {
	int pos_x;
	int pos_y;
};

int map[N][N];
int keyPress;
int key;

int next_head_x, next_head_y;
int cur_tail_x, cur_tail_y;

snakeNode* snake_head = (snakeNode *)malloc(sizeof(snakeNode));
snakeNode* snake_tail = (snakeNode *)malloc(sizeof(snakeNode));

foodNode* food = (foodNode *)malloc(sizeof(foodNode));

int main()
{
	initSnake();

	initMap();

	gameRun();

	return 0;
}

void initMap()
{
	int i, j;
	for(i = 0; i < N; i++)
		for (j = 0; j < N; j++)
		{
			if (i == 0 || i == N - 1)
				map[i][j] = 1;
			else if (j == 0 || j == N - 1)
				map[i][j] = 1;
			else
				map[i][j] = 0;
		}
}

void showGame()
{
	int i, j;
	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			if (map[i][j] == 1) {
				gotoxy(j*2, i);
				printf("□");
			}
			else if (map[i][j] == 0) {
				gotoxy(j*2, i);
				printf("  ");
			}
		}
		printf("\n");
	}
	gotoxy(snake_head->pos_y * 2, snake_head->pos_x);
	printf("●");
	gotoxy(snake_tail->pos_y * 2, snake_tail->pos_x);
	printf("●");
	gotoxy(food->pos_y * 2, food->pos_x);
	printf("◇");
}

void initSnake()
{
	snake_head->pos_x = 15;
	snake_head->pos_y = 15;
	snake_head->pre = NULL;
	snake_head->next = snake_tail;

	snake_tail->pre = snake_head;
	snake_tail->pos_x = snake_tail->pre->pos_x + 1;
	snake_tail->pos_y = snake_tail->pre->pos_y;
	snake_tail->next = NULL;

	food->pos_x = rand() % 28 + 1;
	food->pos_y = rand() % 28 + 1;
}

void control(int direction)
{
	if (direction == UP)
	{
		moveUp();
	}
	else if (direction == DOWN)
	{
		moveDown();
	}
	else if (direction == LEFT)
	{
		moveLeft();
	}
	else if (direction == RIGHT)
	{
		moveRight();
	}
	
}

void updateSnake(int next_head_x, int next_head_y)
{
	snakeNode* p = snake_tail;
	while (p != snake_head)
	{
		p->pos_x = p->pre->pos_x;
		p->pos_y = p->pre->pos_y;
		p = p->pre;
	}
	p->pos_x = next_head_x;
	p->pos_y = next_head_y;
}

void gotoxy(int x, int y)
{
	COORD pos;
	HANDLE hOutput;
	pos.X = x;
	pos.Y = y;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOutput, pos);
}

void gameRun()
{
	showGame();

	control(UP);

	while (TRUE)
	{
		if (GetAsyncKeyState(VK_RIGHT))
		{
			control(RIGHT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			control(LEFT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_UP))
		{
			control(UP);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			control(DOWN);
			Sleep(TIME);
		}
	}
}

void moveUp()
{
	while (TRUE)
	{
		next_head_x = snake_head->pos_x - 1;
		next_head_y = snake_head->pos_y;
		cur_tail_x = snake_tail->pos_x;
		cur_tail_y = snake_tail->pos_y;
		updateSnake(next_head_x, next_head_y);
		gotoxy(next_head_y * 2, next_head_x);
		printf("●");
		crashTest(next_head_x, next_head_y);
		if (next_head_x == food->pos_x && next_head_y == food->pos_y)
		{
			addSnakeNode(cur_tail_x, cur_tail_y);
			createFood();
		}
		else
		{
			gotoxy(cur_tail_y * 2, cur_tail_x);
			printf("  ");
		}

		Sleep(TIME);

		if (GetAsyncKeyState(VK_RIGHT))
		{
			control(RIGHT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			control(LEFT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_UP))
		{
			control(UP);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			continue;
		}

	}
}

void moveDown()
{
	while (TRUE)
	{
		next_head_x = snake_head->pos_x + 1;
		next_head_y = snake_head->pos_y;
		cur_tail_x = snake_tail->pos_x;
		cur_tail_y = snake_tail->pos_y;
		updateSnake(next_head_x, next_head_y);
		gotoxy(next_head_y * 2, next_head_x);
		printf("●");
		crashTest(next_head_x, next_head_y);
		if (next_head_x == food->pos_x && next_head_y == food->pos_y)
		{
			addSnakeNode(cur_tail_x, cur_tail_y);
			createFood();
		}
		else
		{
			gotoxy(cur_tail_y * 2, cur_tail_x);
			printf("  ");
		}

		Sleep(TIME);
		if (GetAsyncKeyState(VK_RIGHT))
		{
			control(RIGHT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			control(LEFT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_UP))
		{
			continue;
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			control(DOWN);
			Sleep(TIME);
		}

	}
}

void moveLeft()
{
	while (TRUE)
	{
		next_head_x = snake_head->pos_x;
		next_head_y = snake_head->pos_y - 1;
		cur_tail_x = snake_tail->pos_x;
		cur_tail_y = snake_tail->pos_y;
		updateSnake(next_head_x, next_head_y);
		gotoxy(next_head_y * 2, next_head_x);
		printf("●");
		crashTest(next_head_x, next_head_y);
		if (next_head_x == food->pos_x && next_head_y == food->pos_y)
		{
			addSnakeNode(cur_tail_x, cur_tail_y);
			createFood();
		}
		else
		{
			gotoxy(cur_tail_y * 2, cur_tail_x);
			printf("  ");
		}

		Sleep(TIME);
		if (GetAsyncKeyState(VK_RIGHT))
		{
			continue;
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			control(LEFT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_UP))
		{
			control(UP);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			control(DOWN);
			Sleep(TIME);
		}

	}
}

void moveRight()
{
	while (TRUE)
	{
		next_head_x = snake_head->pos_x;
		next_head_y = snake_head->pos_y + 1;
		cur_tail_x = snake_tail->pos_x;
		cur_tail_y = snake_tail->pos_y;
		updateSnake(next_head_x, next_head_y);
		gotoxy(next_head_y * 2, next_head_x);
		printf("●");
		crashTest(next_head_x, next_head_y);
		if (next_head_x == food->pos_x && next_head_y == food->pos_y)
		{
			addSnakeNode(cur_tail_x, cur_tail_y);
			createFood();
		}
		else
		{
			gotoxy(cur_tail_y * 2, cur_tail_x);
			printf("  ");
		}

		Sleep(TIME);
		if (GetAsyncKeyState(VK_RIGHT))
		{
			control(RIGHT);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_LEFT))
		{
			continue;
		}
		else if (GetAsyncKeyState(VK_UP))
		{
			control(UP);
			Sleep(TIME);
		}
		else if (GetAsyncKeyState(VK_DOWN))
		{
			control(DOWN);
			Sleep(TIME);
		}

	}
}

void createFood()
{
	food->pos_x = rand() % 28 + 1;
	food->pos_y = rand() % 28 + 1;
	gotoxy(food->pos_y * 2, food->pos_x);
	printf("◇");
}

void addSnakeNode(int cur_tail_x, int cur_tail_y)
{
	snakeNode* tempNode = (snakeNode *)malloc(sizeof(snakeNode));
	tempNode->pos_x = cur_tail_x;
	tempNode->pos_y = cur_tail_y;
	tempNode->next = NULL;
	snake_tail->next = tempNode;
	tempNode->pre = snake_tail;
	snake_tail = tempNode;
}

void crashTest(int head_x, int head_y)
{
	snakeNode* p = snake_head->next;
	while (p != NULL)
	{
		if (p->pos_x == head_x && p->pos_y == head_y)
		{
			gotoxy(32 * 2, 15);
			printf("...发生撞击!......游戏结束...");
			getchar();
		}
		if (p->pos_x == 1 || p->pos_x == N - 2 || p->pos_y == 1 || p->pos_y == N - 2)
		{
			gotoxy(32 * 2, 15);
			printf("...发生撞击!......游戏结束...");
			getchar();
		}
		p = p->next;
	}
}