【发布时间】: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] 的列表。
【问题讨论】:
-
在下面的帖子中查看我的解决方案。我创建了自己的按钮数组(您可以改用图片框)。我创建了一个继承标准按钮类的类,然后添加了行号和列号等属性,以便我可以轻松判断按下了哪个按钮:stackoverflow.com/questions/37165402/…
-
@jdweng 我可以毫不费力地确定哪个图片框对应于哪一行和哪一列。我只是无法确定在执行特定方向的移动时移动了哪些图块。
-
可以给继承的类添加属性,更好的识别每个图片框。您可以添加图片名称或其他任何可以为您提供更多信息的名称。在您的情况下,磁贴名称可能会有所帮助。