• 给大家分享一个小程序—2048


    微信公众号:CodeId
    有什么建议可以到公众号里进行留言。

    很高兴又和大家见面了,最近写了个小游戏——2048,这个游戏实现起来不是很难,感觉它对自己的逻辑能力起到一个训练作用,还不错,所以今天分享给大家。我是通过小程序写的,源码已经放到GitHub上了https://github.com/CrazyIdeas1/WeiXinXiaoChengXu_2048Pro。这篇文章的讲解顺序是先分析2048然后通过代码实现里面的主要功能。

    0.开篇看图

    主页
    主页

    1. 2048分析

    2048小游戏的规则想必大家已经知道了吧,简单的说就是你通过上下左右的滑动一个4*4的表格,表格中相同的数字进行求和,使它们的和接近2048。下面我们取出其中的一个方向(其他方向类似),对它的过程进行简单的分析:

    1//选取向左滑到的方向
    22 0 0 2 4 0 0 0 4 0 0 0
    30 2 2 0 相同求和 0 4 0 0 位置移动 4 0 0 0
    42 4 2 0 ------> 2 4 2 0 -----> 2 4 2 0
    50 2 4 0 0 2 4 0 2 4 0 0
    6//起始 结束

    通过上面的分析我们知道,当我们的手指向某一个方向滑动表格时,它的内部至少要经历两步操作,一个是相同求和,另一个是位置移动。接下来对着两步进行分析

    2.相同的求和

    相同求和是指在某一方向上,对值相等并且中间没有其他值的两个数,进行相加求和,看下面代码:

     1merge: function(cells){
    2 for (let i = 0; i < 4; i++) {
    3 for (let j = 0; j < 4; j++) {
    4 if (cells[i][j] != "") {//排除前面的空格 标记一
    5 if ((j + 1) < 4 && cells[i][j] == cells[i][j + 1] && cells[i][j] != 2048) { //标记二
    6 cells[i][j] += cells[i][j + 1];//求和
    7 cells[i][j + 1] = "";//清空原有值
    8 j++;//把坐标移到两个数的后面
    9 } else {
    10 for (let k = j + 1; k < 4; k++) { //标记三
    11 if (cells[i][k] != "") {
    12 if (cells[i][j] == cells[i][k] && cells[i][j] != 2048) {//标记二
    13 cells[i][j] += cells[i][k];//求和
    14 cells[i][k] = ""; //清空原有值
    15 j = k;
    16 } else {
    17 j = k - 1;
    18 }
    19 break;
    20 }
    21 }
    22 }
    23 }
    24 }
    25 }
    26 }

    简单解读一下上面的代码:标记一是用来排除前面的空值的,例如0 0 2 2,直接排除前面的两个空值(0)。标记二是用来判断两个值是否相等的,相等时就进行里面的一些列操作。标记三是用来排除两个数之间是空值的情况的,例如2 0 0 2,排除中间的两个空值(0)。其他的就不用多说,都有注释。

    3.位置移动

    位置移动是指让表格中所有的数字在不变顺序的情况下,统一移动到某一方向上,数与数之间和数与某一方向的边之间不允许有空值。看下面代码:

     1moveUnit: function(cells){
    2 for (let i = 0; i < 4; i++) {
    3 var count = 0;
    4 for (let j = 0; j < 4; j++) {
    5 if (cells[i][j] != "") {
    6 cells[i][count++] = cells[i][j];//标记一
    7 if ((count - 1) != j) {//标记二
    8 cells[i][j] = "";//把当前值清空
    9 }
    10 }
    11 }
    12 }
    13 }

    在上述代码中标记一表示把当前值赋值到前面去。标记二表示如果当前值的位置和你赋值到前面去的位置 相同时,就不把当前值清空。

    4.转变方向

    读完上面的几步,你会发现完成某一方向(上面讲的是向左移动)的移动和求和,已经基本完事,只要把上边的代码稍加改变就可以把其他三个方向的代码敲出来了(我一开始就是这么干的)。但是这样会出现一个问题,就是很多的代码都会重复出现,代码量也很大。后来我通过转变方向的方法把代码就行了简单优化。
    转变方向就是把所有方向上的表格按照一定的规则统一转换到同一个方向上去操作,等操作完毕后再按照一定的规则转换到原来的方向。看下面代码:

    4.1 转换到同一方向

     1changeDirection: function(cells){
    2 var result = [[],[],[],[]]
    3 for(let i = 0; i < 4; i++){
    4 for(let j = 0; j < 4; j++){
    5 if (this.driection == 1){ // 上 》》左
    6 result[i][j] = cells[j][3-i]
    7 } else if (this.driection == 2){// 下 》》左
    8 result[i][j] = cells[3-j][i]
    9 } else if (this.driection == 3){//右 》》 左
    10 result[i][j] = cells[i][3-j]
    11 } else if (this.driection == 4){//不动
    12 result[i][j] = cells[i][j]
    13 }
    14 }
    15 }
    16 return result;
    17 }

    在上面代码中 1表示方向上、2表示方向下、3表示方向右、4表示方向左(本篇通用)。

    4.2 转回到以前的方向

     1reChangeDirection: function(result){
    2 var cells = [[], [], [], []]
    3 for (let i = 0; i < 4; i++) {
    4 for (let j = 0; j < 4; j++) {
    5 if (this.driection == 1) { // 左 >>>>> 上
    6 cells[i][j] = result[3 - j][i];
    7 } else if (this.driection == 2) {//左 >>>>> 下
    8 cells[i][j] = result[j][3 - i];
    9 } else if (this.driection == 3) {//左 >>>>> 右
    10 cells[i][j] = result[i][3 - j];
    11 } else if (this.driection == 4) {//左 不动
    12 cells[i][j] = result[i][j];
    13 }
    14 }
    15 }
    16 return cells;
    17 },

    以上两段代码 都是有关表格方向的转变,里面没有涉及到什么算法,如何理解比较困难,就自己找几个样例在纸上写一写、画一画。

    5.产生随机数

    上面我们基本解决了表格的合并和移动问题,接下来是看如何产生随机的24。看下面代码:

     1randomunt: function (cells) {
    2 var value = Math.random() < 0.9 ? 2 : 4;//产生随机值,90%概率产生 2
    3 var re = [];
    4 var count = 0;
    5 for (let k = 0; k < 4; k++) {//统计有哪些格子没有数字
    6 for (let kk = 0; kk < 4; kk++) {
    7 if (cells[k][kk] == "") {
    8 re[count++] = { k, kk };
    9 }
    10 }
    11 }
    12 if (count > 0) {//当没有空格时就不进行随机数赋值了
    13 var location = parseInt(Math.random() * (re.length - 1));//随机选择位置
    14 cells[re[location].k][re[location].kk] = value;//进行赋值
    15 }
    16 }

    在上述代码中 注释已经解释的比较明白。我这里简单说一下思路:首先随机产生一个值24,然后通过循环把所有空值的坐标存入数组(re)中,再从数组中随机选取一个空值坐标,通过坐标对相应元素进行赋值。

    6.游戏结束

    游戏的基本操作终于要结束了,接下来我们判断游戏是如何结束的。看下面代码:

     1endgame: function (cells) {
    2 var isNULL = false; //判断是否有空元素
    3 for (let x = 0; x < 4; x++) {
    4 for (let y = 0; y < 4; y++) {
    5 if (cells[x][y] == "") {
    6 isNULL = true;
    7 }
    8 }
    9 }
    10 if (!isNULL) { //没有空元素时 进入
    11 for (let i = 0; i < 4; i++) {
    12 for (let j = 0; j < 4; j++) {
    13 if ((j + 1) < 4 && cells[i][j] == cells[i][j + 1]) {//判断横向是否有相等的元素
    14 return false;
    15 }
    16 if ((j + 1) < 4 && cells[j][i] == cells[j + 1][i]) {//判断纵向是否有相等的元素
    17 return false;
    18 }
    19 }
    20 }
    21 return true;
    22 }
    23 return false;
    24 }

    简述上面的代码:首先判断是否表格中是否存有空值,有 就证明游戏没有结束,没有 就判断表格中的上下左右是否有相等的元素,没有 证明游戏已经结束,有 就继续进行游戏。

    今天的学习暂时告一段落,后面会不定时更新的。送大家一句话生活越来越美好
    下面是我的公众号:CodeId 欢迎关注

    CodeId
    CodeId
  • 相关阅读:
    快速幂
    快速幂
    快速排序的分治求解方法
    快速排序的分治求解方法
    合并排序的分治求解方法
    合并排序的分治求解方法
    重写ListView解决ListView内部ViewPaper滑动事件冲突问题
    HDU 4970(杭电多校#9 1011题)Killing Monsters(瞎搞)
    Java 反射机制[Field反射]
    【公告】博客数据异常已所有恢复
  • 原文地址:https://www.cnblogs.com/CrazyIdeas/p/8666238.html
Copyright © 2020-2023  润新知