Linux学习之路(番外--贪吃蛇)

#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));            //打印完后给一个延迟来进入下一个周期
}

// 生成食物
void 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;//生成在边框,重新生成
            continue;
        }
        for(i = 0;i < len; i++)
        {
            if(food == snake[i])
            {
                temp = 1;    //生成在蛇的身体,重新生成
            }
        }
    }
    
}

// 移动蛇
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 = 1; i < len; i++)
    {    //判断是否撞到自己身体
        if(snake[i] == snake[0])
        {
            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;
}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值