如何确定哪些瓷砖在我的2048实施中移动和合并?

Swe*_*per 13 c# string algorithm

我正在构建一个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``
    ````
    ```b
    ``cb
    
    Run Code Online (Sandbox Code Playgroud)
  • 对于每个字符串,

    • 删除所有后面的刻度
    • 使用正则表达式(是的,我在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());
    }
Run Code Online (Sandbox Code Playgroud)

但是,我目前的算法存在一个非常大的问题.这个算法只告诉我移动的最终结果,但我不知道哪个图片框(我用图片框来显示图块)我需要移动,每个图片框应该移动多少个空格,以及哪个图片盒子需要显示一个新的图像.我真的不想使用其他解决方案,我只想对当前的解决方案进行一些更改.

以下是我需要从每一行获取的内容(字符串):

  • List<(int x, int spaces)>.每个元素代表哪个图块需要移动(x坐标),以及它应移动多少个空格(spaces).
  • List<int>.每个元素表示合并到的图块的x坐标.

如何从行字符串中获取这些信息?例:

行字符串:

`a`a
Run Code Online (Sandbox Code Playgroud)

将生成一个列表[(1, 1), (3, 3)]和另一个列表[1].

tri*_*cot 5

我认为对字符的转换实际上并没有添加任何有用的东西.如果你坚持使用数字表示(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++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,fromTo数组将指示每个索引,即原始位置的块所在的位置.该result会的最终值.从这两条信息中,您还可以知道合并了哪些块.原始位置i的块在合并时result[fromTo[i]] != row[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]
Run Code Online (Sandbox Code Playgroud)