C++ 简单贪吃蛇

大家好,我是YQ。首先上一张图C++ 简单贪吃蛇
然后上菜单图

C++ 简单贪吃蛇

使用的数据结构和算法

main

void init(string &,int,int);
void set_level();
void view_score();
void create_new_game();
int show_menu();
int main()
{
    int choice;
    void (*farray[])(void)={set_level,view_score,create_new_game};
    for(;;)
    {
     choice=show_menu();
     if(choice>=1 && choice<=3)
     farray[choice-1]();
     else if (choice==4) break;
 }
 return 0;
} 

一定要自己定义set_level(),view_score()等函数,main()函数中主要运用了函数指针来缩短代码。其中忽略了必要的#include头文件和using指示(如 using namespace std;),请自行补充。

create_new_game是怎么让游戏运行起来的

我的想法是有
两个线性表

一个字符串
()
定义第一个线性表的代码片段如下:

int coord[sz][2]={{cols/2,lines/2}},length=1,
 fd[]={1+rand()%cols,1+rand()%lines};

也就是一个维数为2的一维的整型数组,length即蛇身的长度,fd[]存储食物的坐标,sz是自己定义的一个常量:

const int cols=60,lines=20,sz=cols*lines;

其中的cols和lines是很重要的常量,它们代表输出字符的行数和列数,即字符组成的一个长方形的长和宽,包括有空格(spac),回车(carriage return)和其他的字符,如蛇身(’*’),蛇的食物(’$’),设置边界(’#’),都可以自己可以定义,如下例:

const char spac=' ',snk_body='*',snk_fd='$';

等等……
()
定义第二个线性表的代码片段如下:

char dir[]={east};

即存储每一个蛇身元素下一瞬的方向的一个表,存储的顺序是由蛇身到蛇尾,
数组下标依次为为0~length-1。
其中的east是枚举常量,如下:

enum {x,head=0,y,east='d',south='s',west='a',north='w',exit='q',pause='p'
 };

x,head=0,y这些仅仅是为了之后写代码时阅读方便,其中的x==0,head到y的值递增1,实例片段如下:

 case east:{
      dir[head]=east;
      ++coord[head][x];
      if(coord[head][x]==cols) coord[head][x]=1;
      break;
      }

这是键盘按下后的一个执行片段。
(三)
存储需打印的元素的一个字符串,大家应该都注意到了,
前面两个表很容易模拟蛇身的移动和坐标、方向的改变,但无法直接打印出来,这时需要有一个方便的适合打印的东西出现。
直接用标准库里的string类就得了(在C++ Primer 第4版·特别版中有详细介绍,或查阅MSDN )
MSDN里string class的链接:](https://docs.microsoft.com/en-us/dotnet/api/system.string?redirectedfrom=MSDN&view=netframework-4.7.2)
代码片段如下:

 string s;
 init(s,cols,lines);

事实上,函数init(s,cols,lines)更有用,你总得设置一些c_return和bound吧,
但我不贴出这个函数的代码,因为我内部实现我写错了,导致整个游戏运行的不好,只能吃一个球,有时候还吃不到。
你还得定义一个整型,存储游戏时的分数,如下:

 int score;

输出是整个程序中最简单的一句:

 print: 
  cout<<s<<setfill('0')<<setw(4)<<score<<endl;

(记得包含适当的头文件)其中的print是goto语句的标号,我在处理完蛇(包括Check,Sports和粘贴Paste三个过程)后从while语句的末尾用goto调到程序开始输出的地方,比较方便。
其中Check检查是否吃到食物是否死亡,检查死亡很方便,判断蛇的下一步是不是吃到蛇身就行了,没必要遍历蛇身元素,可以用到()中数据结构的特性方便实现。
Sports把除蛇头之外的元素的方向(存储在dir中,见())依次赋值为它的前一个元素的dir值,
即蛇向前移动,然后根据不同的方向按不同方式增减坐标,如下所示:

 /*Start sports*/
   for(int i=length-1;i!=0;--i)
   dir[i]=dir[i-1];
   for(int j=0;j!=length;++j)
   switch(dir[j])
   {
    case east:++coord[head][x];break;
    case south:++coord[head][y];break;
    case west:--coord[head][x];break;
    case north:--coord[head][y];break;
    default:;break;
   }
   
   /*Finished sports*/

其中/**/之间的内容为注释,在编译时会忽略,不增加运行时文件的大小,在C++ Primer中也有讲到,博主就是看这本书细致地学习了C++的。

到这里完了。
再添一张游戏时的图:

C++ 简单贪吃蛇
本来应该蛇身长度+1的,并且赋有正确的方向和坐标,却只是加了分,果然程序中有错误。