我正在构建一个2048 WinForms游戏,只是为了好玩 .
请注意,这不是2048 AI . 我只是想制作一部可由人类演奏的2048游戏 .
我首先决定用0-17代表瓷砖 . 0表示空图块 . 1表示2个图块 . 2表示4瓦 . 3表示8瓦,依此类推 .
然后我考虑如何计算得到的板,给定移动方向和移动前的板 . 这就是我的想法:
-
要向上移动,它只是将电路板逆时针旋转90度,向左移动,然后向后旋转电路板
-
要向右移动,它只是将板顺时针旋转180度,向左移动,然后向后旋转
-
要向下移动,它只是将板顺时针旋转90度,向左移动,然后向后旋转 .
所以我只需要弄清楚当玩家向左移动时如何计算得到的棋盘,然后我可以通过旋转棋盘,向左移动和向后旋转来找出其余的方向 . 然后我用这个非常奇怪的算法向左移动了 .
-
通过添加96并转换为
char
将每个初始板的整数转换为字符 . 现在后面的刻度线()代表一个空的平铺,
a代表一个2平铺,
b代表一个4平铺,依此类推,直到
p` . -
将字符连接起来形成4个字符串,每个字符串代表一行电路板 .
-
示例板可能如下所示:
aa``
``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());
}
但是,我目前的算法存在一个非常大的问题 . 这个算法只告诉我移动的最终结果,但我不知道哪个图片框(我用图片框来显示图块)我需要移动,每个图片框应该移动多少个空格,以及哪个图片盒子需要显示一个新的图像 . 我真的不想使用其他解决方案,我只想对当前的解决方案进行一些更改 .
以下是我需要从每一行获取的内容(字符串):
-
A
List<(int x, int spaces)>
. 每个元素代表哪个图块需要移动(x坐标),以及它应移动多少个空格(spaces
) . -
A
List<int>
. 每个元素表示合并到的图块的x坐标 .
如何从行字符串中获取这些信息?例:
行字符串:
`a`a
将产生一个像 [(1, 1), (3, 3)]
的列表和另一个像 [1]
的列表 .
1 回答
我认为对字符的转换实际上并没有添加任何有用的东西 . 如果你坚持使用数字表示(0 =空),那么你可以使用以下逻辑来找到目标配置和哪个块去了哪里 . 这是伪代码(给出
row
):现在
fromTo
数组将指示每个索引,即原始位置的块所在的位置 .result
将具有最终值 . 从这两条信息中,您还可以知道合并了哪些块 .result[fromTo[i]] != row[i]
时合并原始位置i的块 . 您还知道一个街区的行程距离:i - fromTo[i]
. 简而言之,您拥有为每个块设置动画的所有信息 .例子