c语言课程结束小项目:2048小游戏

《C语言程序设计基础》学习完毕,完成第一个项目:2048小游戏。

//思考:编程时,要先想整个框架还是先想每个函数的算法。

//思考:每一个函数要不要传参数(即数组)

//思考:每一个函数之间的联系是什么,谁调用谁…这里很容易搞得头晕,越想越觉得复杂,便不想完成项目了。

 

将游戏分为几个步骤,拆分来完成每一个函数。

一、定义一个4*4的二维数组arr[4][4],初始化为0;

二、打印界面函数:Show_game();将数组打印出来;

三、随机函数:Add_rand():在数组中随机选出一个元素赋值,并且赋值要随机2或者4。所以就要定义i,j两个数组下表变量,将随机值%4,(求4的余数)就会得到0、1、2、3,将随机值赋值给i、j。还需要随机的2和4,可以在定义一个随机数m,m%3,得到0、1、2,在m大于1的情况下将m赋值给数组元素arr[i][j]。

这里的arr[i][j] = (m>1) ?2:4;这句代码,一句解决,厉害厉害是我最开始没有想到的。都是c语言中最简单的语句,但自己在实际编程中用得少,下意识的只会用if语句去判断,导致代码可读性差。

srand((unsigned) time (NULL));//随机种子。Srand需要用到头文<stdlib.h>,

这句用到time()函数,所以需要用到头文件<time.h>

关于srand()函数:

    3.1设置随机的起点

    3.2Void srand(unsigned int seed);

    3.3参数seed,随机生成的种子。

    3.4用法:srand和rand()配合使用产生伪随机数序列。rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数。如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。srand(unsigned seed)通过参数seed改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,从而实现真正意义上的“随机”。通常可以利用系统时间来改变系统的种子值,即srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列

四、游戏初始化函数InitGame():游戏开始第一个随机值要定为2

五、*核心算法*上下左右移动函数:Move_****()

我们这里分析左移(其他移动方法几乎相同)

┏━┳━┳━┳━┓i

┣━╋━╋━╋━┫i

┣━╋━╋━╋━┫i

┣━╋━╋━╋━┫i

┗━┻━┻━┻━┛

 K    J   J   J

左移的结果:是将每行的元素移动到最左边。

将k列设置为当前列,遍历数组时:i++;j++

找到arr[i][j] == 0时,不管

找到arr[i][j]不为0时,分三个情况移动:

  1. arr[i][k] == arr[i][j]时
  2. arr[i][k] == 0时
  3. arr[i][k] != 0 && arr[i][k] != arr[i][j] 又分两种情况

a.j、k挨着

b.j、k不挨着

 

右移同理,将k列的当前放在最右边:

┏━┳━┳━┳━┓i

┣━╋━╋━╋━┫i

┣━╋━╋━╋━┫i

┣━╋━╋━╋━┫i

┗━┻━┻━┻━┛

 J    J   J    K

 

上移动:

┏━┳━┳━┳━┓k

┣━╋━╋━╋━┫j

┣━╋━╋━╋━┫j

┣━╋━╋━╋━┫j

┗━┻━┻━┻━┛

 i    i    i   i       

 

向下移动:

┏━┳━┳━┳━┓j

┣━╋━╋━╋━┫j

┣━╋━╋━╋━┫j

┣━╋━╋━╋━┫k

┗━┻━┻━┻━┛

i     i    i     i   

 

每一种情况都相似,所以函数只是在遍历是将条件略微根据k、j、i修改。

 

六、判断游戏是否结束函数:GameOver(). 游戏结束有两个条件:1.没有一个元素为0  2.没有相邻的元素相等。

条件一:定义一个变量n,初始化为0;写了一个bool函数,遍历每一个元素,如果数组中有一个0元素,n++;判断n的值,若n == 0,返回1,说明条件该成立。(这个写法我一开始没有想到用一个计数器n)。

条件二:同样的方法,定义变量n,判断数组相邻位置是否一样n++。若n == 0则没有相邻位置元素一样,返回1。

最后GameOver函数中判断条件一和二,一&&二,则返回1,表示游戏结束。

(这里我写复杂了,用一个bool函数就可以实现,只需要遍历一次,找出n和m的值,if(n==0 &&m==0),则返回true,表示游戏结束)

七、主函数中,接受键盘字符getchar,用到switch语句写接收到的case

八、用到清屏系统命令system(“cls”),需要加头文件<windows.h>。

九、getchar()getch()是有区别的。它们都是输入单个字符用的。getch()用户不需要按回车,是读取按键值用的,并且需要头文件conio.h。按键输入时,屏幕没有反应。getchar()需要回车,是在输入设备中得到数据用的。按键输入时,屏幕显示输入的字符.

十、上下左右箭头:72 80 75 77.就是数字,不是字符,写成【case 75’: 】就错了。这也导致我开始从键盘怎么也读不上箭头符号。

 

以下源代码:

#include<stdio.h>

#include<time.h>

#include<stdlib.h>

#include<windows.h>

#include<conio.h>

 

 

int arr[4][4] = {0};//游戏抽象为二维数组

 

int if_need_add_rand;//是否生成随机数 1表示生成 0不生成

 

void ShowArr()//和下例的函数功能一样,但是下面例子加了边框,游戏观赏性高

{

       for(int i = 0;i < 4;i++)

       {

              for(int j = 0;j < 4;j++)

              {

                     printf("%5d",arr[i][j]);

              }

              printf("\n\n");

       }

}

void ShowGame()//游戏界面(参考网上,加了边框,真的好看)

{

       printf("\n\n  *****2048*****\n");

       printf("┏━━━┳━━━┳━━━┳━━━┓\n");

       for(int i = 0;i<4;i++)

       {

              printf("┃");

              for(int j = 0;j < 4;j++)

              {

                     //二维数组元素为0

                     if(arr[i][j] == 0)

                     {

                            printf("   ┃");//4个空格

                     }

                     else

                     {

                            printf("%3d┃",arr[i][j]);

                     }

              }

              if(i<3)

              {

                     printf("\n┣━━━╋━━━╋━━━╋━━━┫\n");

              }

              else

              {

                     printf("\n┗━━━┻━━━┻━━━┻━━━┛\n");

                     printf("****WELCOME****\n\n\n");

              }

 

       }

}

 

void Add_rand()//在随机数组中放入一个随机的2或者4,2的概率要大。

{

       srand((unsigned) time (NULL));//随机种子

       int i;

       int j;

       int m = rand() % 3;//m可能的结果为0、1、2。

       while(1)

       {

              i = rand() % 4;

              j = rand() % 4;

              if(arr[i][j] == 0)

              {

                     arr[i][j] = (m>1) ? 4 :2;//m大于1为4,否则为2。这样2的概率为33.3%,4的概率为66.7%

                     break;//生成一个数,则退出

              }

              else

              {

                     continue;//否则执行下一次循环,重新生成随机值。

              }

       }

}

void InitGame()//初始化:游戏开始有两个数字

{

       if_need_add_rand = 1;//需要生成一个随机数

       int i = rand()%4;

       int j = rand()%4;

       arr[i][j] = 2;//第一个数字为2

}

 

void Move_left()//左移动

{

       for(int i = 0;i < 4;i++)

       {

              for(int j = 1,k = 0;j < 4;j++)

              {

                     //先找到k项后面不为0的项

                     if(arr[i][j] > 0)//分3个情况

                     {

                            //1.k项 == j项

                            if(arr[i][k] == arr[i][j])

                            {

                                   arr[i][k++] *= 2;//相当于arr[i][k++] <<= 1这样效率更高

                                   arr[i][j] = 0;

                                   if_need_add_rand = 1;

                            }

                            //2.k项 == 0

                            else if(arr[i][k] == 0)

                            {

                                   arr[i][k] = arr[i][j];

                                   arr[i][j] = 0;

                                   if_need_add_rand = 1;

                            }

                            //3.k项 != 0;j项 != k项

                            else//分2种情况

                            {

                                   arr[i][++k] = arr[i][j];

                                   if(j != k)

                                   {

                                          arr[i][j] = 0;

                                          if_need_add_rand = 1;

                                   }

                                  

                            }

                     }

 

              }

       }

 

}

void Move_right()//右移

{

       for(int i = 0;i < 4;i++)

       {

              for(int j = 2,k = 3;j >= 0;j--)

              {

                     //先找到k项前面不为0的项

                     if(arr[i][j] > 0)//分3个情况

                     {

                            //1.k项 == j项

                            if(arr[i][k] == arr[i][j])

                            {

                                   arr[i][k--] *= 2;//相当于arr[i][k--] <<= 1这样效率更高

                                   arr[i][j] = 0;

                                   if_need_add_rand = 1;

                            }

                            //2.k项 == 0

                            else if(arr[i][k] == 0)

                            {

                                   arr[i][k] = arr[i][j];

                                   arr[i][j] = 0;

                                   if_need_add_rand = 1;

                            }

                            //3.k项 != 0;j项 != k项

                            else//分2种情况

                            {

                                   arr[i][--k] = arr[i][j];

                                   if(j != k)

                                   {

                                          arr[i][j] = 0;

                                          if_need_add_rand = 1;

                                   }

                                  

                            }

                     }

 

              }

       }

 

}

void Move_up()//上移

{

       for(int i = 0;i < 4;i++)//列

       {

              for(int j = 1,k = 0;j < 4;j++)//行。

              {

                     //先找到k项后面不为0的项

                     if(arr[j][i] > 0)//分3个情况

                     {

                            //1.k项 == j项

                            if(arr[k][i] == arr[j][i])

                            {

                                   arr[k++][i] *= 2;

                                   arr[j][i] = 0;

                                   if_need_add_rand = 1;

                            }

                            //2.k项 == 0

                            else if(arr[k][i] == 0)

                            {

                                   arr[k][i] = arr[j][i];

                                   arr[j][i] = 0;

                                   if_need_add_rand = 1;

                            }

                            //3.k项 != 0;j项 != k项

                            else//分2种情况

                            {

                                   arr[++k][i] = arr[j][i];

                                   if(j != k)

                                   {

                                          arr[j][i] = 0;

                                          if_need_add_rand = 1;

                                   }

                                  

                            }

                     }

 

              }

       }

 

}

void Move_down()//下移

{

       for(int i = 0;i < 4;i++)//列

       {

              for(int j = 2,k = 3;j >= 0;j--)//行

              {

                     //先找到k项后面不为0的项

                     if(arr[j][i] > 0)//分3个情况

                     {

                            //1.k项 == j项

                            if(arr[k][i] == arr[j][i])

                            {

                                   arr[k--][i] *= 2;

                                   arr[j][i] = 0;

                                   if_need_add_rand = 1;

                            }

                            //2.k项 == 0

                            else if(arr[k][i] == 0)

                            {

                                   arr[k][i] = arr[j][i];

                                   arr[j][i] = 0;

                                   if_need_add_rand = 1;

                            }

                            //3.k项 != 0;j项 != k项

                            else//分2种情况

                            {

                                   arr[--k][i] = arr[j][i];

                                   if(j != k)

                                   {

                                          arr[j][i] = 0;

                                          if_need_add_rand = 1;

                                   }

                                  

                            }

                     }

 

              }

       }

 

}

bool TiaoJian_1()//游戏结束条件1:没有格子为0,游戏结束,return 1

{

       int n = 0;

       for(int i = 0;i < 4;i++)

       {

              for(int j = 0;j < 4;j++)

              {

                     if(arr[i][j]  == 0)

                     {

                            n++;//有格子为零,游戏继续

                     }

                    

              }

       }

       if( n == 0)//游戏结束

       {

              return true;

       }

       else//游戏继续

       {

              return false;

       }

             

}

bool TiaoJian_2()//2.相邻(上下,左右)的值不相等,则游戏结束,return 1

{

       int n = 0;

       for(int i = 0;i < 4;i++)

       {

              for(int j = 0;j+1 < 4;j++)

              {

                     if((arr[i][j] == arr[i][j+1]) || (arr[j][i] == arr[j+1][i]))

                     {

                            n++;

                     }

              }

       }

       if(n == 0)//表示没有相等,结束

       {

              return 1;

       }

       else

       {

              return 0;

       }

}

bool GameOver()//判断游戏:true表示结束。

{

       if(TiaoJian_1()  && TiaoJian_2())

       {

              return true;

       }

       else

       {

              return false;

       }

      

}

 

 

int main()

{

       InitGame();

       Add_rand();

       ShowGame();

       //ShowArr();

       while(1)

       {

              int ch;

              if_need_add_rand = 0;

              switch(ch = getch())//接收字符函数

              {

                  case 'a':

                  case 'A':

                     case '4':

                  case 75:

                            Move_left();

                         break;

                     case 'd':

                     case'D':

                     case '6':

                     case 77:

                            Move_right();

                            break;

                     case'w':

                     case 'W':

                     case '8':

                     case 72:

                            Move_up();

                            break;

                     case 's':

                     case 'S':

                     case'2':

                     case 80:

                            Move_down();

                            break;

                     default:

                            break;

              }

 

              if(if_need_add_rand == 1)

              {

                    

                     Add_rand();

                     system("cls");//清屏系统命令

                     ShowGame();

                     //ShowArr();

              }

              if(GameOver())

              {

                     printf("    ***游戏结束***\n");

                     break;

              }

             

       }

}

 

猜你喜欢

转载自blog.csdn.net/zDavid_2018/article/details/81265696
今日推荐