Working Through the Sphere Puzzle

The sphere puzzle is one of those things that sounds straightforward until you actually try to solve it programmatically or visually. You have a set of constraints involving spherical objects fitting into a bounded space or aligning to a target configuration, and the naive approaches break down fast. I spent way too many hours on this early in my career before figuring out the actual mechanics. There are really two viable paths here. The brute force simulation method and the geometric constraint approach. Most people start with brute force because it's easier to code, but it hits a wall pretty quickly once you move past three or four spheres. I had a project where we needed to solve for seven spheres in a constrained volume, and the simulation approach took about 14 hours on a single core. That's not acceptable for anything resembling production use. The constraint-based method treats each sphere as a set of equations. Distance between centers must equal the sum of radii for touching spheres, boundaries create hard limits, and any external forces become inequality constraints. You set this up as a system and feed it to an optimizer. I used SLSQP from SciPy in most cases, though COBYLA works better when your constraints are messy or discontinuous. The difference in runtime was roughly six minutes versus two hours for a six-sphere case.

One thing nobody warns you about: when two spheres have nearly identical radii and you're packing them tightly, the optimizer tends to get stuck in local minima. I ran into this on a client project where the spheres were within 0.001 of each other in radius. The solver kept returning slightly overlapping configurations that looked correct numerically but were physically impossible. The workaround was adding a small penalty term to the objective function that explicitly penalized any center-to-center distance below the sum of radii plus a tiny epsilon buffer. Something like 1e-6. It sounds trivial but it made the difference between a solution that held up under verification and one that fell apart when I rendered it.

How to actually implement it

Start by defining your variables clearly. Each sphere needs a center coordinate (x, y, z) and a radius. If the radius is fixed and known, that's one fewer variable per sphere, which helps the optimizer converge faster. Fixed-radius problems typically solve in under three minutes with seven or eight spheres. Variable-radius problems scale much worse because every degree of freedom multiplies the search space. Write the constraint functions before you write the main solver loop. I know that sounds backward, but the constraint definitions will tell you immediately if your problem is over-constrained or under-constrained. I've seen people waste half a day debugging a solver only to realize their constraint equations had a sign error that made the feasible region empty. Put a simple feasibility check in place right away. Run the constraints with a dummy initial guess and see if any of them return violations that are wildly outside numerical tolerance. If they do, your formulation is broken. For the actual implementation, I'd recommend using a library like SciPy's optimize module or, if you're doing this in JavaScript, a library like solvers-js. Python gives you more flexibility for experimentation. The constraint format in SciPy expects dictionaries with a type field ("eq" for equality, "ineq" for inequality) and a fun field pointing to your constraint function. Inequality constraints need to return values greater than or equal to zero, which trips up everyone at least once because the natural mathematical form often gives you less-than-or-equal-to expressions.

Get the Full Details

3d Sphere Puzzle Solution
3d Sphere Puzzle Solution

When Sphere Puzzle Solution breaks down

There are legitimate cases where even the constraint-based approach fails or becomes impractical. Six degrees of freedom per sphere is manageable. Ten or more starts getting expensive unless you have a very good initial guess. And if your spheres have irregular or non-uniform sizes with tight packing requirements, you should consider switching to a dedicated packing algorithm like a Monte Carlo simulated annealing approach. These are slower to set up but handle edge cases much better. Another limitation: the solver assumes perfect arithmetic. Real-world applications involving 3D rendering or physics engines introduce floating-point drift that can make a mathematically valid solution appear invalid visually. Always run a post-solve validation step that checks every pairwise distance against the theoretical minimum. If any pair violates it by more than your tolerance threshold, flag it. I usually set the validation tolerance at 1e-5 for production work, which catches the cases the optimizer misses without being so loose that obvious errors slip through.