字符游戏——智能蛇

经过了漫长的一学期地学习,一直以来的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 20
int 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 20
int 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;
    }
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值