Note:想了半天开场白,发现真的不知道说啥,得,直接给您阐述思路吧。
首先最基础的,2048只有四种操作手法,就是上下左右的移动(手机上就为划屏)。但是有过一定编程基础的你肯定能想到,很明显要用一个类似方法来实现这四种操作,而不是四种完全不同的方法。所以我们完全可以先实现一种操作,进而类比到其他操作就能很快的实现这个过程。
玩家选定一个移动方向之后,我们希望看到的是相同相邻的数据相加,且所有数据都堆积到移动的方向上。这就是我们最基本的玩法和需求。所有我们就要细分理解实现其中的过程:
1、我么希望相同相邻的数据相加,那么相同但是不相邻中间隔0的数据怎么处理?
2、我们希望两个数相加过后不再参与下一次的相加,如2240,不能2+2之后又+4,这一块怎么设计呢?
3、在不同的移动方向上,我们相加和读取的顺序是不同的,怎么才能找到一个能重载的方法呢?
2048游戏就是一个二维数组上的游戏。我们的所有操作,实际上都是针对这一个二维数组的。而大部分时候,我们都会选择用嵌套的for循环,来分而治之。什么意思呢?我们可以将二维数组看成多个一维数组,我们不去操作整个二维数组而是操作每一行每一列。向左移动时,我们一行一行的处理;向上移动时,我们一列一列的处理。这样问题就简单很多了。所以我们的大概思路就有了,就拿向左移动举个例子。
首先我们希望实现相加,那我们将这一行读取出来,当做一维数组来处理。我们逐个扫描数据,遇到相邻一样的我们就直接相加。这时候问题1就来了,隔着0怎么处理?我们自然可以选择跳过,读到0就跳过不就好了吗。但这时我们需要拿一个数据,记录之前的非零数。你比如说2004008,第一个2我们必须记录下来,直到遇到一个4,我们再拿来做比较,然后我们又得去记录4。这样会不会就显得很麻烦呢?我们换种思路,我们何不直接将0全部移动到最右边呢?从游戏直观上看也确实是0都挪到了右边。所以我们可以考虑新建一个数组,读取一行之后就将所有的非零数一次存进新数组,2004008就成了2480000,这不就方便多了吗?相同相邻的相加,后一个置0,继续遍历下一个数据,处理完后再复制给二维数组不就好了。所以我们把第一个问题解决了。
我们希望不要多次相加,这个其实已经解决掉了,为什么这么说?前面说到了,相加之后,后一个位置数据置0。那么它就不可能和再后面一个相加,也就不用担心参与下一次的加法。当然这里我们要做一个特殊处理,就是0不能拿来判断,不能两个相邻的0你也去做一个加法对不对。所以我们要加一个判断,读到0咱们就不理,因为加了之后必有0,跳过就好了。第二个问题也解决掉了。
前两段,我们已经实现了相加的过程,很简单对不对。关键就是最后一个,我们总不能每一个操作,都设计一个新的算法来实现吧?程序不就要求最好实现重载和复用吗。所以我们需要寻找其中,能够一样用在其他操作上的步骤,然后把它单独提出来写成方法就好了。首先读取,这个可以吗?这就要说到读取那块了。我们观察2048的游戏规则就能发现,数字是往玩家操作的方向堆积的,相加的方向也是不一样的。你比如往左是右边往左加,而往右确实左边往右加。所以读取行和列这块我们不能一视同仁,读取是为了复制到一个新的数组中一起做操作。所以这个操作咱们可以提成一个方法。移动0,相加的过程都是一样的,提出了就好了。剩下的就是每一个操作中循环体的细小差异罢了,这些都是提不出来的。
大概思路就是酱了,语文不好,表述能力不是很强,但是想法都是在代码中的。因为自学的是U3D游戏开发,所以用的是C#语音,和C/C++在我看来差异并不是很大。很容易换成C/C++来实现,所以仍然有借鉴的价值。不多说啦,结合文字和代码能够理解的更快,加油!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Game_2048
{
class Program
{
private static void RemoveZero(int[] array) // 后移0
{ // 将0全部后移,转换一下思路就是将所有非0元素赋值给一个新的数组
int[] newArray = new int[array.Length]; // 默认赋值全0
for (int i = 0, j = 0; i < array.Length; i++) // 用array.Length可以让2048扩展到 nxn
{
if (array[i] != 0)
newArray[j++] = array[i];
}
newArray.CopyTo(array, 0); // 将新数组的数据复制给array
}
private static void Merge(int[] array) // 相加
{ // 将相邻且相同的数据相加,已经做过加法的就不加
RemoveZero(array); // 先将所有0后移
for (int i = 0; i < array.Length - 1; i++)
{
if (array[i] != 0 && array[i] == array[i + 1]) // 非0数据才做相加
{
array[i] *= 2; // 相同且相邻则相加
array[i + 1] = 0; // i先自增即移到下一个数据,清零后i再自增再移到下一个数据
}
}
RemoveZero(array); // 再次将所有0后移
}
private static void MoveToUp(int[,] map) // 上移
{
int[] mergeArray = new int[map.GetLength(0)]; // 获取一维维数即行数
// 遍历列
for (int c = 0; c < map.GetLength(1); c++)
{
for (int r = 0; r < map.GetLength(0); r++) // 在每一列中遍历行
mergeArray[r] = map[r, c]; // 将该列数组赋值给新数组
Merge(mergeArray); // 进行相加操作
for (int r = 0; r < map.GetLength(0); r++) // 将相加后的结果又给回二维数组
map[r, c] = mergeArray[r];
}
}
private static void MoveToDown(int[,] map) // 下移
{
int[] mergeArray = new int[map.GetLength(0)]; // 获取一维维数即行数
// 遍历列
for (int c = 0; c < map.GetLength(1); c++)
{
for (int r = map.GetLength(0) - 1; r >=0; r--) // 倒着赋值
mergeArray[3 - r] = map[r, c];
Merge(mergeArray); // 进行相加操作
for (int r = map.GetLength(0) - 1; r >=0; r--) // 将相加后的结果又给回二维数组
map[r, c] = mergeArray[3 - r];
}
}
private static void MoveToLeft(int[,] map) // 左移
{
int[] mergeArray = new int[map.GetLength(1)]; // 获取二维维数即列数
// 遍历行
for (int r = 0; r < map.GetLength(0); r++)
{
for (int c = 0; c < map.GetLength(1); c++)
mergeArray[c] = map[r, c]; // 将该行数组赋值给新数组
Merge(mergeArray); // 进行相加操作
for (int c = 0; c < map.GetLength(1); c++) // 将相加后的结果又给回二维数组
map[r, c] = mergeArray[c];
}
}
private static void MoveToRight(int[,] map) // 右移
{
int[] mergeArray = new int[map.GetLength(1)]; // 获取二维维数即列数
// 遍历行
for (int r = 0; r < map.GetLength(0); r++)
{
for (int c = map.GetLength(1) - 1; c >= 0; c--)
mergeArray[3 - c] = map[r, c]; // 将该行数组赋值给新数组
Merge(mergeArray); // 进行相加操作
for (int c = map.GetLength(1) - 1; c >= 0; c--) // 将相加后的结果又给回二维数组
map[r, c] = mergeArray[3 - c];
}
}
private static void PrintArray(int[,] map) // 打印输出
{
for (int r = 0; r < map.GetLength(0); r++)
{
for (int c = 0; c < map.GetLength(1); c++)
Console.Write(map[r, c] + "\t"); // WriteLine会在输出完后自动换行
Console.WriteLine();
}
}
static void Main(string[] args)
{
int[,] map = new int[4, 4] // 初始化赋值
{
{2, 2, 4, 8},
{2, 4, 4, 4},
{0, 8, 4, 0},
{2, 4, 0, 4}
};
PrintArray(map);
Console.WriteLine();
MoveToRight(map);
PrintArray(map);
}
}
}
自己试着不要看把代码码出来哦,测试样例可以直接复制,加油小伙汁小改改,为了更美好的未来呢~~~
转载:https://blog.csdn.net/qq_37701948/article/details/102467695