2048小游戏(变态版哦)

简介: 2048小游戏(变态版哦)

近日,由于博主同学暑假有个作业是写个2048小游戏,我一听挺好玩的。。然后就开始了。。


首先,2048在移动过程中的规则其实也没有特别难,但是感觉也不是一句话就能说完的。(不过玩的多……感觉总是有的)


废话不多说,其实博主同学提供了pdf描述了2048的算法。

20160725084338215.png

各位筒子入坑前请先过几眼这个规则,以及其算法(当然我觉得算法第二点有点问题,后述)


那么在游戏的编写前,可以先对细枝末节做一些准备。

1.出现数字2/4的概率

int getRand()
{
    int i = rand() % 10;
    if (i < 1)
        return 4;
    else
        return 2;
}

2.移动后新数字产生的位置(当然也是随机数了)

int getRandAddr()//返回一个0-15的数
{
    return rand() % 16;
}
bool isSafeAddr(int addr)//由上一个函数产生的位置不一定安全,判断一下
{
    if (a[addr / 4][addr % 4] == 0)//当这个位置是0,也就是空才安全
        return true;
    return false;//都没安全当然不安全拉
}

3.判断2048游戏是否结束(就是你game over拉)

bool isEnd()
{
    for (int i = 0; i < 4; i++)//第一步,只要有空位,那就还没输
    {
        for (int j = 0; j < 4; j++)
        {
            if (a[i][j] == 0)
                return false;
        }
    }
    //第二步,当你满了之后,要判断上下左右相邻的是否还能合并
    for (int i = 0; i < 4; i++)//行
    {
        for (int j = 0; j < 3; j++)
        {
            if (a[i][j] == a[i][j + 1])
                return false;
        }
    }
    for (int i = 0; i < 4; i++)//列
    {
        for (int j = 0; j < 3; j++)
        {
            if (a[j][i] == a[j+1][i])
                return false;
        }
    }
    return true;
}

对了,顶上预编译指令和全局变量如下

#include<iostream>
#include<string>
#include<ctime>//给srand()预备
#include<conio.h>
using namespace std;
int a[4][4];//2048的数组
int b[4][4];//提供给它撤销功能(不过就提供了一步,感觉要很多步要用栈吧。
//PS:真正的2048哪有这个功能啊)
int score=0;//记录积分
int score_ex = 0;//为撤销而存在

好了,下面进入正文。

W/A/S/D的移动是2048的核心,我只展示一下W吧,反正其他类似,敲起来累死(方向变来变去,路痴的我要神经衰弱了)

void isW()//0往下靠拢
{
    for (int i = 0; i < 4; i++)//排0
    {
        //感觉这个和冒泡类似,不过只将0往下冒
        //这儿采用的是大数往上浮
        //最上面的一格不考虑
        if (a[1][i] != 0)//第二行
        {
            if (a[0][i] == 0)
            {
                a[0][i] = a[1][i];
                a[1][i] = 0;
            }
        }
        if (a[2][i] != 0)//第三行
        {
            for (int j = 0; j < 2; j++)
            {
                if (a[j][i] == 0)
                {
                    a[j][i] = a[2][i];
                    a[2][i] = 0;
                    break;
                    /*这儿要解释一下为什么找到一个就够,
                    而且从最上面开找。
                    假设1{0,2,4,8},当2浮动后,0就会往下一位,由于我已经从第一行开写,所以不会存在有0存留在上面。
                     假设2{0,0,2,4},这个假设说明了这个for循环要从0开始的原因,不然2只会和第二个0作交换,形成{0,2,4,0}。*/
                }
            }
        }
        if (a[3][i] != 0)//第四行
        {
            for (int j = 0; j < 3; j++)
            {
                if (a[j][i] == 0)
                {
                    a[j][i] = a[3][i];
                    a[3][i] = 0;
                    break;
                }
            }
        }
    }
    //排0结束,下面开始合并并算积分
    for (int i = 0; i < 4; i++)
    {
        int flag = 3;
        //找出列中最后一个非零的
        for (int j = 3; j >= 0; j--)
        {
            if (a[j][i] != 0)
            {
                break;
            }
            flag--;
        }
        if (flag == 0)//只有第一行非零
            continue;//也就是只有一个数,根本不能合并,直接跑下一行
        if (flag == 1)
        {//有两个数,判断一下能否合并就好
            if (a[0][i] == a[1][i])
            {
                a[0][i] += a[0][i];//不用*2是为了省时,没去学移位,这儿移位最好吧
                a[1][i] = 0;//合并了就置0
                score += a[0][i];
                continue;
            }
            continue;
        }
        if (flag == 2)
        {
            if (a[0][i] == a[1][i])
            {
                a[0][i] += a[0][i];
                a[1][i] = a[2][i];//这儿要注意不能立马置0,而是把下一个数先移上来
                a[2][i] = 0;
                score += a[0][i];
                continue;
            }
            if (a[1][i] == a[2][i])
            {
                a[1][i] += a[1][i];
                a[2][i] = 0;
                score += a[1][i];
                continue;
            }
            continue;
        }
        /*if (flag == 2)
        //这儿是PDF中的算法,但是我认为它并不符合真正的2048,
        为了方便大家我再手打一遍算法描述2),
        每次按方向键后,逐行计算移动后的方格值的算法是:先将所有值为0的数移至行首。然后从行首开始逐一和后一个数比较,如果相等则合并这2个格子,合并过的方块不再继续合并;
        那么问题就来了假设原先是{0,8,8,8}的转置,那么往上移动时,0往下沉,完成0的移动后应该为{8,8,8,0}的转置,
        根据算法描述,0的方向是行首,那么从行首开始合并,结果应该是{8,16,0,0},
        细心的小伙伴到这儿应该发现问题大了!这个规则不让人玩高分啊!!
        没发现的话,你就用注释的代码多玩玩,出了1024就神级了。。。
        {
            if (a[1][i] == a[2][i])
            {
                a[1][i] += a[1][i];
                a[2][i] = 0;
                score += a[1][i];
                continue;
            }
            else
            {
                if (a[0][i] == a[1][i])
                {
                    a[0][i] += a[0][i];
                    a[1][i] = a[2][i];
                    a[2][i] = 0;
                    score += a[0][i];
                    continue;
                }
            }
            continue;
        }*/
        if (flag == 3)
        {//这儿的逻辑可能会令人作呕,因为我是从原来的规则改过来的
            if (a[0][i] == a[1][i])
            {//判断1、2两行是否相同
                a[0][i] += a[0][i];
                a[1][i] = a[2][i];
                a[2][i] = a[3][i];
                a[3][i] = 0;
                score += a[0][i];
                //有必要进一步判断剩下的两行能否合并,例{2,2,4,4},之所以后面不是a[2][i]与a[3][i]是因为上面刚做过移动
                if (a[1][i] == a[2][i])
                {
                    a[1][i] += a[1][i];
                    a[2][i] = 0;
                    score += a[1][i];
                }
                continue;//移动完就去下一行吧
            }
            else
            {
                if (a[1][i] == a[2][i])
                {//当前两行不同,就判断2、3两行是否相同
                    a[1][i] += a[1][i];
                    a[2][i] = a[3][i];
                    a[3][i] = 0;
                    score += a[1][i];
                    continue;
                }
                if (a[2][i] == a[3][i])
                {//跑到这儿就意味着1、2 ,2、3不相同,判断3、4是否相同
                    a[2][i] += a[2][i];
                    a[3][i] = 0;
                    score += a[2][i];
                    continue;
                }
                continue;
            }
        }
        /*if (flag == 3)
        {
            if (a[2][i] == a[3][i])
            {
                a[2][i] += a[2][i];
                a[3][i] = 0;
                score += a[2][i];
                if (a[0][i] == a[1][i])
                {
                    a[0][i] += a[0][i];
                    a[1][i] = a[2][i];
                    a[2][i] = 0;
                    score += a[0][i];
                }
                continue;
            }
            else
            {
                if (a[1][i] == a[2][i])
                {
                    a[1][i] += a[1][i];
                    a[2][i] = a[3][i];
                    a[3][i] = 0;
                    score += a[1][i];
                    continue;
                }
                if (a[0][i] == a[1][i])
                {
                    a[0][i] += a[0][i];
                    a[1][i] = a[2][i];
                    a[2][i] = a[3][i];
                    a[3][1] = 0;
                    score += a[0][i];
                    continue;
                }
                continue;
            }
        }*/
    }
}

当当当,完成四个移动的函数还改了好几遍真是头昏脑涨啊。

接下来制定游戏规则部分,不过先初始化一下吧

void init()
{
    cout << "rule:\n\t1.w/s/a/d for direction\n\t2.r to restart \n\t3.u to 返回一步(不能连续用)\n\t4.e to exit\n";
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            a[i][j] = 0;
            b[i][j] = 0;
        }
    }
    score = 0;
    score_ex = 0;
    srand(time(NULL));//如果随机数种子不改一下,每次玩的都一样……
    int addr = getRandAddr();
    a[addr / 4][addr % 4] = getRand();
}

那么开始GAME吧

void game()
{
    string choose;
    cout << "choose level: 1-normal   2-hard  3-BT:";//选择难度吧,骚年~
    while (cin>>choose)
    {
        if (choose[0] == '1')
        {
            init();
            break;
        }
        if (choose[0] == '2')
        {
            init2();
            break;
        }
        if (choose[0] == '3')
        {
            init3();//哈哈变态版,添加了四个障碍
            break;
        }
    }
    while (1)
    {
        display();
        if (isEnd())//判断你是否还能移动
        {
            string end;
            cout << "\t\tGame over !\n";
            cout << "\t\tYour Score is:" << score << endl;
            cout << "input 'r' to restart other to exit.";
            cin >> end;
            if (end[0] == 'r')
            {
                system("cls");
                game();
            }
            else
            {
                exit(0);
            }
        }
        //cin >> choose;//原来用这个,每次输入w/a/s/d都要按下Enter
        choose[0] = _getch();//这个按了w就会直接移动了,详情百度conio.h _getch();
        if (choose[0] == 'u')
        {
            reWrite();//just one step ,就是将备份的数组写回进来
            system("cls");
            continue;
        }
        copyRight();//既然你都不撤回了,我就先将现在的保存一下
        switch (choose[0])
        {
            case 'w':isW(); break;//上下左右
            case 'a':isA(); break;
            case 's':isS(); break;
            case 'd':isD(); break;
            case 'e':exit(0);
            case 'r':{system("cls"); game(); break; }//一般人不会一直玩到栈溢出吧。。。
            default:
            {
                system("cls");
                cout << "Error input,Try angin.\n";
                continue;
            }
        }
        if (isSame())
        {//如果相同就不产生新数字了,算法里面没描述,玩过都知道~
            system("cls");//因为每次都会display()还是应该清除一下
            continue;
        }
        int addr = getRandAddr();
        while (!isSafeAddr(addr))//一直找到安全位置为止
        {
            addr = getRandAddr();
        }
        a[addr / 4][addr % 4] = getRand();//产生新数了。
        system("cls");
    }
}

下面这个函数都是在里面出现过,不是很重要而且没代码的

void init2()//这个只是一个障碍,想要4障碍自己写一下吧
{
    cout << "rule:\n\t1.w/s/a/d for direction\n\t2.r to restart \n\t3.u to 返回一步(不能连续用)\n\t4.e to exit\n";
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            a[i][j] = 0;
            b[i][j] = 0;
        }
    }
    score = 0;
    score_ex = 0;
    srand(time(NULL));
    int addr = getRandAddr();
    a[addr / 4][addr % 4] = getRand();
    addr = getRandAddr();
    while (!isSafeAddr(addr))
    {
        addr = getRandAddr();
    }
    a[addr / 4][addr % 4] = -1;
}
void display()//打印一下
{
    char D = char(127);//障碍物的样子,我也不知道用啥好
    for (int i = 0; i < 4; i++)
    {
        cout << "\t";
        for (int j = 0; j < 4; j++)
        {
            if (a[i][j] == 0)//每次都是0眼都花了
            {
                cout << ".\t";
                continue;
            }
            if (a[i][j] == -1 || a[i][j] == -2 || a[i][j] == -3 || a[i][j] == -4)//遇到障碍物
            {
                cout << D<<"\t";
                continue;
            }
            cout << a[i][j] << "\t";
        }
        cout << "\n\n";
    }
    cout << "score: " << score << "\n\n";
    cout << "\t" << "Next:";
}

这儿可能代码还不全,待会上传下载的,会在下面补上。

附上一张变态版的皂片吧(^__^) 嘻嘻……

目录
相关文章
|
2月前
|
Java Android开发
大鱼吃小鱼【小游戏】
大鱼吃小鱼【小游戏】
100 0
|
2月前
|
Linux C语言
|
10月前
|
Python
实现一个2048小游戏
要实现一个2048小游戏,你需要使用Python编程语言和图形用户界面(GUI)库。下面是一个使用Tkinter库来创建2048小游戏的基本步骤
446 3
|
2月前
贪吃蛇小游戏
贪吃蛇小游戏
228 5
|
12月前
10点小游戏 2021-04-22
10点小游戏 2021-04-22
113 0
|
12月前
|
移动开发
H5贪吃蛇小游戏
H5贪吃蛇小游戏
点这里,玩小蚂蚁的小游戏
对于很多人来说(比如说我自己),平时没有大段的时间和精力去玩一个大游戏,这些人需要一些简单好玩的小游戏,拿起来就能玩几下,在忙碌的生活中寻求片刻的放松,随时又可以放下,继续回归到生活。如果你也是这些人的话,那么这些小游戏就是为你而做的,希望你能够喜欢。
89 0
点这里,玩小蚂蚁的小游戏
小蚂蚁的小游戏系列
对于很多人来说(比如说我自己),平时没有大段的时间和精力去玩一个大游戏,这些人需要一些简单好玩的小游戏,拿起来就能玩几下,在忙碌的生活中寻求片刻的放松,随时又可以放下,继续回归到生活。如果你也是这些人的话,那么这些小游戏就是为你而做的,希望你能够喜欢。
83 0
小蚂蚁的小游戏系列
|
存储 定位技术 开发工具
坦克大战小游戏的实现
坦克大战小游戏的实现
推箱子小游戏(c++实现)
推箱子小游戏(c++实现)