#include "snake.h"
//定义需要的全局变量
const int COL = 15;
const int ROW = 20;
int score = 0;
pNode pTail = NULL;
//在地图中心生成长度为 1 的贪吃蛇
pNode InitSnake() {
pNode pHead = NULL, p2 = NULL, p3 = NULL;
pHead = (pNode)malloc(sizeof(Node));
pHead->x = ROW / 2;
pHead->y = COL / 2;
pHead->next = pHead->pre = NULL;
p2 = (pNode)malloc(sizeof(Node));
p2->x = pHead->x;
p2->y = pHead->y + 1;
p2->next = NULL;
p2->pre = pHead;
pHead->next = p2;
p3 = (pNode)malloc(sizeof(Node));
p3->x = pHead->x;
p3->y = pHead->y + 2;
p3->next = NULL;
p3->pre = p2;
p2->next = p3;
pTail = p3;
return pHead;
}
//在地图的随机位置生成食物
Food CreateFood() {
Food food;
srand((unsigned)time(NULL));
food.x = rand() % ROW;
food.y = rand() % COL;
return food;
}
//贪吃蛇移动的过程,即链表中所有节点从尾结点开始逐个向前移动一个位置
bool Move(pNode pHead, char key) {
bool game_over = false;
pNode pt = pTail;
while (pt != pHead) { // 每个节点依次向前完成蛇的移动
pt->x = pt->pre->x;
pt->y = pt->pre->y;
pt = pt->pre;
}
switch (key) {
case'd': {
pHead->x += 1;
if (pHead->x >= ROW)
game_over = true;
break;
}
case'a': {
pHead->x -= 1;
if (pHead->x < 0)
game_over = true;
break;
}
case's': {
pHead->y += 1;
if (pHead->y >= COL)
game_over = true;
break;
}
case'w': {
pHead->y -= 1;
if (pHead->y < 0)
game_over = true;;
break;
}
}
if (SnakeDeath(pHead))
game_over = true;
return game_over;
}
char CheckKey(char direct) {
char key;
if (kbhit()) { // kbhit函数检查是否有键盘端的输入
key = getch();
if (direct != 'd'&& key == 'a')
direct = key;
else if (direct != 'a'&&key == 'd')
direct = key;
else if (direct != 'w'&&key == 's')
direct = key;
else if (direct != 's'&&key == 'w')
direct = key;
else if (key == 27) // 27是esc的ascII码
direct = key;
}
return direct;
}
//吃食物,等同于链表中新增一个节点
pNode EatFood(pNode pHead, pFood pFood) {
pNode p_add = NULL, pt = NULL;
if (pFood->x == pHead->x&&pFood->y == pHead->y) {
p_add = (pNode)malloc(sizeof(Node));
score++;
pTail->next = p_add;
p_add->pre = pTail;
p_add->next = NULL;
pTail = p_add;
// 检查食物是否出现在蛇身的位置上
do {
*pFood = CreateFood();
} while (FoodInSnake(pHead, pFood));
}
return pHead;
}
//判断食物的出现位置是否和蛇身重合
bool FoodInSnake(pNode pHead, pFood pFood) {
pNode pt = NULL;
for (pt = pHead; pt != NULL; pt = pt->next) {
if (pFood->x == pt->x&&pFood->y == pt->y)
return true;
}
return false;
}
//当蛇头和蛇身重合时,游戏结束
bool SnakeDeath(pNode pHead) {
pNode pt = NULL;
for (pt = pHead->next; pt != NULL; pt = pt->next) {
if (pt->x == pHead->x&&pt->y == pHead->y)
return true;
}
return false;
}
void Show(pNode pHead, Food food) {
int row = 0, col = 0, flag = 0;
pNode pt = NULL;
system("cls");
printf("\n\n");
color(3);
printf(" 学数据结构,欢迎看我的博客:https://blog.csdn.net/qq_25775935\n");
printf(" \n");
printf(" 游戏名: 贪吃蛇 分数: ");
printf(" %d\n", score);
printf(" ----------------------------------------------\n\n\n");
printf(" ");
printf("┌");
for (row = 0; row < ROW; row++) {
color(3);
printf("──");
}
printf("┐");
putchar('\n');
for (col = 0; col < COL; col++) {
color(3);
printf(" ┃");
for (row = 0; row < ROW; row++) {
pt = pHead;
flag = 0;
//打印出蛇
while (pt != NULL) {
if (row == pt->x && col == pt->y) {
if (pt == pHead) {
color(6);
printf("■");
}
else {
color(6);
printf("□");
}
flag = 1;
break;
}
pt = pt->next;
}
//打印出食物或两个空格
if (!flag) {
if (row == food.x && col == food.y) {
color(4);
printf("★");
continue;
}
printf(" ");
}
}
color(3);
printf("┃\n");
}
printf(" └");
for (row = 0; row < ROW; row++) {
color(3);
printf("━━");
}
printf("┘");
color(3);
putchar('\n');
printf("\n ----------------------------------------------\n");
printf(" W↑ A← →D ↓S");
}
//退出游戏前,手动销毁链表中各个节点
void ExitGame(pNode *pHead)
{
pNode p_delete = NULL, p_head = NULL;
while (*pHead != NULL) {
p_head = (*pHead)->next;
if (p_head != NULL)
p_head->pre = NULL;
p_delete = *pHead;
free(p_delete);
p_delete = NULL;
*pHead = p_head;
}
}
void color(int m) {
HANDLE consolehend;
consolehend = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(consolehend, m);
}
// 隐藏光标
void gotoxy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
void HideCursor() {
CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}