First your merging problem
Currently you're always scanning your tiles top-to-bottom and left-to-right, independently of the player's move. For 2048, however, it is preferable to scan in the opposite direction of the player's move, since tiles will only be merged in that direction. For example, let's take the following scenario:
0 0 2 0 |
0 0 2 2 | Player move
0 2 4 8 v
2 32 4 2
Let's assume the player's move direction is towards the bottom, so we start scanning from the bottom towards the top. In the third column, we'd need to first merge 4+4 and then 2+2, i.e. bottom-to-top. Going in that direction allows you to merge 4+4 and then mark the bottom-most field of the column as merged, thus not allowing further merges (indicated by the parentheses around the number):
0 0 0 0 |
0 0 2 2 | Player move
0 2 2 8 v
2 32 (8) 2
After merging the bottom-most cells (if possible), we proceed with the cells above and so on...
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
When no more merges are possible the move ends and all "merged" markers are removed and we wait for the next turn. This approach fixes your multiple-merge problem.
Another example for the scan direction (numbers now represent how a loop would run through the fields):
Player move
---->
4 3 2 1
8 7 6 5
12 11 10 9
16 15 14 13
About your code
Looking at the code, one notices that there is lots of code duplication regarding your loops. For each case
you do a separate nested for
-loop, which is not really optimal. Instead, you might be able to do something like this:
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)
[...]
}
}
}