#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#define KEYCODE_U 0x41 // 向上按键
#define KEYCODE_D 0x42 // 向下按键
#define KEYCODE_L 0x44 // 向左按键
#define KEYCODE_R 0x43 // 向右按键
int kfd = 0;
struct termios cooked, raw;
char dir = KEYCODE_U; // 当前蛇的移动方向
// 获取键盘响应:上、下、左、右键
void* get_dir(void *a)
{
while(1)
{
char c;
tcgetattr(kfd, &cooked); // 得到 termios 结构体保存,然后重新配置终端
memcpy(&raw, &cooked, sizeof(struct termios));
raw.c_lflag &=~ (ICANON | ECHO);
raw.c_cc[VEOL] = 1;
raw.c_cc[VEOF] = 2;
tcsetattr(kfd, TCSANOW, &raw);
if(read(kfd, &c, 1) < 0)
{
perror("read():");
exit(-1);
}
tcsetattr(kfd, TCSANOW, &cooked);//在程序结束时在恢复原来的配置
dir = c;
}
}
unsigned char map[17][17] = {0}; // 游戏地图
int snake[50] = {78}; // 初始化蛇坐标,游戏开始的时候蛇在第5行第11列
int food = 73; // 食物的坐标,游戏开始的时候在第5行第6列
int len = 1; // 保存蛇的当前长度
// 将 数字 转化为坐标系
void num_to_xy(int num, unsigned char *x, unsigned char *y)
{
*x = num/17;
*y = num%17;
}
// 更新地图数据
void update_map()
{
unsigned char x,y;
unsigned char num;
int i,j;
for(i = 0;i <= 289; i++)
{
if(i < 17 || i%17 == 16 || i%17 ==0 || i > 272) //边框位置赋值#
{
num_to_xy(i,&x,&y);
map[x][y] = '#';
}
else if(i == food) //食物位置赋值@
{
num_to_xy(i,&x,&y);
map[x][y] = '@';
}
else
{
num_to_xy(i,&x,&y); //其他位置赋值空格
map[x][y] = ' ';
}
}
for(i = 0;i <=289; i++) //蛇存在的所用位置赋值为"*"
{
for(j = 0; j < len; j++)
{
if(i == snake[j])
{
num_to_xy(i,&x,&y);
map[x][y] = '*';
}
}
}
}
// 打印地图
void print_map()
{
int i,j;
system("clear"); //清屏
for(i = 0;i < 17 ;i++)
{
for(j = 0;j < 17; j++)
{
printf("%c",map[i][j]); //第i行第j列打印map[i][j]
}
printf("\n");
}
usleep(500000/(len/4+1)); //打印完后给一个延迟来进入下一个周期
}
// 生成食物
int generate_food()
{
srand(time(NULL));
int i;
int temp = 1; //用于判定生成的随机数食物符不符合条件
while(temp)
{
food = rand()%289;
temp = 0; //符合条件用0跳出循环
if(food < 17 || food%17 == 16 || food%17 ==0 || food > 272)
{
temp = 1; //生成在边框,重新生成
}
for(i = 0;i < len; i++)
{
if(food == snake[i])
{
temp = 1; //生成在蛇的身体,重新生成
}
}
}
return food;
}
// 移动蛇
void move_snake()
{
unsigned char x,y; // 坐标
num_to_xy(snake[0], &x, &y); // 获取蛇头的坐标
int i = 0;
int end = 0;
// 判断移动方向
switch (dir)
{
case KEYCODE_U: // 向上移动
x--;
break;
case KEYCODE_D: // 向下移动
x++;
break;
case KEYCODE_L: // 向左移动
y--;
break;
case KEYCODE_R: // 向右移动
y++;
break;
}
end = snake[len-1]; //保留上一次的尾巴
for(i = len-1; i > 0; i--)
{
snake[i] = snake[i-1]; //从尾巴到第二个位置逆向覆盖
}
snake[0] = x*17 + y; //根据移动的方向重新生成一个头
if(snake[0] == food)
{
len++; //吃到食物时长度+1
generate_food(); //吃到食物则重新生成随机数
snake[len-1] = end; //在吃到食物时,用上次的尾巴赋值给现在的最后一个位置
}
}
// 判断蛇是否应该存活,如果返回值是0代表应该存活,1代表不应该存活
int isalive()
{
int temp = 0;
int i,j;
if(snake[0] < 17 || snake[0]%17 == 16 || snake[0]%17 ==0 || snake[0] > 272)
{ //判断头是否撞到边框
temp = 1;
}
for(i = 0; i < len; i++)
{ //判断是否撞到自己身体
for(j = i + 1;j < len; j++)
{
if(snake[i] == snake[j])
{
temp = 1;
}
}
}
return temp;
}
int main()
{
// 开启一个线程用于获取键盘的上下左右键响应
pthread_t tid1;
pthread_create(&tid1, NULL, get_dir, NULL);
while(1)
{
// 更新地图数据
update_map();
// 打印地图
print_map();
// 移动蛇
move_snake();
if (isalive() == 1)
{
break;
}
}
tcsetattr(kfd, TCSANOW, &cooked);//在程序结束时在恢复原来的配置
printf ("Game Over!\n");
return 0;
}
贪吃蛇
最新推荐文章于 2021-05-03 08:28:20 发布