DEV Community

Lucian (LKB)
Lucian (LKB)

Posted on Edited on Originally published at lkforge.com

How an AI actually beats 2048 (expectimax, not an LLM)

Every number in this post comes from our own re-runnable 250-game self-play benchmark. Nothing here is estimated.

Updated September 2026: the solver was reworked to expand every tile spawn with probability-threshold pruning plus a transposition table, following Robert Xiao's canonical 2048 AI (nneonneo). It now reaches 2048 in 92.8% of games (up from ~70%), and the sections below describe the current build.

If you've ever asked "are there any AI tools that can actually beat 2048?", the answer is yes — and the interesting part is which kind of AI does it. It is not a language model. A 2048-solving AI is a small, deterministic search algorithm you can run in a browser tab with no network calls. Here is exactly how one works, and where it hits its ceiling.

Why not an LLM?

You could paste the board into a chat model and ask for a move. It will often give you a plausible one — and sometimes an illegal or losing one — because a language model predicts the next tokens of text, not the next move of a game tree. Winning a game of chance is a search problem, and we already have an exact algorithm for it.

Game-tree search A language model
How a move is chosen Search the tree, return a specific legal move Predict tokens; the "move" is whatever it writes
Determinism Same board → same move, every time Sampling is probabilistic
Latency A couple of milliseconds, on your device An API round-trip
Cost / offline Free, offline, no key Hosted or paid API

The core idea: expectimax

2048 is a game against chance — you pick a direction, then the game drops a random tile (a 2 with 90% probability, a 4 with 10%) on a random empty square. The right tool is expectimax search, a tree that alternates two layer types:

  • On a max layer the AI tries all four moves and keeps the best.
  • On a chance layer it considers every square a new tile could land on and averages the outcomes, weighted by probability.

By looking several layers deep, it picks the move whose likely future is strongest — accounting for unlucky spawns instead of grabbing whatever looks good right now.

Why not minimax? Minimax assumes an adversary playing the worst tile against you. But 2048's tiles are random, not malicious. Averaging over outcomes (expectimax) models the real game; minimax would play far too defensively. This is the textbook split — minimax for chess, expectimax for games against nature.

The heuristic: scoring a board

Search needs a way to score a board it can't play all the way out. The whole evaluation is three terms:

score = positional + empties × 200000 + smoothness × 4000
Enter fullscreen mode Exit fullscreen mode
  • Positional (corner-snake) — each square has a fixed rank; a tile's value is multiplied by 4^rank. Because the weights grow as powers of four, one big tile in the corner dominates everything, so the search is rewarded for stacking value toward that corner in snake order.
  • Empty squares — every blank cell is worth a flat 200000. Empty space is what keeps future moves legal, so a nearly-full board scores as almost worthless no matter how large its tiles.
  • Smoothness — for each pair of neighbours, subtract |log2(a) − log2(b)|. Mergeable neighbours cost almost nothing; a 2 next to a 512 is punished. Jagged boards score lower.

Keeping full expansion fast

The chance layer is where the cost explodes: every empty cell is a place two different tiles could appear. The solver keeps that in check without cutting corners on accuracy:

  • Full, deterministic expansion. It expands every empty square (a 2 at 90%, a 4 at 10%) rather than sampling a few at random, so the same board always yields the same move and a seeded run reproduces exactly.
  • Probability-threshold pruning. Each branch carries the cumulative probability of reaching it. Once that drops below 0.0001, the line is scored statically instead of expanded. Wide-open boards splinter into low-probability branches that prune themselves shallow; tight boards with few empties are searched deep — exactly where mistakes are fatal.
  • A transposition table. The same position can be reached by different move orders, so scored boards are cached (keyed on the board, guarded by depth) and reused within each turn's search.
  • Adaptive depth. More than 8 empties → depth 4, more than 4 → 5, more than 2 → 6, otherwise 7.

Together that costs about 1.8 ms per move on a laptop — still instant enough to watch live.

How well does it actually play?

We ran the exact search code headless for 250 full games:

Who / what Top tile Notes
Theoretical maximum 131,072 Absolute ceiling on a 4×4 board
Best research AI (2025) 65,536 Reached ~8.4% of games; median score ~820,000
This browser solver 8,192 10.8% of games; reaches 2048 92.8% and 4096 64% of the time
Most human players 2,048 The original win condition

So an expectimax solver with full expansion clears the 2048 win condition in about 93% of games, pushes to 4096 in about two-thirds, and reaches 8192 in roughly one game in nine — 16384 has never been reached in testing. A second, seeded 250-game run landed at 92.8% / 65.6% / 12.8%, the same picture within sampling error. The state-of-the-art research AIs (expectiminimax plus endgame tablebases) go three doublings higher, to 65,536, but even they hit that only ~8% of the time. The theoretical 131,072 ceiling is never reached in normal play.

What caps this one is not the search design but two live-speed knobs — the depth cap and the pruning threshold. Offline record-setters push both much harder and spend far longer per move.

Try it / reproduce it

You can watch this exact solver run by turning on Autoplay in the free browser game at lkforge.com/games/2048 — no install, no account, runs entirely on your device. The full heuristic breakdown and the benchmark methodology are in the original write-up.

To reproduce the numbers, the shipped engine and its seeded selfPlayGame harness are public in solver-core.js, and you can run the benchmark in your browser.

If you want to build your own: implement expectimax at depth 3–5 with the three-term heuristic above, then add full chance expansion with a probability cutoff and a transposition table — that combination is what took this solver from ~70% to over 90%. Run a few hundred self-play games to measure your own reach rates. The whole thing fits in a couple hundred lines of JavaScript.

Top comments (0)