4

我决定制作一个 2048 命令行版,但我无法获得正确的磁贴移动......

我目前的结构是板是一个二维数组(4x4)的整数。当接收到输入时,它将尝试将每个图块推向该方向(忽略值为 0 的图块),如果它注意到更改,它将重新开始(因为底行的图块必须一直向上,不仅仅是一步)。但是,这样做的副作用是以下问题:
[2][2][4] 使用命令 -> 应该给出 [0][4][4] 但由于它重新开始,程序将能够合并4和4并得到一个[0][0][8] intead ...
另一个难题是[4][4][8][8]应该给出[0][0][8][16 ] 所以我不能在合并后停下来。

下面的代码是我的 processCommand 函数。它需要一个棋盘和一个输入(即“d”、“u”、“l”或“r”。如果游戏注意到游戏结束,它将把“游戏结束”作为输入)。它不是很漂亮,我尝试为移动瓷砖制作一个 for 循环(例如,如果你写“l”,值 horiz 将为 -1,如果你写“r”,它将为 1,然后我移动瓷砖水平点,但我无法做到这一点)。

任何关于如何做到这一点的想法(以及对我的编程的批评)将不胜感激!

func processCommand(board [][]int, input string) {

board_new := board

switch input {
    case "d":
        for i := 0; i < height - 1; i++ {
            for j := 0; j < width; j++ {

                if board[i][j] == 0 {
                    continue
                }

                if board[i + 1][j] == 0 || board[i + 1][j] == board[i][j] {
                    board_new[i + 1][j] = board[i + 1][j] + board[i][j]
                    board_new[i][j] = 0
                    i = 0
                    j = 0
                    change = true
                }
            }
        }

    case "u":
        for i := 1; i < height; i++ {
            for j := 0; j < width; j++ {

                if board[i][j] == 0 {
                    continue
                }

                if board[i - 1][j] == 0 || board[i - 1][j] == board[i][j] {
                    board_new[i - 1][j] = board[i - 1][j] + board[i][j]
                    board_new[i][j] = 0
                    i = 1
                    j = 0
                    change = true
                }
            }
        } 

    case "l":
        for i := 0; i < height; i++ {
            for j := 1; j < width; j++ {

                if board[i][j] == 0 {
                    continue
                }

                if board[i][j - 1] == 0 || board[i][j - 1] == board[i][j] {
                    board_new[i][j - 1] = board[i][j - 1] + board[i][j]
                    board_new[i][j] = 0
                    i = 0
                    j = 1
                    change = true
                }
            }
        }

    case "r":
        for i := 0; i < height; i++ {
            for j := 0; j < width - 1; j++ {

                if board[i][j] == 0 {
                    continue
                }

                if board[i][j + 1] == 0 || board[i][j + 1] == board[i][j] {
                    board_new[i][j + 1] = board[i][j + 1] + board[i][j]
                    board_new[i][j] = 0
                    i = 0
                    j = 0
                    change = true
                }
            }
        }

    case "gameover":
        gameOver = true

    default:
        processCommand(board, input)
}

board = board_new

}

4

1 回答 1

5

首先你的合并问题

目前,您始终从上到下和从左到右扫描您的图块,与玩家的移动无关。然而,对于 2048,最好在玩家移动的相反方向上扫描,因为只会在该方向上合并图块。例如,让我们看下面的场景:

0   0   2   0   |
0   0   2   2   | Player move
0   2   4   8   v
2   32  4   2

让我们假设玩家的移动方向是向下的,所以我们开始从底部向上扫描。在第三列中,我们需要先合并 4+4,然后再合并 2+2,即从下到上。朝那个方向前进允许您合并 4+4,然后将列的最底部字段标记为已合并,因此不允许进一步合并(由数字周围的括号表示):

0   0   0   0   |
0   0   2   2   | Player move
0   2   2   8   v
2   32  (8) 2

合并最底部的单元格后(如果可能),我们继续上面的单元格,依此类推......

0   0   0   0   |
0   0   0   2   | Player move
0   2   (4) 8   v
2   32  (8) 2

[...]

0   0   (0) 0   |
0   0   (0) 2   | Player move
0   2   (4) 8   v
2   32  (8) 2

当不再可能合并时,移动结束,所有“合并”标记都被删除,我们等待下一轮。这种方法解决了您的多重合并问题。

扫描方向的另一个示例(数字现在表示循环将如何通过字段):

Player move
    ---->
4   3   2   1
8   7   6   5
12  11  10  9
16  15  14  13

关于您的代码

查看代码,人们注意到您的循环有很多代码重复。对于每一个case你都做一个单独的嵌套for循环,这并不是最佳的。相反,您可能可以执行以下操作:

for i := 1; i < height; i++ {
    for j := 0; j < width; j++ {
        if board[i][j] == 0 {
            continue
        }

        switch input {
            case "d":
                updateBoardDown(board, i, j)
            case "u":
                updateBoardUp(board, i, j)

            [...]
        }
    }
}
于 2014-04-09T10:19:08.523 回答