#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<time.h>
#include<windows.h>
#define WIGTH 50
#define HEIGHT 25
//const int iWight = 50;
//const int iHeight = 50;
char cBody = '#';
char cFloor = ' ';
char cFood = '$';
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode *pNext;
} SnakeNode;
char GlobleMap[HEIGHT][WIGTH] = {0};
int iLengt = 2;
SnakeNode* CreatSnake(); // 创建一个蛇头
SnakeNode* CreatFood(SnakeNode *pHead); // 创建一个食物
int IsBump(SnakeNode *pFood, SnakeNode *pHead); // 检测与食物、墙壁、身体的碰撞
char MoveSnake(char cDirection, SnakeNode **pHead); // 给一个方向移动蛇,要改变蛇头,所以这里用二级指针
void Init(); // 初始化地图
void GetKey(int x);
void Elongate(char cDirection, SnakeNode *pHead); // 增加蛇的长度
void PrintSnake(SnakeNode *pHead); // 将蛇身打印在地图里
void PrintFood(SnakeNode *pFood); // 将食物打印在地图里
void DrewGloble(); // 打印地图
void Free(SnakeNode *pHead); // 释放内存,结束时调用
void GoToXY(int x, int y); // 辅助函数
int main()
{
SnakeNode *pHead = CreatSnake();
SnakeNode *pFood = CreatFood(pHead);
int t;
char cDirection = 0;
GoToXY(40, 10);
printf("开始之前请将输入法设置为英文小写\n");
GoToXY(40, 12);
printf("w--上;s--下;a--左;d--右;其他键暂停");
GoToXY(40, 14);
printf("按回车键开始游戏。。。。。。");
getchar();
system("cls");
while(1)
{
Init();
PrintSnake(pHead);
PrintFood(pFood);
DrewGloble();
//------------这一段没写在函数里,有点麻烦------------
if(!kbhit())
{
cDirection = MoveSnake(cDirection, &pHead); // 如果没有按键盘,按原来的方向走
}
else
{
char cTmp = getch(); // 按下键盘,检测键盘的值,确保不会回头
if(cDirection == 's' && cTmp == 'w')
MoveSnake(cDirection, &pHead);
else if(cDirection == 'w' && cTmp == 's')
MoveSnake(cDirection, &pHead);
else if(cDirection == 'd' && cTmp == 'a')
MoveSnake(cDirection, &pHead);
else if(cDirection == 'a' && cTmp == 'd')
MoveSnake(cDirection, &pHead);
else
cDirection = MoveSnake(cTmp, &pHead);
}
//--------------按下键盘,检测键盘的值,确保不会回头--------------
//--------------碰撞检测--------------------
t = IsBump(pFood, pHead);
if(t == 1) // 吃到食物, 蛇身边长,更新食物
{
Elongate(cDirection, pHead);
pFood = CreatFood(pHead);
}
else if(t == 2) // 撞到墙或者身体,游戏结束
{
GoToXY(60, 12);
printf("\aGAME OVER");
GoToXY(60, 14);
printf("哎呀,你撞到墙了!");
break;
}
else if(t == 3) // 撞到墙或者身体,游戏结束
{
GoToXY(60, 12);
printf("\aGAME OVER");
GoToXY(60, 14);
printf("哎呀,你吃到自己了!");
break;
}
//-------------------------------------------
}
Free(pHead);
getchar();
GoToXY(0, 26);
return 0;
}
void Init()
{
GoToXY(0, 0); // 回到左上角的位置,重新打印地图
for(int i=0; i<HEIGHT; i++)
{
for(int j=0 ;j<WIGTH; j++)
{
if(i==0 || i==HEIGHT-1)
GlobleMap[i][j] = '_';
else if(j==0 || j==WIGTH-1)
GlobleMap[i][j] = '|';
else
GlobleMap[i][j] = ' ';
}
}
}
SnakeNode* CreatSnake()
{
SnakeNode *pHead = (SnakeNode*)malloc(sizeof(SnakeNode)); // 创建两个节点的蛇
pHead->x = 6;
pHead->y = 9;
pHead->pNext = (SnakeNode*)malloc(sizeof(SnakeNode));
pHead->pNext->x = 7;
pHead->pNext->y = 9;
pHead->pNext->pNext = NULL;
return pHead;
}
SnakeNode* CreatFood(SnakeNode *pHead)
{
srand(time(NULL));
SnakeNode *pFood = (SnakeNode*)malloc(sizeof(SnakeNode));
pFood->pNext = NULL;
SnakeNode *pNon = pHead;
int x = rand()%48 + 1; // 确保食物不会出现在边界, 还应该写 食物不能出现在蛇身,我暂时没写
int y = rand()%23 + 1;
A:
while(pNon != NULL)
{
if(pNon->x == x && pNon->y == y)
{
x = rand()%48 + 1;
y = rand()%22 + 1;
pNon = pHead;
goto A;
}
pNon = pNon->pNext;
}
pFood->x = x;
pFood->y = y;
return pFood;
}
void Elongate(char cDirection, SnakeNode *pHead)
{
SnakeNode *pNon = pHead;
SnakeNode *pTmp;
while(pNon->pNext != NULL)
{
pNon = pNon->pNext;
}
pTmp = (SnakeNode*)malloc(sizeof(SnakeNode)); // 在蛇尾添加一个节点
pNon->pNext = pTmp;
pTmp->pNext = NULL;
switch(cDirection) // 添加的节点,与移动方向相反,例如:蛇头往上走,添加的节点在尾巴的下面
{
case 's': pTmp->y = pNon->y - 1;
pTmp->x = pNon->x;
break;
case 'w': pTmp->y = pNon->y + 1;
pTmp->x = pNon->x;
break;
case 'd': pTmp->x = pNon->x - 1;
pTmp->y = pNon->y;
break;
case 'a': pTmp->x = pNon->x + 1;
pTmp->y = pNon->y;
break;
default : break;
}
// printf("\a");
}
void PrintSnake(SnakeNode *pHead)
{
SnakeNode *pNon = pHead; // 将蛇的位置,标注在地图上
while(pNon != NULL)
{
GlobleMap[pNon->y][pNon->x] = cBody;
pNon = pNon->pNext;
}
}
void PrintFood(SnakeNode *pFood)
{
GlobleMap[pFood->y][pFood->x] = cFood; // 将食物的位置,标注在地图上
}
///这里改变了头指针的值,所以要传入指针的地址
char MoveSnake(char cDirection, SnakeNode **pHead)
{
SnakeNode *pNon = *pHead;
while(pNon->pNext->pNext != NULL) // 找到尾节点的前一个节点
pNon = pNon->pNext;
SnakeNode *pTmp = pNon->pNext; // pTmp为尾节点
pNon->pNext = NULL; // pNon变成尾节点
pTmp->pNext = *pHead; // pTmp指向头节点
*pHead = pTmp; // 更新pHead*pHead
switch(cDirection) // 整体思想是 把蛇尾拿下来,放在蛇头上,来蛇的整体实现移动
{
case 'w': (*pHead)->y = (*pHead)->pNext->y - 1;
(*pHead)->x = (*pHead)->pNext->x;
break;
case 's': (*pHead)->y = (*pHead)->pNext->y + 1;
(*pHead)->x = (*pHead)->pNext->x;
break;
case 'a': (*pHead)->x = (*pHead)->pNext->x - 1;
(*pHead)->y = (*pHead)->pNext->y;
break;
case 'd': (*pHead)->x = (*pHead)->pNext->x + 1;
(*pHead)->y = (*pHead)->pNext->y;
break;
default : break;
}
return cDirection;
}
void DrewGloble()
{
for(int i=0; i<HEIGHT; i++)
{
for(int j=0 ;j<WIGTH; j++)
{
printf("%c", GlobleMap[i][j]);
}
printf("\n");
}
GoToXY(60, 3);
printf("您的得分是:%d", (iLengt-2)*5);
GoToXY(60, 6);
printf("食物一共有:%d", iLengt-2);
GoToXY(60, 9);
printf("蛇的长度是:%d", iLengt);
}
void Free(SnakeNode *pHead)
{
SnakeNode *pNon = pHead->pNext;
free(pHead);
while(pNon != NULL)
{
SnakeNode *pTmp = pNon->pNext;
free(pNon);
pNon = pTmp;
}
}
int IsBump(SnakeNode *pFood, SnakeNode *pHead)
{
int iFlag = 0;
if(pHead->x == pFood->x && pHead->y == pFood->y)
{
iLengt++;
iFlag = 1; // 1 代表吃到食物
}
else if(pHead->x == 0 || pHead->x == WIGTH-1 || pHead->y == 0 || pHead->y == HEIGHT-1)
{
iFlag = 2; // 2 代表撞墙
}
SnakeNode *pNon = pHead->pNext;
while(pNon != NULL)
{
if(pHead->x == pNon->x && pHead->y == pNon->y)
{
iFlag = 3; // 3 表示撞到自己
break;
}
pNon = pNon->pNext;
}
return iFlag;
}
// 抄的API
void GoToXY(int x, int y) // x, y代表想去的像素点的位置,其他不用知道
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(handle, coord);
}