I am building a little 2048 WinForms game just for fun.
Note that this is not about a 2048 AI. I am just trying to make a 2048 game that can be played by humans.
I first decided to use 0-17 to represent the tiles. 0 represents an empty tile. 1 represents a 2 tile. 2 represents a 4 tile. 3 represents a 8 tile, and so on.
Then I was thinking about how to calculate the resulting board, given the direction of movement and the board before the move. Here's what I thought about:
- To move up, it's just rotating the board counterclockwise by 90 degrees, move left, then rotate the board back
- To move right, it's just rotating the board clockwise by 180 degrees, move left, then rotate back
- To move down, it's just rotating the board clockwise by 90 degrees, move left, then rotate back.
So I just need to figure out how to calculate the resulting board when the player moves left, then I can just figure out the rest of the directions by rotating the board, move left, and rotating back. I then came p with this quite bizarre algorithm for moving left.
- Convert each of the initial board's integers into characters by adding 96 and casting to
char
. Now a back tick (`) represents an empty tile,a
represents a 2 tile,b
represents a 4 tile, and so on, al the way top
. - Concatenate the characters to form 4 strings, each representing a row of the board.
An example board might look like this:
aa`` ```` ```b ``cb
For each string,
- Remove all the back ticks
- Use the regex (yes I'm using a regex in a 2048 game)
([a-p])\1
and get the first match of the string. - replace the first match with the new tile
- match the rest of the string which hasn't been matched yet until no more matches is found.
- Pad the string to the right if it has fewer than 4 characters.
- Turn each string back to an array of integers by subtracting 96
So this is how I evaluate each row:
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());
}
However, there is a really big problem with my current algorithm. This algorithm only tells me the final result of a move, but I don't know which picture box (I'm using picture boxes to show the tiles) I need to move, how many spaces should each picture box move, and which picture boxes need to show a new image. I really want to not use another solution and I want to just make some changes to my current solution.
Here are the things I need to get from each row (string):
- A
List<(int x, int spaces)>
. Each element represents which tile needs to move (the x coordinate), and how many spaces it should move (spaces
). - A
List<int>
. Each element represents the x coordinates of the tiles which is merged into.
How can I get these information from a row string? Example:
The row string:
`a`a
will produce a list like [(1, 1), (3, 3)]
and another list like [1]
.