An IDA*-based solver and terminal visualizer for the BrainBall, a spherical rotation puzzle with 13 numbered, two-colored tiles.
The BrainBall is a ball with 13 tiles, numbered 1 to 13, arranged in a single ring around its circumference. Every tile is either white or yellow. The puzzle starts solved (all tiles white, in order 1-13) and is scrambled by repeatedly performing one of two physical moves:
-
180° flip (
turn180) - the whole ball is turned inside out. Every one of the 13 tiles changes color (white becomes yellow and vice versa), and the ring's direction reverses (clockwise becomes counter-clockwise). -
Side turn (
turnSides(index)) - the ball contains an axis in the middle. You can turn the tiles around and place specific tiles on this axis. Now the ball is rotated around this axis that runs through one specific tile. This axis splits the remaining 12 tiles into two arcs on either side: a 3-tile arc centered on the chosen tile, and, on the opposite side of the ball, a 4-tile arc. Turning the ball around this axis reverses the order of each arc internally and flips the color of every tile in both arcs (7 tiles in total: 3 + 4). The tile the axis passes through does not move position, but it does still flip color.
The goal is to get all 13 tiles back to white, in their original numerical order.
Because a turnSides move can leave the ball with fewer white tiles
facing up than yellow ones, this solver always normalizes the ball back
to the "white majority up" orientation with an extra turn180() whenever
that happens - both at the very start of the search and after every move
during the search. That is a bookkeeping/search convenience, not a move
you need to make on the physical ball; the visualizer shows it as its own
separate step so it is never confused with an actual side turn.
The solver uses IDA* (Iterative Deepening A*): a depth-first search
that repeatedly re-runs itself with an increasing cost threshold, only
exploring branches whose estimated total cost (f = g + h) is within
that threshold. Compared to plain BFS/DFS this keeps memory usage low
(no huge open/closed lists) while still finding a shortest solution,
provided the heuristic h never overestimates the true remaining cost
("admissible").
Two things make this tractable for a puzzle with a branching factor of 13 (13 possible side-turns from every position):
-
Reverse-move pruning. A state never immediately re-applies the
turnSidesindex that was just used to reach it. This is not a correctness requirement, just a pruning heuristic that cuts the effective branching factor from 13 to 12 and avoids the search wasting time undoing its own last move. -
Pattern database heuristic. Before solving, the solver runs one backward breadth-first search starting from the solved configuration, up to 6 moves deep, recording the exact number of moves back to the goal for every state it reaches (a few million states, easily fits in memory). During the main search, whenever the current state is found in this database, that exact distance is used as
hinstead of an estimate - this is far more informative than any simple formula and is what makes the last few moves of the search fast. For states outside the database's reach, a cheap fallback estimate is used instead:(misplaced colors + misplaced tile numbers) / 7, divided by 7 because a single move can affect at most 7 tiles at once (this keeps the estimate admissible, i.e. it never overestimates).
src/
logic/
BrainBallColor.java - the WHITE/YELLOW enum
BrainBallTile.java - a single numbered, colored tile
BrainBallState.java - one ring configuration + the two moves
BrainBallSolver.java - the IDA* search + pattern database
SolveResult.java - solver output (path, flags) for the UI
ui/
BrainBallConsoleRenderer.java - draws the ball as a circle in the
terminal and narrates each step
app/
Main.java - demo entry point: scrambles a ball, solves
it, prints the solution
Requires a JDK (17+). From the src/ directory:
javac -d out $(find . -name "*.java")
java -cp out app.MainThe terminal needs ANSI color support (any modern terminal / IntelliJ's run console / VS Code's integrated terminal all work) to show the white/yellow tile backgrounds correctly.
Each step is printed as a circle of the 13 tiles, tile number on a background matching its color, with the tiles affected by the current move shown in bold:
(exact layout depends on your terminal's font)

