请选择 进入手机版 | 继续访问电脑版

字符游戏-智能蛇

[复制链接]
冰宇 发表于 2020-12-31 18:57:50 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
字符游戏-智能蛇

一、VT 100 终端尺度

  这里按照老师的课件要求,体验一下VT 100 输入输出功能以及清屏操纵,代码直接复制课件中代码,这里就不再放一次了,直接给出运行效果:
  1. gcc sin-demo.c -osin.out -lm ./sin.out
复制代码


  • 运行后不绝输出波浪形字符

二、kbhit()

  我们照旧按照课件要求,体验一检测tty输入的程序,将我们之前的snake的代码放入对应位置,运行后查察效果:
  1. #include #include #include #include #include #include #include #include #include static struct termios ori_attr, cur_attr;static __inline int tty_reset(void){        if (tcsetattr(STDIN_FILENO, TCSANOW, &ori_attr) != 0)                return -1;        return 0;}static __inlineint tty_set(void){                if ( tcgetattr(STDIN_FILENO, &ori_attr) )                return -1;                memcpy(&cur_attr, &ori_attr, sizeof(cur_attr) );        cur_attr.c_lflag &= ~ICANON;//        cur_attr.c_lflag |= ECHO;        cur_attr.c_lflag &= ~ECHO;        cur_attr.c_cc[VMIN] = 1;        cur_attr.c_cc[VTIME] = 0;        if (tcsetattr(STDIN_FILENO, TCSANOW, &cur_attr) != 0)                return -1;        return 0;}static __inlineint kbhit(void) {                           fd_set rfds;        struct timeval tv;        int retval;        /* Watch stdin (fd 0) to see when it has input. */        FD_ZERO(&rfds);        FD_SET(0, &rfds);        /* Wait up to five seconds. */        tv.tv_sec  = 0;        tv.tv_usec = 0;        retval = select(1, &rfds, NULL, NULL, &tv);        /* Don&#39;t rely on the value of tv now! */        if (retval == -1) {                perror("select()");                return 0;        } else if (retval)                return 1;        /* FD_ISSET(0, &rfds) will be true. */        else                return 0;        return 0;}//将你的 snake 代码放在这里#define SNAKE_MAX_LENGTH 20#define SNAKE_HEAD &#39;H&#39;#define SNAKE_BODY &#39;X&#39;#define BLANK_CELL &#39; &#39;#define WALL_CELL &#39;*&#39;#define SNAKE_FOOD &#39;$&#39;//  -1体现向上(dy)或者向左(dy)  +1体现向下(dy)或者向右(dx)void snakeMove(int, int);//随机投放食物 void put_money(void);//输出二维数组图形 void output(void);//游戏竣事 void gameover(void);//吃食物int eat_money(int dx, int dy);char map[12][12] ={ "***********","*XXXXH    *","*         *","*         *","*         *","*         *","*         *","*         *","*         *","*         *","*         *","***********" };int snakeX[SNAKE_MAX_LENGTH] = { 1,2,3,4,5 };int snakeY[SNAKE_MAX_LENGTH] = { 1,1,1,1,1 };int moneyX, moneyY;int snakeLength = 5;int continuegame = 1;int main(){                put_money();                               //  首先投放食物         output();        //设置终端进入非缓冲状态        int tty_set_flag;        tty_set_flag = tty_set();        int key;        while(continuegame == 1) {                if( kbhit() ) {                        key = getchar();                        if(key == &#39;w&#39; || key == &#39;W&#39;){                                snakeMove(0, -1);                        }                        if(key == &#39;s&#39; || key == &#39;S&#39;){                                snakeMove(0, 1);                        }                        if(key == &#39;a&#39; || key == &#39;A&#39;){                                snakeMove(-1, 0);                        }                        if(key == &#39;d&#39; || key == &#39;D&#39;){                                snakeMove(1, 0);                        }                system("clear");//对于 VT100 终端, printf("\033[2J"); 也可以实现清屏。                output();                gameover();                }         }        //规复终端设置        if(tty_set_flag == 0)                 tty_reset();        return 0;}void snakeMove(int dx, int dy) {        int i;        //判断是否吃到食物        if (eat_money(dx, dy));        else {                map[snakeY[0]][snakeX[0]] = BLANK_CELL;                //  如果不是,那么以前的最后一节变成空缺                map[snakeY[snakeLength - 1]][snakeX[snakeLength - 1]] = SNAKE_BODY;                //  以前的头变成身子                for (i = 0; i < snakeLength - 1; i++) {                        //  以前所有的坐标都向前移动                        snakeX[i] = snakeX[i + 1];                        snakeY[i] = snakeY[i + 1];                }                snakeX[snakeLength - 1] += dx;                snakeY[snakeLength - 1] += dy;                map[snakeY[snakeLength - 1]][snakeX[snakeLength - 1]] = SNAKE_HEAD;                //  新的头        }}void put_money(void) {        int i;        srand(time(NULL));        moneyX = rand() % 9 + 1;        srand(time(NULL));        moneyY = rand() % 9 + 1;        for (i = 0; i < snakeLength; i++) {                while (moneyX == snakeX[i] && moneyY == snakeY[i]) {                        srand(time(NULL));                        moneyX = rand() % 9 + 1;                        srand(time(NULL));                        moneyY = rand() % 9 + 1;                        i = -1;                }        }        map[moneyY][moneyX] = &#39;$&#39;;}void output(void) {        int i, j;         for (i = 0; i < 12; ++i) {                for (j = 0; j < 12; ++j) {                        printf("%c", map[i][j]);                }                putchar(&#39;\n&#39;);        }}void gameover(void) {        if (snakeX[snakeLength - 1] == 0 || snakeX[snakeLength - 1] == 10                || snakeY[snakeLength - 1] == 0 || snakeY[snakeLength - 1] == 10) {                continuegame = 0;                printf("撞到墙了!") ;         }        int i;        for (i = 0; i < snakeLength - 1; i++) {                //  以前所有的坐标都向前移动                if (snakeX[i] == snakeX[snakeLength - 1] &&                        snakeY[i] == snakeY[snakeLength - 1]) {                        printf("咬到自己了!") ;                         continuegame = 0;                        }        }        if (SNAKE_MAX_LENGTH == snakeLength) {                continuegame = 0;                printf("congratulations!\twin!\n");        }}int eat_money(int dx, int dy) {        if (snakeX[snakeLength - 1] + dx == moneyX && snakeY[snakeLength - 1] + dy == moneyY) {                snakeLength++;                snakeX[snakeLength - 1] = snakeX[snakeLength - 2] + dx;                snakeY[snakeLength - 1] = snakeY[snakeLength - 2] + dy;                map[snakeY[0]][snakeX[0]] = SNAKE_BODY;                map[snakeY[snakeLength - 2]][snakeX[snakeLength - 2]] = SNAKE_BODY;                map[snakeY[snakeLength - 1]][snakeX[snakeLength - 1]] = SNAKE_HEAD;                put_money();                return 1;        }        else return 0;}
复制代码


  • 之后我们编译运行,并查察效果:
  1. gcc kihib.c -oihib.out -lm./kihib.out
复制代码


  • 可以观察看我们的程序变成了检测键盘输入,而不会在终端上出现我们输入的wasd等操纵了,体验到了tty输入的优势

三、实现智能蛇

  所谓的智能蛇,也就是我们要用程序来为我们的snake选择下一步行走的道路,而取代我们的键盘输入,所以整体逻辑和我们原本的snack是相同的,我们要做的是增加一个选择函数,来取代我们的键盘输入来为snake选择门路


  • 我们首先增加对于路径选择函数的界说:
  1. //自动寻找char wheregonext(int hx, int hy, int fx, int fy);
复制代码


  • 之后我们要在检测键盘输入的位置,将字符读取更换为使用我们的函数
  1.         while (continuegame == 1) {                   //  每次循环都要判断是否游戏已经竣事                ch = wheregonext(snakeX[snakeLength - 1], snakeY[snakeLength - 1], moneyX, moneyY);                printf("\033[2J");                switch (ch) {
复制代码


  • 最后是我们的函数部分:

    • 整体思路按照老师给出的伪代码来实现:
    • 伪代码如下


实现代码如下:
[code]//用数组distance[4]={0,0,0,0} 纪录离食物的间隔char wheregonext(int hx, int hy, int fx, int fy) {// Hx,Hy: 头的位置        // Fx,Fy:食物的位置        char p = 0;        int min = 9999;        int distance[4];        distance[0] = abs(fx - (hx - 1)) + abs(fy - hy);        distance[1] = abs(fx - (hx + 1)) + abs(fy - hy);        distance[2] = abs(fx - hx) + abs(fy - (hy - 1));        distance[3] = abs(fx - hx) + abs(fy - (hy + 1));        // 分别盘算蛇头周边四个位置到食物的间隔。H头的位置,F食物位置        if (distance[0]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )