c语言学习之小游戏2048

来源:互联网 发布:淘宝怎么抢购秒杀 编辑:程序博客网 时间:2024/06/05 17:01

2048是一个很经典的游戏,记得当时我身边有个小伙伴很沉迷这个,也觉得这个游戏很厉害,于是今天就编写了下一个无图形界面的。

2048游戏在我看来需要有以下几点:

    ①随机数:对于计算机发生随机数函数rand()是并不是一个真正的随机数,它是由计算机产生的一系列伪随机数,就是当我们运行这个函数的时候需要每次获得的结构都是一样的,我不希望编写游戏编写出来每一次结果都一样,我查阅了资料,发现随机数只要给一个随机数的种子(用来初始化第一个随机数),后面的结果就会随着初始值得改变而改变,虽然还这不是真正的随机数,但是只要做到了每一运行结果不相同我觉得也差不多可以算是随机数了,符合我的要求,所以准备用时间来初始化这个随机数,这样就达到每次结果不一样了。

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

    ②获取键盘:我需要知道当我游戏开始时我怎么获取玩家按下了哪个键,上网搜索发现原来我们每一个键都对应两个两个数值,按下产生一个数值,松开产生另外一个数值,我创建了一个char 类型的变量来接收按下的数值然后根据已知的数值比较这样就可以知道是哪个键了(感谢这篇博文的博主http://home.51.com/xjq12311/diary/item/10048503.html)

    解决了上面几个技术上的难题,于是我开始入手写,首先创建一个二维数组并且初始化为0。代码如下:

        int **cheil = (int **)malloc(sizeof(int*)* 5);  //动态开辟二维数组存放数据for (i = 0; i < 5; i++){cheil[i] = (int *)calloc(4, sizeof(int));}

然后利用随机数产生对应的坐标,并且判断是否该位置是否存在数值,若已存在就让位置++到下一个位置,如果位置全部被占满则返回0,否则返回1.代码如下:

//随机数int Rand(int n)  {return (rand() % n);}//1/5的几率是4,4/5的几率是2int Rand2or4()  { if (Rand(5) == 1){return 4;} else {return 2; }}//产生随机位置并写入int SandSeat(int **n)  {    int x1;    int y1;    int x2;    int y2;    x1 = Rand(4);    y1 = Rand(4);    x2 = x1;    y2 = y1;    while (1)    {        if (n[x1][y1] == 0)        {            break;        }        else        {            y1++;            if (y1 > 3)            {                y1 %= 4;                x1++;            }            if(x1 > 3)            {                x1 %= 4;            }            if (x1 == x2&&y1 == y2)            {                return 0;            }        }    }        n[x1][y1] = Rand2or4();    return 1;}

下面就是向右移动,根据游戏规则我们知道如果向右移动首先会把相同的数值加起来然后移动到最右边,我打算设置一个标记变量来记录是否移动或相加。代码如下:

int MoveRight(int **n){int i;int j;int k;int flg=0;  //标记变量for (i = 0; i < 4; i++)    //4行{for (j = 0; j < 3; j++)   //发现相邻数字相同或者相隔的数字只有0就相加并把后面数字置0;{for (k = j+1; k<4&&n[i][k]==0; k++){;}if (k<4 && n[i][j] == n[i][k]){n[i][j] += n[i][k];n[i][k] = 0;flg = 1;}}for (j = 0; j < 4; j++)   //发现有0向左移动,由于是向右移动,所以从左边一个一个移动{if (n[i][j] == 0){for (k = j; k > 0; k--){if (n[i][k - 1] != 0)  //判断前面是否为0{Swap(n[i][k], n[i][k - 1]);  //交换函数flg = 1;}}}}}return flg;}

同理写出向上、下、左移动。

然后我们需要一个判断数组相邻是否相等,相等返回1,因为在2048游戏中结束的条件是全部被占满并且相邻没有相等的值,代码如下:

//判断是否有相同int Noun(int **n){    int i;    int j;    for (i = 0; i <4; i++)    {        for (j = 0; j < 4; j++)        {            if (n[i + 1][j] == n[i][j] || n[i][j] == n[i][j + 1] || n[i][j] == 0)            {                return 1;            }        }    }    return 0;}

最后就是输出一下数组就可以了

在主函数中我打算首先获取是否有相等的值,并找一个变量记录,然后调用对应的移动函数,通过移动函数返回来判断是否发生移动或者相加,如果没有发生就停止本次循环,

如果发生移动就调用随机写入函数写入并记录返回值i,最后再以判断是否有相同函数返回值flg2,如果两个返回值不同时为零说明游戏还没有死亡,继续循环,

最终代码如下:

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <stdlib.h>#include<conio.h>//随机数int Rand(int n)  {return (rand() % n);}//1/5的几率是4,4/5的几率是2int Rand2or4()  { if (Rand(5) == 1){return 4;} else {return 2; }}//输出数组void Show(int **n)    {int i;int j;for (i = 0; i < 4; i++){for (j = 0; j < 4; j++){printf("%4d ", n[i][j]);}printf("\n");}}//产生随机位置并写入int SandSeat(int **n)  {int x1;int y1;int x2;int y2;x1 = Rand(4);y1 = Rand(4);x2 = x1;y2 = y1;while (1){if (n[x1][y1] == 0){break;}else{y1++;if (y1 > 3){y1 %= 4;x1++;}if(x1 > 3){x1 %= 4;}if (x1 == x2&&y1 == y2){return 0;}}}n[x1][y1] = Rand2or4();return 1;}//交换函数void Swap(int &a, int &b){int temp = a;a = b;b = temp;}//右移int MoveRight(int **n){int i;int j;int k;int flg=0;for (i = 0; i < 4; i++){for (j = 0; j < 3; j++)   //发现相邻数字相同或者相隔的数字只有0就相加并把后面数字置0;{for (k = j+1; k<4&&n[i][k]==0; k++){;}if (k<4 && n[i][j] == n[i][k]){n[i][j] += n[i][k];n[i][k] = 0;flg = 1;}}for (j = 0; j < 4; j++)   //发现有0向左移动{if (n[i][j] == 0){for (k = j; k > 0; k--){if (n[i][k - 1] != 0){Swap(n[i][k], n[i][k - 1]);flg = 1;}}}}}return flg;}//左移int MoveLeft(int **n){int i;int j;int k;int flg = 0;for (i = 0; i < 4; i++){for (j = 3; j > 0; j--)   //发现相邻数字相同或者相隔的数字只有0就相加并把前面数字置0;{for (k = j - 1; k>=0 && n[i][k] == 0; k--){;}if (k >= 0 && n[i][j] == n[i][k]){n[i][j] += n[i][k];n[i][k] = 0;flg = 1;}}for (j = 3; j >= 0; j--)   //发现有0向右移动{if (n[i][j] == 0){for (k = j; k < 3; k++){if (n[i][k + 1] != 0){Swap(n[i][k], n[i][k + 1]);flg = 1;}}}}}return flg;}//上移int MoveUp(int **n){int i;int j;int k;int flg = 0;for (j = 0; j < 4; j++){for (i = 0; i < 3; i++)   //发现相邻数字相同或者相隔的数字只有0就相加并把下面数字置0;{for (k = i + 1; k<4 && n[k][j] == 0; k++){;}if (k<4 && n[i][j] == n[k][j]){n[i][j] += n[k][j];n[k][j] = 0;flg = 1;}}for (i = 3; i >= 0; i--)   //发现有0向下移动{if (n[i][j] == 0){for (k = i; k < 3; k++){if (n[k+1][j] != 0){Swap(n[k][j], n[k + 1][j]);flg = 1;}}}}}return flg;}//下移int MoveDn(int **n){int i;int j;int k;int flg = 0;for (j = 0; j < 4; j++){for (i = 3; i > 0; i--)   //发现相邻数字相同或者相隔的数字只有0就相加并把上面数字置0;{for (k = i - 1; k>=0 && n[k][j] == 0; k--){;}if (k >= 0 && n[i][j] == n[k][j]){n[i][j] += n[k][j];n[k][j] = 0;flg = 1;}}for (i = 0; i < 4; i++)   //发现有0向上移动{if (n[i][j] == 0){for (k = i; k > 0; k--){if (n[k-1][j] != 0){Swap(n[k][j], n[k - 1][j]);flg = 1;}}}}}return flg;}//判断是否有相同int Noun(int **n){int i;int j;for (i = 0; i <4; i++){for (j = 0; j < 4; j++){if (n[i + 1][j] == n[i][j] || n[i][j] == n[i][j + 1] || n[i][j] == 0){return 1;}}}return 0;}int main(){int key;   //获取按键int i;int flg = 1;  //移动的标记int flg2 = 1; //判断相邻的标记srand((unsigned)time(NULL));  //随机种子int **cheil = (int **)malloc(sizeof(int*)* 5);  //动态开辟二维数组存放数据for (i = 0; i < 5; i++){cheil[i] = (int *)calloc(4, sizeof(int));  //初始化}SandSeat(cheil);SandSeat(cheil);while (i||flg2){i = 0;  //判断写入的标记system("cls");Show(cheil);flg2 = Noun(cheil);  //判断相邻是否有相等或有0key = getch();if (key == 27) break;  //Esc键if (key == 72){flg=MoveUp(cheil);if (flg == 0)   //判断发生移动{continue;}i=SandSeat(cheil);}if (key == 80){flg = MoveDn(cheil);if (flg == 0){continue;}i = SandSeat(cheil);}if (key == 75){flg = MoveLeft(cheil);if (flg == 0){continue;}i = SandSeat(cheil);}if (key == 77){flg = MoveRight(cheil);if (flg == 0){continue;}i = SandSeat(cheil);}flg2 = Noun(cheil);}return 0;}

最后发现根本不需要写入的返回值,因为在判断是否有相等的函数中我也判断了是否有空值的情况,这个是我思考不全面,只需要简单的修改就可以了,如果你有兴趣可以尝试修改下或者给我留言。因为还不会运用图形库所以暂时就是这个版本,等学会运用图形库我再来修改补充,做出一个有界面的2048.



原创粉丝点击