如何确定在我的 2048 实现中哪些图块移动和合并?
Posted
技术标签:
【中文标题】如何确定在我的 2048 实现中哪些图块移动和合并?【英文标题】:How can I figure out which tiles move and merge in my implementation of 2048? 【发布时间】:2018-07-30 00:41:21 【问题描述】:我正在构建一个 2048 WinForms 小游戏,只是为了好玩。
请注意,这与2048 AI 无关。我只是想做一个人类可以玩的2048游戏。
我首先决定使用 0-17 来表示瓷砖。 0 代表一个空的瓦片。 1 代表 2 瓦。 2 代表一个 4 瓦。 3 代表 8 块,以此类推。
然后我在考虑如何计算得到的棋盘,给定移动方向和移动前的棋盘。这是我的想法:
要向上移动,只需将板逆时针旋转 90 度,向左移动,然后将板向后旋转 要向右移动,只需将板顺时针旋转 180 度,向左移动,然后再旋转回来 要向下移动,只需将板顺时针旋转 90 度,向左移动,然后再旋转回来。所以我只需要弄清楚当玩家向左移动时如何计算结果棋盘,然后我可以通过旋转棋盘、向左移动和向后旋转来计算剩下的方向。然后我用这个非常奇怪的左移算法来了 p。
通过添加 96 并强制转换为char
,将初始棋盘的每个整数转换为字符。现在,反勾号 (`) 表示空磁贴,a
表示 2 磁贴,b
表示 4 磁贴,依此类推,一直到p
。
将字符连接成 4 个字符串,每个字符串代表棋盘的一行。
一个示例板可能如下所示:
aa``
````
```b
``cb
对于每个字符串,
删除所有反引号 使用正则表达式(是的,我在 2048 游戏中使用正则表达式)([a-p])\1
并获取字符串的第一个匹配项。
用新图块替换第一个匹配项
匹配尚未匹配的其余字符串,直到找不到更多匹配项为止。
如果字符串少于 4 个字符,则将其填充到右侧。
通过减去 96 将每个字符串变回整数数组
这就是我评估每一行的方式:
int[] EvaluateRow(int[] row)
// RowToString converts an int[] to a string like I said above
StringBuilder rowString = new StringBuilder(RowToString(row));
rowString.Replace("`", "");
var regex = new Regex("([a-p])\\1");
int lastIndex = -1;
while (true)
var match = regex.Match(rowString.ToString(), lastIndex + 1);
if (match.Success)
// newChar is the new tile after the merge
char newChar = (char)(match.Value[0] + 1);
rowString.Remove(match.Index, match.Length);
rowString.Insert(match.Index, newChar);
lastIndex = match.Index;
Score += // some calculation for score, irrelevant
else
break;
// StringToRow converts a string to an int[]
return StringToRow(rowString.ToString());
但是,我当前的算法存在一个非常大的问题。这个算法只告诉我一个移动的最终结果,但是我不知道我需要移动哪个图片框(我正在使用图片框显示瓷砖),每个图片框应该移动多少空间,以及哪个图片框需要显示新图像。我真的不想使用其他解决方案,我只想对我当前的解决方案进行一些更改。
这是我需要从每一行(字符串)中得到的东西:
List<(int x, int spaces)>
。每个元素表示需要移动哪个图块(x 坐标),以及它应该移动多少个空格 (spaces
)。
List<int>
。每个元素代表被合并到的瓦片的 x 坐标。
如何从行字符串中获取这些信息?示例:
行字符串:
`a`a
将生成一个类似[(1, 1), (3, 3)]
的列表和另一个类似[1]
的列表。
【问题讨论】:
在下面的帖子中查看我的解决方案。我创建了自己的按钮数组(您可以改用图片框)。我创建了一个继承标准按钮类的类,然后添加了行号和列号等属性,以便我可以轻松判断按下了哪个按钮:***.com/questions/37165402/… @jdweng 我可以毫不费力地确定哪个图片框对应于哪一行和哪一列。我只是无法确定在执行特定方向的移动时移动了哪些图块。 可以给继承的类添加属性,更好的识别每个图片框。您可以添加图片名称或其他任何可以为您提供更多信息的名称。在您的情况下,磁贴名称可能会有所帮助。 【参考方案1】:我不认为对字符的转换真的增加了任何有用的东西。如果您坚持使用数字表示(0 = 空),那么您可以使用以下逻辑来查找目标配置 和 哪个块去了哪里。这是伪代码(给出row
):
fromTo = [-1, -1, -1, -1];
result = [0, 0, 0, 0];
prevVal = 0;
pos = 0;
for (i = 0; i < 4; i++)
if (row[i]) // Not empty
if (row[i] == prevVal)
result[pos-1]++; // merged
fromTo[i] = pos-1;
prevVal = 0; // avoid triple merge
else
result[pos] = row[i];
fromTo[i] = pos;
prevVal = row[i];
pos++;
现在fromTo
数组将为每个索引指示该原始位置的块所在的位置。 result
将具有最终值。从这两条信息中,您还可以知道合并了哪些块。 result[fromTo[i]] != row[i]
时合并原始位置 i 的块。您还知道一个块将行进的距离:i - fromTo[i]
。简而言之,您拥有为每个块设置动画的所有信息。
示例
row | fromTo | result
------------+----------------+-----------
[0,1,0,1] | [-1,0,-1,0] | [2,0,0,0]
[0,1,1,1] | [-1,0,0,1] | [2,1,0,0]
[1,1,1,1] | [0,0,1,1] | [2,2,0,0]
[1,2,2,3] | [0,1,1,2] | [1,3,3,0]
【讨论】:
你能举个例子吗?如果行是[0,1,0,1]
,fromTo
和 result
会是什么?为什么?
我添加了一些示例。第一个将有[-1,0,-1,0]
用于fromTo
。 -1 是默认值,当初始位置没有块时不会触及。两个零表示位置 1 和 3 的块都将转到位置 0(它们将合并的位置)。 result
将在第一个位置反映此合并:[2,0,0,0]
。其他零是默认值,表示该位置将为空。以上是关于如何确定在我的 2048 实现中哪些图块移动和合并?的主要内容,如果未能解决你的问题,请参考以下文章