C语言使用一维数组对贪吃蛇的简单实现

Ciallo!这里是一位即将步入大学的小菜鸡一枚,三个月的假期加上疫情原因延迟开学的我完全受不了了啦,所以不如坐下来好好学习一下大学要学的c语言。(我的专业是物联网啊淦,听说物联网学的东西又多又杂,现在的我很方张 ~ o(* ̄▽ ̄*)o)

        经过几天的努力,终于把c语言的一些基础概念搞清楚了(超级摸的好不好),此时我想起我之前用python写的一个输入字符串-用电脑读出来的一段代码(下一次发?那个贼简单),欸,突然有个编写贪吃蛇的代码想法,不过我决定先用自己的思路来构思一下。

先放一张效果图,最后做出来的效果挺不错,还是保留了一些原本的特性。

目标拆解

        贪吃蛇咋做呢,就用命令提示符窗口来做吧。第一步先实现游戏的地图,第二步实现贪吃蛇的位置、长度和移动,第三步实现贪吃蛇的穿墙或撞墙,第四步实现食物的位置,,第五步实现游戏的胜利和失败。啊,感觉好复杂。

        啊,这位靓仔,实现自己想法那种事情啦,很coooooool的啦,慢慢看下去了啦。(我好机车哦)

第一步 

        先构思一下贪吃蛇的图形。欸,直接用printf打印出来就不用啥外部插件实现图形化了啊,可以用ascii码来表示蛇和食物,空格来表示格子。那么怎么做呢,那就用一个长度为100的数组,然后打印数组每个数且每10格换个行,酱紫10*10的格子就做粗来啦。

        声明一个长度为100的数组,然后给每个元素赋值为32(ascii码32为空格),输出时用%c将数组的元素转换为ascii对应的字符。

int board[100];
memset(board,32,sizeof(board));
for(int i=0;i<100;i++){                 //输出完整网格
        if(i%10==0){
            printf("\n%c  ",board[i]);
        }
        else{
            printf("%c  ",board[i]);
        }
        
    }

        这里用余数==0来表示第10格,那第0格咋办,用 "%c\n" 输出就会变成第一行只有一个,那就用“”“\n%c” 直接在第一个或十一个元素前换行,相当于在本该第二行的第一个前换行。

        但在这里又遇到了一个问题,网格是做出来了,那怎么刷新呢,我苦思冥想,终于,经过百度我想起来了命令提示符cls这个命令 ,这个命令可以清除命令提示符内的所有内容。不断的打印和清楚,就像放动画一样。

        system()函数可以输入cmd命令。

#include<windows.h>
system("cls"); 

        (可以欸,这样甚至可以实现动画欸,超酷的好不好)

第二步

        1、既然用数组来存储了地图,那就在数组里改变元素的值(打印根据数组元素的值打印空格或者字符),这样就和地图一起打印出来了。

        2、那么最难的一步来了,怎么实现贪吃蛇的长度呢,想了半天想到了一个笨方法(自己想的当然没有网上的各种高级方法精妙),那就把蛇身的位置都用另一个数组记录下来,(因为我地图使用的是一维数组,所以蛇身的每一个位置其实就是一个数字,把这个数字存储到另一个数组就ok啦)

//这是数组每一个元素赋值为其下标时打印的结果
0   1   2   3   4   5   6   7   8   9  
10  11  12  13  14  15  16  17  18  19  
20  21  22  23  24  25  26  27  28  29  
30  31  32  33  34  35  36  37  38  39  
40  41  42  43  44  45  46  47  48  49  
50  51  52  53  54  55  56  57  58  59  
60  61  62  63  64  65  66  67  68  69  
70  71  72  73  74  75  76  77  78  79  
80  81  82  83  84  85  86  87  88  89  
90  91  92  93  94  95  96  97  98  99

        比如说,蛇身数组存储了[45,46,47,0,0,....],蛇的长度变量 length 为2  (代码中简写为l,其实可以看成增加的长度),那么蛇头的位置就是47,那么只要在输出地图的时候将45,46,47三个位置的元素的值改变,那么输出地图的时候,这三个位置就是蛇的位置了。

int body[100]={0};            //声明蛇身数组
int l =0 ;                    //这里为了方便对应数组,就将蛇的长度声明为0,数组第一个元素下标为0
for(int i=l;i>=0;i--){        //将蛇身的位置对应到棋盘上
    board[body[i]]=79;        //从下标为l的数组开始,body[i]是蛇头的位置
}                             //board[body[i]]=79就是将地图上蛇的位置的ascii码变为79,就是0

      3、 那么蛇移动的时候怎么办呢。

               a. 首先先获取移动的方向,通过一个if判断键盘按下,否则代码会一直停在这等你按下一个键。

然后获取键盘值,用switch对应键盘值给移动方向变量move赋值。如果输入方向和移动的方向相反则不改变方向。这里可以在代码上方加一句Sleep(500),让代码等待500毫秒,但等待的时候输入的字符仍会被下方代码检测到,这样做出来的贪吃蛇操纵更加流畅。

int move;                       //移动的方向
if(_kbhit()){                   //检测键盘按下
    Fx=_getch();                //获取键盘值
    switch (Fx){
    case 119 : if(move==2){move=2;}else{move=8;};break;    //根据返回值给move赋值,并且不能反方向
     case 115 : if(move==8){move=8;}else{move=2;};break;
     case 97 : if(move==6){move=6;}else{move=4;};break;
     case 100 : if(move==4){move=4;}else{move=6;};break;
     default :break;
  }              
}

                b.然后是蛇头的移动了。 我们把原本是一维的数组通过打印换行的方式实现了二维的表现,那么只要在一维的数据上改变就能实现对二维表现的更改。形象的来说,如果蛇头向上移动了,蛇头的位置就-10,在图上的表现就是蛇头位置55变成了45,向上移动了一格。那么根据刚刚的移动方向变量move移动蛇头的位置place。

switch (move)
        {
        case 8:place -=10;break;
        case 2:place +=10;break;
        case 4:place -=1 ;break;
        case 6:place +=1 ;break;    
        default:
            break;
        }

                c.蛇头移动了,那么蛇身怎么办呢。那就每移动一次,蛇身数组中的元素赋值为后一个元素的值。还是[45,46,47,0,0,...]这个数组,长度 length 为 2 (代码中简写为l) ,这个蛇头向上移动了一格,在地图上就是47这个位置变成了37。那么数组[45,46,47,0,0,....]就这样看,把第二个元素赋值给第一个元素,把第三个元素赋值给第二个元素,最后给第三个元素赋值为37,那么数组就会变为[46,47,37,0,...],(赋值个数由length决定)

int place ;                 //声明place变量为蛇头的位置
body[l]=place;            //将蛇头的位置赋值给蛇身数组的对应位置
for(int i=0;i<l;i++){                   
    body[i]=body[i+1];           
}

        其实这里我并不是很理解,如果将对body[l]的赋值放在for循环后,运行的时候出现很多问题。这样能行就酱紫吧,代码界不是有一句老话:能实现目的的代码就不要动它。(逃避可耻但很有用)。     

        代码以你不懂的方式运行了起来.jpg

第三步

        这一步的实现比较简单。直接4个判断,见下方代码。并且将place变量修正为另一边。

如果要实现碰界结束直接将判断执行  设置一个  胜利失败标识符  ,这个标识符将判断是否失败

if(place<-1){         //向上越界            
    place += 100;
}
else if(place>100){        //向下越界
    place -=100;
}
else if((place+1) %10 ==0 &move==4){   //向左越界
    place += 10;
}
else if(place %10 ==0 &move==6){    //向右越界
    place -=10;
}

第四步

        实现食物的位置,简单的直接将食物的位置在地图上随机,只不过要判断食物的位置不能和蛇重合。代码如下:

board[ppl]=111;         //食物的ascii码                     
if(place==ppl){        //蛇头和食物重合就给蛇长度+1
    l +=1;
    ppl=rand()%100;           //设置食物位置
    for(int i=0;i<l;i++){      //判断食物是否和蛇身位置重合,如果重合则再随机食物位置
        if(ppl==body[i])
        {
        ppl=rand()%100;
        }
    }    
}

第五步

        实现游戏的胜利和失败。简单设置一个胜利失败标识符。

for(int i=1;i<l;i++){
    if(place==body[i-1]){   //只要蛇头位置和蛇身第二位起相同,就判断为失败
        lose=1;
    }
}
        
if(l>99){
            lose=2;        //当长度l达到某值就判断为胜利。
        }

        然后是失败和胜利的结束界面

if(lose){                   //判断是否失败
        printf("you lose\n按R键重新开始,任意键退出");
        int r=_getch();        //获取按键    
        if(r==114){            //r键的按键值为114
            lose=0;            //重现开始,初始化
            int board[100]={0};
            l=0;
        }
        else{
            break;              //否则退出
        }       
    }
    else if(lose==2){
        printf("y=You Win!\n按R键重新开始,任意键退出");
        int r=_getch();
        if(r==114){
            lose=0;                
            int board[100]={0};
            l=0;
        }
        else{
            break;
        }
        
    }

下面放上完整代码,才学不久啊,代码乱别骂俺QAQ。祝各位身体健康,永远不死。

#include<stdio.h>
#include<windows.h>  //Sleep和system函数
#include<string.h>  //memset 函数
#include<conio.h>  //检测键盘函数getch
#include<stdlib.h> //rand函数
int main(){
    int lose=0;                    //判断胜利失败的标识
    int Fx;                         //下面判断方向用的
    int move;                       //移动方向
    int board[100]={0};             //设置地图,实现方法为长度为100的数组
    memset(board,32,sizeof(board));  //初始化地图
    int place=55;                   //初始化位置
    int l=0; //贪吃蛇长度
    int body[100]={0};
    int lengthadd=0;
    int i1;    
    int ppl;
    ppl=rand()%100;
    for(;;){       
    system("cls"); 
    if(lose){                   //判断是否失败
        printf("you lose\n按R键重新开始,任意键退出");
        int r=_getch();
        if(r==114){
            lose=0;
            int board[100]={0};
            l=0;
        }
        else{
            break;
        }       
    }
    else if(lose==2){
        printf("y=You Win!\n按R键重新开始,任意键退出");
        int r=_getch();
        if(r==114){
            lose=0;
            int board[100]={0};
            l=0;
        }
        else{
            break;
        }
        
    }                                           
        for(int i=0;i<100;i++){                 //输出完整地图
        if(i%10==0){
            printf("\n%c  ",board[i]);
        }
        else{
            printf("%c  ",board[i]);
        }
        
    }
    printf("\nyour score:%d\n",l);
                                    //printf("%d",place);
    memset(board,32,sizeof(board));
    Sleep(500);
    if(_kbhit()){                   //检测键盘按下
            Fx=_getch();            
             switch (Fx)
            {
            case 119 : if(move==2){move=2;}else{move=8;};break;    //根据返回值给move赋值,并且不能反方向
            case 115 : if(move==8){move=8;}else{move=2;};break;
            case 97 : if(move==6){move=6;}else{move=4;};break;
            case 100 : if(move==4){move=4;}else{move=6;};break;
            default :break;
            }
        }
    switch (move)
        {
        case 8:place -=10;break;   //通过字符的位置来表示蛇头位置
        case 2:place +=10;break;
        case 4:place -=1 ;break;
        case 6:place +=1 ;break;    
        default:
            break;
        }
        if(place<-1){                                   //实现越过边界时的穿越效果
            place += 100;
        }
        else if(place>100){                                 //每当位置到边界且方向为穿越边界时,位置移动到另一边
            place -=100;
        }
        else if((place+1) %10 ==0 &move==4){
            place += 10;
        }
        else if(place %10 ==0 &move==6){
            place -=10;
        }
        for(int i=1;i<l;i++){
            if(place==body[i-1]){
                lose=1;
            }
        }
        
        body[l]=place;
        for(int i=l;i>=0;i--){                  //将蛇身的位置对应到棋盘上
            board[body[i]]=79;      
        }
        for(int i=0;i<l;i++){                       //用另一个数组存储蛇身的位置
            body[i]=body[i+1];           
        }
        board[ppl]=111; //食物的ascii码                     //设置食物位置
        if(place==ppl){
            l +=1;
            ppl=rand()%100;
            for(int i=0;i<l;i++){
                if(ppl==body[i]){
                    ppl=rand()%100;
                }
            }    
        }
        if(l>99){
            lose=2;
        }
        }
    }
    


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值