最近在做一个 C++ 为基础的游戏课程设计, 没想到什么好做的, 于是做了 2048

自己在高一的时候开始接触 2048, 并且现在基本玩的还行

这游戏一个看你智商, 另外一个运气也占了不少因素. 因为未知的方块要想把它利用起来, 或者不想让它造成太大麻烦, 那么它就要出现在合理并且合适的位置

2048 其实做起来挺简单的, 对于游戏来说. 如果有基本入门 Win 32 编程的几乎都会做吧

但是, 2048 里面有一个很重要的东西, 就是本身的移动算法

一开始想的是把每种情况都列出来, 刚开始漏了很多种情况, 只考虑到四个格子都有数字的情况, 所以感觉挺简单的. 后来发现, 只有三个格子有、只有两个格子有和只有一个格子有数字这些情况, 并且情况里分成了很多小情况, 就是上下或者左右是否相等, 如何相等的问题. 于是放弃了这种写法

又在网上搜到了 5 个 for 语句完成, 上下左右每个函数都包含了 5 个 for 语句. 这种方法可以使程序正常运行, 算法上就不怎么样了

后来又发现了一种算法, 不得不说想出这种算法的人真的是聪明的一笔

一个数组, 总共才 4 个数字, 能想到这个确实不容易

基本的几个变量这里作一下解释 :

moved :  移动判断 bool 变量, 如果按键后数组有变化, 则赋值 true

full : 判断数组中是否含有 0, 如果有则赋值 false

checkFull() 方法和 full 变量联合使用

saveToRecallArray() 方法 : 保存数组在 recallArray 数组中, 方便用户在有撤回次数的时候使用撤回功能

checkGameWin() 方法 : 在移动之后, 检测是否胜利

emptyPositionFill() 方法 : 在移动之后, 在数组为 0 的位置产生一个 2 或者 4 其中一个数字

ARRAY_NUMBER : 宏常量 4. 定义了数组横排与竖排的最大元素个数

以上所有变量和方法均写在一个叫做 Game 的对象当中, 具体是上、下、左还是右可以通过方法名字去判断

具体代码如下 (非注册用户等待 2018 年 1 月中旬, 注册用户请忽略) :

12 月 29 更新

遍历数组 {

    从遍历元素下一个元素开始进行对数组进行新的遍历 {

        查找不为 0 的元素的下标

    }

    如果找到不为 0 的元素下标 {

        如果当前元素等于 0 {

            交换查找元素与当前被遍历元素

        }

        如果当前元素不等于 0 {

            当前元素 x 2

            查找元素对应位置 0

        }

    }

}

下面以向左滑动为例子, 给出代码 :

void Game::leftKeyDown() {

    bool moved = false;

    bool full = checkFull();

    int tempArray[ARRAY_NUMBER][ARRAY_NUMBER];

    if (recallTimes) {

        saveToTempRecallArray(tempArray);

    }

    for (int i = 0; i < ARRAY_NUMBER; i++) {

        for (int j = 0; j < ARRAY_NUMBER; j++) {

            int next = -1;

            for (int k = j + 1; k < ARRAY_NUMBER; k++) {

                if (arr[i][k] != 0) {

                    next = k;

                    break;

                }

            }

            if (next != -1) {

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

                    moved = true;

                    arr[i][j] = arr[i][next];

                    arr[i][next] = 0;

                    j--;

                }else if (arr[i][j] == arr[i][next]) {

                    moved = true;

                    score += arr[i][j];		//游戏得分增加

                    arr[i][j] *= 2;

                    arr[i][next] = 0;

                }

            }

        }

    }

    if (moved) {

        checkGameWin();

        if (recallTimes) {

            saveToRecallArray(tempArray);

        }

    }else if (!moved && full) {

        checkGameOver();

        return;

    }

    if (moved && !full) {

        emptyPositionFill();

    }

}