首页 > 编程知识 正文

2048算法思路,2048c语言算法分析

时间:2023-05-06 12:23:41 阅读:232650 作者:2513

 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); } }}

自己试着不要看把代码码出来哦,测试样例可以直接复制,加油小伙汁小改改,为了更美好的未来呢~~~

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。