Project
Tic Tac Go Perfected
An automated daily solver for Google’s Tic Tac Go, built on verified push-level Sokoban search.
Input
Live puzzle screenshot
Transform
Gemini parse → push-level search → verify
Output
Replayable, verified solution
Evaluation set
340+ boards
Typical solve
Milliseconds
A friend showed me Google's Tic Tac Go, a small daily logic puzzle you're supposed to finish in about two minutes. I spent two months on it. What started as "can I solve today's board automatically?" turned into a browser-automation pipeline, a vision parser, a search problem, a machine-learning experiment, a database, and a scheduled cloud service that publishes a verified solution every day.
The problem
Tic Tac Go gives you a grid with a player, walls, and pieces you can push. You win by forming a line under the puzzle's rules. It looks trivial and is genuinely not: the branching comes from where you move pieces, and the number of reachable board states grows quickly.
I wanted a system that could, unattended: open the live puzzle, read the board, solve it, prove the solution is legal, and let anyone replay it.
My role
I built the product and the deployed system end to end: the site, the browser automation, the vision parsing, the solver, the verification, and the daily cloud job. Abdullah Waris collaborated on the early solver research; he built a beam-search + CNN solver that could take up to ~300 seconds on hard boards, which was a useful baseline and a good foil for the direction I took.
The system
- 01A scheduled job (Vercel Cron) opens Google's live Tic Tac Go puzzle.
- 02Browserless captures the rendered puzzle as an image.
- 03Gemini parses the screenshot into a structured board representation.
- 04The backend selects and runs a solver.
- 05The returned move sequence is independently verified for legality and a win.
- 06The board and solution are stored in Neon (Postgres).
- 07The Next.js site lets anyone view, replay, and browse past days.
The unglamorous half of this project was reliability, not cleverness. Getting a clean, correctly-cropped screenshot of the live board was harder than any single search decision.
NoteWhy the screenshot was the hard part
The capture stack went through three iterations. Local Playwright worked on my machine and nowhere else. A hosted browser (Browserbase) was better but still flaky on the exact crop. I landed on Browserless with an explicit wait for the board to finish rendering before capture. Early attempts grabbed a top-left fragment of the page instead of the puzzle. Only once the image was reliable could Gemini parse it consistently. Vision parsing is only as good as the pixels you hand it.
The solver: from BFS to a Sokoban reframing
The interesting part is how the solver evolved. Each step taught me something the next one used.
Breadth-first search
BFS was the interpretable baseline and gives shortest paths, but its memory footprint became impractical as the state space grew.
A* search
I moved to A* with heuristic prioritization. Better, but large boards still produced enormous search frontiers. The frontier, not the depth, was the enemy.
An early learned ranker
I experimented with a linear tree-ranker to prioritize promising A* branches. The first checked-in model reached about 69.05% holdout top-one accuracy across its decision groups. Useful, but the real lesson was that *representation* mattered more than bolting learning onto the wrong search.
The Sokoban reframing
The insight that changed everything: Tic Tac Go is essentially Sokoban. What matters isn't each individual step you walk; it's the next push that changes the board. So I stopped searching over walking steps and started searching over pushes.
- 01Flood-fill every cell the player can currently reach.
- 02Enumerate the pieces that can legally be pushed from that region.
- 03Treat each legal push as a single search action.
- 04Normalize equivalent player positions so the search doesn't re-explore them.
- 05Search over meaningful board changes rather than individual walking steps.
- 06Reconstruct the exact arrow-key path once a push-level solution is found.
On top of push-level search I layered the usual suspects: transposition keys, conservative deadlock detection, immediate losing-line pruning, candidate winning-line analysis, weighted A* with multiple schedules, macro pushes, bounded beam search, committed target-line plans, memoized reachability, and novelty penalties, plus learned move *ordering*.
Results
Typical successful boards solve in milliseconds across an evaluation set of more than 340 boards.
What I take from it
Sometimes the right solution isn't a bigger model. It's representing the problem at the correct level.
The learned ranker helped. The order-of-magnitude improvement came from changing the state representation and searching pushes instead of individual movements. That's the sentence I'd put on the whole project.
Status
Live and running daily at tictacgo.shauryav.com. Collaborator: Abdullah Waris (early solver research).
Related work
