贪吃蛇的升级——智能蛇

来源:互联网 发布:mac启动windows 编辑:程序博客网 时间:2024/06/13 10:13

智能蛇

在上一篇博客当中,已经粗略完成一个小小的“贪吃蛇”的程序框架,接下来我们来看一下如何实现更高级的玩法–不需要控制,让蛇自己去吃!

实验环境的准备

其实在上一篇博客中的使用颜色选择时已经在Ubuntu系统下使用了VT-100控制码。
这个实验我选择在Ubuntu下的Code::Blocks完成

非阻塞地检测键盘输入的方法

在之前的游戏中,为了输入命令后不需要回车,并且使输入的命令不显示
Windows下使用的是conio.h中的getch()函数
Ubuntu下使用的是

        system("stty -icanon");        system("stty -echo");        input=getchar();        system("stty icanon");        system("stty echo");

而今天我们在Ubuntu下使用更高级的kbhit()函数来解决这个问题

#include <stdio.h>#include <time.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <termios.h>#include <unistd.h>#define SNAKE_MAX_LENGTH 20#define SNAKE_HEAD 'H'#define SNAKE_BODY 'X'#define BLANK_CELL ' '#define SNAKE_FOOD '$'#define WALL_CELL '*'#define BLOCKS '#'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 snakeLength=5;int tempX=0;int tempY=0;int color=0;int score=0;static struct termios ori_attr, cur_attr;static __inlineint 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'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;}void color_choose(void){    printf("Please choose color (Input 1~5):\n");    printf("\033[30m(1)Black  \033[31m(2)Red  \033[32m(3)Green  \033[33m(4)Yellow  \033[34m(5)Blue\033[0m\n");    scanf("%d",&color);    system("clear");}void set_blocks(void){    int number=0;    int x = 0;    int y = 0;    int turn=0;    srand((unsigned)time(NULL));    printf("How many blocks do you want to set:(range from 0 to 5)\n");    scanf("%d",&number);    while(turn<number)    {        x=rand()%10+1;        y=rand()%10+1;        if(map[x][y]==BLANK_CELL)        {            map[x][y]=BLOCKS;            turn++;        }    }}void snakeMove(int dx,int dy){    int turn=0;    tempX=snakeX[snakeLength-1];    tempY=snakeY[snakeLength-1];    int tempX1=0;    int tempY1=0;    if(map[snakeY[snakeLength-1]+dy][snakeX[snakeLength-1]+dx]==BLOCKS)//当蛇头面前是blocks时无法前进    {        return;    }    snakeY[snakeLength-1]+=dy;    snakeX[snakeLength-1]+=dx;    for(turn=snakeLength-2;turn>=0;turn--)    {        tempX1=snakeX[turn];        tempY1=snakeY[turn];        snakeX[turn]=tempX;        snakeY[turn]=tempY;        tempX=tempX1;        tempY=tempY1;    }}void put_money(void){    int x = 0;    int y = 0;    srand((unsigned)time(NULL));    while(map[x][y]!=BLANK_CELL)    {        x=rand()%10+1;        y=rand()%10+1;    }    map[x][y]=SNAKE_FOOD;}void eat_food(void){    int turn = 0;    if(map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]==SNAKE_FOOD)    {        snakeLength++;        score+=100;        if(snakeLength>20)        {            return;        }        for(turn=snakeLength-1;turn>0;turn--)        {            snakeX[turn]=snakeX[turn-1];            snakeY[turn]=snakeY[turn-1];        }        snakeX[turn]=tempX;        snakeY[turn]=tempY;        put_money();    }}void output(void){    int turnx=0;    int turny=0;    for(turnx=1;turnx<11;turnx++)    {        for(turny=1;turny<11;turny++)        {            if(map[turnx][turny]!=SNAKE_FOOD&&map[turnx][turny]!=BLOCKS)            {                map[turnx][turny]=BLANK_CELL;            }        }    }    for(turnx=0,turny=0;turnx<snakeLength;turnx++,turny++)    {        if(map[snakeY[turny]][snakeX[turnx]]!=SNAKE_FOOD)        {            map[snakeY[turny]][snakeX[turnx]]=SNAKE_BODY;        }    }    map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]=SNAKE_HEAD;    system("clear");    for(turnx=0;turnx<12;turnx++)    {        for(turny=0;turny<12;turny++)        {            printf("\033[?25l \033[%dm %c",29+color,map[turnx][turny]);        }        printf("\n");    }    printf("Score:%d\n",score);}int gameover(void){    int turn = 0;    if(map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]==WALL_CELL)    {        printf("Game Over!!!");        return 0;    }    if(snakeLength>SNAKE_MAX_LENGTH)    {        printf("Game Over!!!");        return 0;    }    for(turn=snakeLength-2;turn>=0;turn--)    {        if(snakeX[turn]==snakeX[snakeLength-1]&&snakeY[turn]==snakeY[snakeLength-1])        {            printf("Game Over!!!");            return 0;        }    }    return 1;}//将你的 snake 代码放在这里int main(){        char input;        //设置终端进入非缓冲状态        int tty_set_flag;        tty_set_flag = tty_set();        color_choose();        set_blocks();        put_money();        output();        //将你的 snake 代码放在这里        printf("pressed `q` to quit!\n");        while(1) {                if( kbhit() )                {                        input = getchar();                        switch(input)                        {                            case'A':snakeMove(-1,0);break;                            case'D':snakeMove(1,0);break;                            case'W':snakeMove(0,-1);break;                            case'S':snakeMove(0,1);break;                            case'q':return 0;                            default:break;                        }                }                else                {                    continue;                }                eat_food();                if(gameover()!=0)                {                    output();                    continue;                }                else                {                    break;                }        }        //恢复终端设置        if(tty_set_flag == 0)                tty_reset();        return 0;}

智能蛇

好了,接下来就开始正式开始我们的智能蛇的编写
首先根据
决定蛇行走的方向函数的伪代码

     // Hx,Hy: 头的位置    // Fx,Fy:食物的位置    function whereGoNext(Hx,Hy,Fx,Fy) {    // 用数组movable[3]={“a”,”d”,”w”,”s”} 记录可走的方向    // 用数组distance[3]={0,0,0,0} 记录离食物的距离    // 分别计算蛇头周边四个位置到食物的距离。H头的位置,F食物位置    //     例如:假设输入”a” 则distance[0] = |Fx – (Hx-1)| + |Fy – Hy|    //           如果 Hx-1,Hy 位置不是Blank,则 distance[0] = 9999    // 选择distance中存最小距离的下标p,注意最小距离不能是9999    // 返回 movable[p]

这是我写的Autorun函数

void Autorun(void){    int add=0;    int turn=0;    int nowx=snakeX[snakeLength-1];    int nowy=snakeY[snakeLength-1];    if(map[nowy-1][nowx]==WALL_CELL||map[nowy-1][nowx]==BLOCKS||map[nowy-1][nowx]==SNAKE_BODY)    {        distance[0]=9999;    }    else    {        distance[0]=abs(nowy-1-Moneyx)+abs(nowx-Moneyy);    }    if(map[nowy][nowx-1]==WALL_CELL||map[nowy][nowx-1]==BLOCKS||map[nowy][nowx-1]==SNAKE_BODY)    {        distance[1]=9999;    }    else    {        distance[1]=abs(nowy-Moneyx)+abs(nowx-Moneyy-1);    }    if(map[nowy+1][nowx]==WALL_CELL||map[nowy+1][nowx]==BLOCKS||map[nowy+1][nowx]==SNAKE_BODY)    {        distance[2]=9999;    }    else    {        distance[2]=abs(nowy-Moneyx+1)+abs(nowx-Moneyy);    }    if(map[nowy][nowx+1]==WALL_CELL||map[nowy][nowx+1]==BLOCKS||map[nowy][nowx+1]==SNAKE_BODY)    {        distance[3]=9999;    }    else    {        distance[3]=abs(nowy-Moneyx)+abs(nowx-Moneyy+1);    }    for(turn=0;turn<3;turn++)    {        if(distance[turn]>distance[turn+1])        {            add=0;        }        else        {            distance[turn+1]=distance[turn];            add++;        }    }    if(distance[3]==9999)    {        return;    }    switch((3-add))    {        case 0:snakeMove(0,-1);break;        case 1:snakeMove(-1,0);break;        case 2:snakeMove(0,1);break;        case 3:snakeMove(1,0);break;        default:break;    }}

但是由于算法太过简陋、粗暴,经常自己走向死局,所以以后还会慢慢改进。
这是本次“智能蛇”的完整代码

#include <stdio.h>#include <time.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <termios.h>#include <unistd.h>#define SNAKE_MAX_LENGTH 100#define SNAKE_HEAD 'H'#define SNAKE_BODY 'X'#define BLANK_CELL ' '#define SNAKE_FOOD '$'#define WALL_CELL '*'#define BLOCKS '#'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 snakeLength=5;int tempX=0;int tempY=0;int color=0;int score=0;int Moneyx=0;int Moneyy=0;int distance[4]={0};static struct termios ori_attr, cur_attr;static __inlineint 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'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;}void color_choose(void){    printf("Please choose color (Input 1~5):\n");    printf("\033[30m(1)Black  \033[31m(2)Red  \033[32m(3)Green  \033[33m(4)Yellow  \033[34m(5)Blue\033[0m\n");    scanf("%d",&color);    system("clear");}void set_blocks(void){    int number=0;    int x = 0;    int y = 0;    int turn=0;    srand((unsigned)time(NULL));    printf("How many blocks do you want to set:(range from 0 to 15)\n");    scanf("%d",&number);    while(turn<number)    {        x=rand()%10+1;        y=rand()%10+1;        if(map[x][y]==BLANK_CELL)        {            map[x][y]=BLOCKS;            turn++;        }    }}void snakeMove(int dx,int dy){    int turn=0;    tempX=snakeX[snakeLength-1];    tempY=snakeY[snakeLength-1];    int tempX1=0;    int tempY1=0;    if(map[snakeY[snakeLength-1]+dy][snakeX[snakeLength-1]+dx]==BLOCKS)//当蛇头面前是blocks时无法前进    {        return;    }    snakeY[snakeLength-1]+=dy;    snakeX[snakeLength-1]+=dx;    for(turn=snakeLength-2;turn>=0;turn--)    {        tempX1=snakeX[turn];        tempY1=snakeY[turn];        snakeX[turn]=tempX;        snakeY[turn]=tempY;        tempX=tempX1;        tempY=tempY1;    }}void put_money(void){    Moneyx = 0;    Moneyy = 0;    srand((unsigned)time(NULL));    while(map[Moneyx][Moneyy]!=BLANK_CELL)    {        Moneyx=rand()%10+1;        Moneyy=rand()%10+1;    }    map[Moneyx][Moneyy]=SNAKE_FOOD;}void eat_food(void){    int turn = 0;    if(map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]==SNAKE_FOOD)    {        snakeLength++;        score+=100;        if(snakeLength>20)        {            return;        }        for(turn=snakeLength-1;turn>0;turn--)        {            snakeX[turn]=snakeX[turn-1];            snakeY[turn]=snakeY[turn-1];        }        snakeX[turn]=tempX;        snakeY[turn]=tempY;        put_money();    }}void output(void){    int turnx=0;    int turny=0;    for(turnx=1;turnx<11;turnx++)    {        for(turny=1;turny<11;turny++)        {            if(map[turnx][turny]!=SNAKE_FOOD&&map[turnx][turny]!=BLOCKS)            {                map[turnx][turny]=BLANK_CELL;            }        }    }    for(turnx=0,turny=0;turnx<snakeLength;turnx++,turny++)    {        if(map[snakeY[turny]][snakeX[turnx]]!=SNAKE_FOOD)        {            map[snakeY[turny]][snakeX[turnx]]=SNAKE_BODY;        }    }    map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]=SNAKE_HEAD;    system("clear");    for(turnx=0;turnx<12;turnx++)    {        for(turny=0;turny<12;turny++)        {            printf("\033[?25l \033[%dm %c",29+color,map[turnx][turny]);        }        printf("\n");    }    printf("Score:%d\n",score);}void Autorun(void){    int add=0;    int turn=0;    int nowx=snakeX[snakeLength-1];    int nowy=snakeY[snakeLength-1];    if(map[nowy-1][nowx]==WALL_CELL||map[nowy-1][nowx]==BLOCKS||map[nowy-1][nowx]==SNAKE_BODY)    {        distance[0]=9999;    }    else    {        distance[0]=abs(nowy-1-Moneyx)+abs(nowx-Moneyy);    }    if(map[nowy][nowx-1]==WALL_CELL||map[nowy][nowx-1]==BLOCKS||map[nowy][nowx-1]==SNAKE_BODY)    {        distance[1]=9999;    }    else    {        distance[1]=abs(nowy-Moneyx)+abs(nowx-Moneyy-1);    }    if(map[nowy+1][nowx]==WALL_CELL||map[nowy+1][nowx]==BLOCKS||map[nowy+1][nowx]==SNAKE_BODY)    {        distance[2]=9999;    }    else    {        distance[2]=abs(nowy-Moneyx+1)+abs(nowx-Moneyy);    }    if(map[nowy][nowx+1]==WALL_CELL||map[nowy][nowx+1]==BLOCKS||map[nowy][nowx+1]==SNAKE_BODY)    {        distance[3]=9999;    }    else    {        distance[3]=abs(nowy-Moneyx)+abs(nowx-Moneyy+1);    }    for(turn=0;turn<3;turn++)    {        if(distance[turn]>distance[turn+1])        {            add=0;        }        else        {            distance[turn+1]=distance[turn];            add++;        }    }    if(distance[3]==9999)    {        return;    }    switch((3-add))    {        case 0:snakeMove(0,-1);break;        case 1:snakeMove(-1,0);break;        case 2:snakeMove(0,1);break;        case 3:snakeMove(1,0);break;        default:break;    }}int gameover(void){    int turn = 0;    if(map[snakeY[snakeLength-1]][snakeX[snakeLength-1]]==WALL_CELL)    {        printf("Game Over!!!");        return 0;    }    if(distance[3]==9999)    {        printf("Game Over!!!");        return 0;    }    for(turn=snakeLength-2;turn>=0;turn--)    {        if(snakeX[turn]==snakeX[snakeLength-1]&&snakeY[turn]==snakeY[snakeLength-1])        {            printf("Game Over!!!");            return 0;        }    }    return 1;}//将你的 snake 代码放在这里int main(){        char input;        unsigned int timE=1000000;        //设置终端进入非缓冲状态        int tty_set_flag;        tty_set_flag = tty_set();        color_choose();        set_blocks();        put_money();        output();        //将你的 snake 代码放在这里        printf("pressed `Q` to quit!\n");        printf("pressed `F` to accelerate!\n");        printf("pressed `L` to decelerate!\n");        while(1) {                if( kbhit() )                {                        input = getchar();                        switch(input)                        {                            case'A':snakeMove(-1,0);break;                            case'D':snakeMove(1,0);break;                            case'W':snakeMove(0,-1);break;                            case'S':snakeMove(0,1);break;                            case'F':timE-=200000;break;                            case'L':timE+=200000;break;                            case'Q':return 0;                            default:break;                        }                }                else                {                    Autorun();                    usleep(timE);                }                eat_food();                if(gameover()!=0)                {                    output();                    continue;                }                else                {                    break;                }        }        //恢复终端设置        if(tty_set_flag == 0)                tty_reset();        return 0;}

End

虽然编写贪吃蛇和智能蛇花费了不少的时间,但是那种专心于当中的感觉真的很好,对程序设计、对软导课的兴趣也在不断增加!!!!

阅读全文
'); })();
1 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 怀孕以后 不孕病 怀不了孕怎么办 不孕证 女人不孕不育的症状有哪些 女人不孕不育的原因 女人不育不孕症状 妇科不孕检查项目 导致不孕不育的原因有哪些 男性检查不孕不育挂什么科 什么叫不孕不育 男性不孕的原因 男人检查不孕不育挂什么科 男人不育的症状有哪些 女人不孕 男的不能生育 不育不孕怎么办 不会怀孕的女人有什么特征 男人不孕不育都因为什么 不育是什么意思 女生不孕不育的原因 先天性不孕不育 男人不孕表现 男的不孕查什么 不孕去医院挂什么科 男人查不孕不育挂什么科 什么情况不孕不育 造成不孕的原因有哪些 不孕不育的征兆 导致不孕的因素有哪些 不孕不育挂什么科室 检查是否不孕挂什么科 男性不孕不育的症状有哪些 男性不孕不育挂哪个科室 不孕不育抗体检查 男性不孕不育表现 不孕不育抗体 女性不孕医院哪里好 女性不孕的常用检查 不孕不育那个医院好 女人不孕不育怎么办