2048 Solver
github.com
github.com
Secondly, the implementation doesn't perform the combination of current state score and proposed state score that lies at the heart of the A* algorithm. Instead it takes the current state for granted (which, again, it must given the inability to backtrack) and chooses the available move with the largest score.
Thirdly, and I'm reaching a little here, I can't find any place where any heuristic is used to optimize search performance by pruning the search tree. The search space is brute forced on each iteration, and the entire tree is scored.
At the expense of seeming pedantic I suggest this is a greedy play algorithm rather than A*. You can be even more precise and call it a single-ply minimax.
Now that that's out of the way, I should temper my criticism with the fact that this implementation works. It's not algorithmically complicated because it doesn't have to be. It doesn't use any of the typical performance tricks because it doesn't need to. What it lacks in sophistication it makes up in "good enough."
Only reach 8192, but with the game implemented in the right way :)
https://github.com/loisaidasam/2048
Essentially it communicates via an API to a webserver where you write your "brain" logic and respond to the API requests with which move to choose next:
https://github.com/loisaidasam/2048/blob/master/js/autonomou...
Since it's over web, you can write your webserver in the language of your choosing. I wrote a small dumb Python webserver using the Flask microframework:
https://github.com/loisaidasam/2048/blob/master/py/webserver...
And it simply returns a random direction:
https://github.com/loisaidasam/2048/blob/master/py/game.py
This can be adapted obviously for whatever logic you choose. The reason I forked this version and not a totally server-side one (which would be better for performance obviously) is that you can actually watch the moves this one makes as it chooses them, which makes it kinda fun.
Enjoy!
With that said, this Java implementation needs a lot of performance improvement. I made some trivial changes on it and benchmarked it at a significant speed boost, I'll send you my revisions on GitHub so you can take a look. Also, as another commenter mentioned, this isn't true A*, but good work nonetheless.
Here's a simple performance improvement: Java's ArrayList is just a wrapped array with two fields:
private transient Object[] elementData;
private int size;
When you initialize it, it initializes elementData to a null array of size of 10. When you put the 11th thing into the list, it creates a new array of size 15 (in general, a 50% increase), and copies references from the old array. This means that in your search, a board with 11 or more open tiles will trigger a resize. This is easily prevented by initializing the list with new ArrayList <Tile> (15)
Bam! One optional parameter, 9% runtime improvement. As the performance gets optimized you can search larger trees in less time.Question that I didn't understand the answer to:
> There are implemented 3 cost functions:
> 1. sum of all tiles in the playing field
is this a useful cost function at all? Surely the sum of the tiles is not affected by strategy played, only by whether a 2 or 4 was randomly received.
> 2. number of all unassigned tiles in the playing field
> 3. average value of an occupied tile
Then, for similar reason, I would be surprised if these were not equivalent.
So in the end you are right these approaches are more or less the same.
Each individual decision is simple (choose from 4 directions), but the overall strategy is difficult (the arrival of each new piece has a random element).
The game tree[0] is awkward to draw in full, because of this random element. If we can draw it out well enough to analyse it, we can come up with a perfect play algorithm that wins as often as possible. Tic-tac-toe is 'solved' in this sense: we always know what the best play is.
Since 2048 remains unsolved (for now), AI algorithms which simplify and try to approximate that process come into play. As long as nobody has come up with perfect play, it's still interesting to see who can come up with the best play.
2048 is relatively simple game to remain unsolved, so it's nice and accessible to apply algorithms to (and still relevant to do so).
2, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
You could theoretically beat that if you happened to get a 4 just when you needed it (starting with 4, 4, 8, 16, etc.)
So I think it can win all games?