字符游戏——智能蛇

来源:互联网 发布:英雄联盟官方代练 知乎 编辑:程序博客网 时间:2024/06/06 09:20

经过了漫长的一学期地学习,一直以来的C语言作业都给我们留下了C似乎只能做数学题这样的一种重要却无趣的功能,这不禁让人有些厌烦。然而,这两周的软件工程导论作业却令我们耳目一新,作业的要求是让我们用C语言完成一个简单的贪吃蛇游戏,并且在此基础上让其“智能”化,即能够自己寻找食物。在我的程序编写过程中,出现了很多令人啼笑皆非的bug,在令人捧腹大笑地同时,也增加了对C语言地兴趣。好了,话不多说,接下来我要介绍一下我的“智能”蛇成长过程。
首先,先贴代码为敬:

#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<math.h>#define WALL_CELL *#define SNAKE_HEAD H#define SNAKE_BODY X#define SNAKE_FOOD $#define SNAKE_MAX_LENGTH 20int snake_index = 4;//当前蛇尾数组下标int fail = 0;//判断是否失败int snake_x[SNAKE_MAX_LENGTH] = {5,4,3,2,1};int snake_y[SNAKE_MAX_LENGTH] = {1,1,1,1,1};int have_food = 0;//判断是否输出食物int distance[4] = {0};char movable[4] = {'W','S','A','D'};int Fx = 0,Fy = 0;char map[12][12] ={    "************",    "*XXXXH     *",    "*          *",    "*          *",    "*          *",    "*          *",    "*          *",    "*          *",    "*          *",    "*          *",    "*          *",    "************"};int getmin(int distance[],char n){    int i = 0,temp = distance[0],j=0;    for(i = 0;i<4;i++)    {        if(temp > distance[i] && movable[i] != n) {            temp = distance[i];            j = i;        }    }    return j;}char getnot_move(){    if( (map[snake_y[0]][snake_x[0] + 1] == 'x' && map[snake_y[0]][snake_x[0] + 1] == '*')) return 'D';    else if( (map[snake_y[0]][snake_x[0] - 1] == 'x' &&  map[snake_y[0]][snake_x[0] - 1] == '*')) return 'A';    else if( (map[snake_y[0]][snake_x[0] + 1] == 'x' && map[snake_y[0]][snake_x[0] + 1] == '*') ) return 'S';    else if( (map[snake_y[0]][snake_x[0] - 1] == 'x' && map[snake_y[0]][snake_x[0] - 1] == '*') ) return 'W';}char wherego(){    int i;        distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx);        distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx);        distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx);        distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx);    char n = getnot_move();    i = getmin(distance,n);    return movable[i];}void movesnake(int sx , int sy)//利用贪吃蛇总是沿着之前的轨迹爬行{    int i,tempx,tempy;    map[snake_y[snake_index]][snake_x[snake_index]] = ' ';    tempx = snake_x[snake_index];    tempy = snake_y[snake_index];//记录新生成的尾巴的位置    for(i = snake_index;i>0;i-- )    {        snake_x[i] = snake_x[i-1];        snake_y[i] = snake_y[i-1];        map[snake_y[i]][snake_x[i]] = 'X';    }    if(sx == 0){        snake_y[0] = snake_y[0] + sy;    }    else snake_x[0] = snake_x[0] + sx;    if(map[snake_y[0]][snake_x[0]] == '$') {        have_food = 0;        snake_index++;        snake_x[snake_index] = tempx;        snake_y[snake_index] = tempy;        //map[snake_y[tempy]][tempx] = 'X';过多导致输出混乱    }    if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1;;    map[snake_y[0]][snake_x[0]] = 'H';}void output(){    int i ,j ;    for( i = 0;i < 12;i++)    {        for(j = 0;j < 12;j++)            printf("%c",map[i][j]);        printf("\n");    }}void put_money(){    int i,j,k;    if(!have_food)    {        srand((int)time(NULL));       for(k = 0;k < 100 ;k++){            i = rand() % 11 + 1;//使输出在框架之内            j = rand() % 11 + 1;            if(map[i][j] == ' ') {                    map[i][j] = '$';                    have_food = 1;                    Fx = j;                    Fy = i;                    break;            }       }    }}void gameover(){    puts("gameover");}int main(){    char ch;    while(1)    {        output();        while(1)        {            put_money();            ch = wherego();            if(ch == 'W') movesnake(0,-1);            else if(ch == 'S') movesnake(0,1);            else if(ch == 'A') movesnake(-1,0);            else if(ch == 'D') movesnake(1,0);            else break;            if(fail){                gameover();                break;            }            output();            if(snake_index == SNAKE_MAX_LENGTH - 1) {                    puts("winning!");                    break;            }        }        break;    }}

这是我看完老师所给的算法后第一感打出的代码(然而错漏百出),由于移动函数方面的判断失误,这条蛇经常把自己咬死了,因而,我对这个代码的移动部分进行了改进。
这里是修改后的移动代码:

int getnot_move(int i){    int dx = 0,dy = 0;    if(i == 0) dy = -1;    else if(i == 1) dy = 1;    else if(i == 2) dx = -1;    else dx = 1;    if(dy){        if(map[snake_y[0] + dy][snake_x[0]] == 'X') return 0;        else if(map[snake_y[0] + dy][snake_x[0]] == '*') return 0;        else return 1;    }    else{        if(map[snake_y[0]][snake_x[0] + dx] == '*') return 0;        else if(map[snake_y[0]][snake_x[0] + dx] == 'X') return 0;        else return 1;    }}char wherego(){    int i;    int count= 4;        distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx);        distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx);        distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx);        distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx);    while(count--){        i = getmin(distance);        if(!getnot_move(i)){            distance[i] = 9999;            i = getmin(distance);        }    }    return movable[i];}

经过修改后的代码,果然不会无缘无故地自己咬死自己啦。

可是:这条蛇却会自己走到死胡同里。。。。。。我再看了一下老师的算法,老师利用贪心的原理,每次都寻找最短的距离,而忽略了这条蛇究竟能不能存活的问题,可以说,这是算法的问题,那么,就只有改变方法了。

方法一:

if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1;

将我的代码里面这条判定死亡的代码删去,蛇就不会死啦!我创作了无敌版贪吃蛇。

当然,下面的方法是更合理的。

方法二:

char map[12][12] ={    "************",    "*XXXXH     *",    "* ******** *",    "* ******** *",    "* ******** *",    "* ******** *",    "* ******** *",    "* ******** *",    "* ******** *",    "* ******** *",    "*          *",    "************"};

只要把地图设置成单行道,那么蛇在限定20的长度以内,就永远不会死啦!

当然,我们应该还有更好地方法:

我们可以设置一条蛇,让它去移动,记录下路径,找出一条不会死的路.

代码呢?

然而博主太懒了,技术又渣,打不出来那么厉害的蛇,所以就没有代码了。。

当然,博主还是对蛇代码进行了一些体验上的改造的,下面贴出代码:

system("cls");

有了这个代码,终于可以好好玩蛇了。

    system("title 贪吃蛇——HaiRG");    system("mode con cols=35 lines=25");    system("color F0");

设定颜色啦、标题啦、大小啦,看起来我觉得更舒适了。

clock_t start,end;start = time(NULL);end   = time(NULL);while(end - start < 4 / snake_index) end = time(NULL);

利用计数器进行延时,并且你会发现蛇越吃越快,这样就增加了少许的难度了。

最后是我完整的代码:

#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<math.h>#define WALL_CELL *#define SNAKE_HEAD H#define SNAKE_BODY X#define SNAKE_FOOD $#define SNAKE_MAX_LENGTH 20int snake_index = 4;//当前蛇尾数组下标int fail = 0;//判断是否失败int snake_x[SNAKE_MAX_LENGTH] = {5,4,3,2,1};int snake_y[SNAKE_MAX_LENGTH] = {1,1,1,1,1};int have_food = 0;//判断是否输出食物int distance[4] = {0};char movable[4] = {'W','S','A','D'};int Fx = 0,Fy = 0;char map[12][12] ={    "************",    "*XXXXH     *",    "* ***  *   *",    "* ***  *   *",    "*          *",    "*  ****    *",    "*          *",    "*  *  **   *",    "*  *       *",    "*  *   **  *",    "*          *",    "************"};int getmin(int distance[]){    int i = 0,temp = distance[0],j=0;    for(i = 0;i<4;i++)    {        if(temp > distance[i] ) {            temp = distance[i];            j = i;        }    }    return j;}int getnot_move(int i){    int dx = 0,dy = 0;    if(i == 0) dy = -1;    else if(i == 1) dy = 1;    else if(i == 2) dx = -1;    else dx = 1;    if(dy){        if(map[snake_y[0] + dy][snake_x[0]] == 'X') return 0;        else if(map[snake_y[0] + dy][snake_x[0]] == '*') return 0;        else return 1;    }    else{        if(map[snake_y[0]][snake_x[0] + dx] == '*') return 0;        else if(map[snake_y[0]][snake_x[0] + dx] == 'X') return 0;        else return 1;    }}char wherego(){    int i;    int count= 4;        distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx);        distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx);        distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx);        distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx);    while(count--){        i = getmin(distance);        if(!getnot_move(i)){            distance[i] = 9999;            i = getmin(distance);        }    }    return movable[i];}void movesnake(int sx , int sy)//利用贪吃蛇总是沿着之前的轨迹爬行{    int i,tempx,tempy;    map[snake_y[snake_index]][snake_x[snake_index]] = ' ';    tempx = snake_x[snake_index];    tempy = snake_y[snake_index];//记录新生成的尾巴的位置    for(i = snake_index;i>0;i-- )    {        snake_x[i] = snake_x[i-1];        snake_y[i] = snake_y[i-1];        map[snake_y[i]][snake_x[i]] = 'X';    }    if(sx == 0){        snake_y[0] = snake_y[0] + sy;    }    else snake_x[0] = snake_x[0] + sx;    if(map[snake_y[0]][snake_x[0]] == '$') {        have_food = 0;        snake_index++;        snake_x[snake_index] = tempx;        snake_y[snake_index] = tempy;        //map[snake_y[tempy]][tempx] = 'X';过多导致输出混乱    }    if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1;    map[snake_y[0]][snake_x[0]] = 'H';}void output(){    int i ,j ;    system("cls");    for( i = 0;i < 12;i++)    {        for(j = 0;j < 12;j++)            printf("%c",map[i][j]);        printf("\n");    }}void put_money(){    int i,j,k;    if(!have_food)    {        srand((int)time(NULL));       for(k = 0;k < 1000 ;k++){            i = rand() % 11 + 1;//使输出在框架之内            j = rand() % 11 + 1;            if(map[i][j] == ' ') {                    map[i][j] = '$';                    have_food = 1;                    Fx = j;                    Fy = i;                    break;            }       }    }}void gameover(){    puts("gameover");}int main(){    char ch;    system("title 贪吃蛇——HaiRG");    system("mode con cols=35 lines=25");    system("color F0");    //clock_t start,end;    while(1)    {        output();        while(1)        {            put_money();            ch = wherego();            start = time(NULL);            end   = time(NULL);            while(end - start < 4 / snake_index) end = time(NULL);            if(ch == 'W') movesnake(0,-1);            else if(ch == 'S') movesnake(0,1);            else if(ch == 'A') movesnake(-1,0);            else if(ch == 'D') movesnake(1,0);            else break;            if(fail){                gameover();                break;            }            output();            if(snake_index == SNAKE_MAX_LENGTH - 1) {                    puts("winning!");                    break;            }        }        break;    }}

附上一些游戏图:
这里写图片描述
这是没设置障碍时的图。
这里写图片描述
很多失败的图我就不发了。。
其实打一条智能蛇的代码还是挺有趣的,你也可以尝试一番。

原创粉丝点击