7 min readfrom Machine Learning

Building a 9-ball AI player: Candidate generation for direct cut shots [P]

Our take

Building a 9-ball AI player involves creating a sophisticated system for candidate shot generation, particularly for direct cut shots. The model assesses potential shots based on the probability of success and the resulting position for subsequent plays. Key components include a transformer-based model to evaluate winning probabilities, a diverse candidate shot generator, and an efficient evaluator. By leveraging the pooltool library for physics simulations, I enhance shot selection through pre-computed lookups and a throw model, dramatically improving evaluation speed.
Building a 9-ball AI player: Candidate generation for direct cut shots [P]

Our take

The 9‑ball AI effort described by ArithmosDev is more than a clever hack for a niche sport; it illustrates how a disciplined blend of physics simulation, data‑driven inference, and curriculum learning can reshape any domain where sequential decision‑making meets real‑world uncertainty. By first grounding the problem in a high‑fidelity pool physics engine (Pooltool) and then engineering a layered approximation pipeline, the author shows how to turn a computationally intractable search into a tractable, data‑rich workflow. This mirrors the broader trend we explore in How AI Agents Will Transform Data Science Work in 2026, where the key to scaling AI lies not in raw compute alone but in clever pre‑computation and model‑based shortcuts that preserve fidelity while slashing latency.

At the heart of the system is a three‑stage candidate generation strategy. First, an acceptance‑window lookup pre‑computes the range of object‑ball departure angles that will land a ball in a given pocket at a specific speed, effectively encoding the geometry of the table and the “down‑the‑rail” effect into a fast, reusable data structure. Next, a shot‑index table maps those geometric requirements to discrete cue‑ball parameters, providing a solid starting point for each candidate. Finally, a lightweight multilayer perceptron (the “throw model”) generalizes across the gaps left by discretization, delivering continuous‑space predictions of cue‑ball deviation with sub‑degree accuracy. The result is a 10,000‑fold speedup over brute‑force simulation, allowing batches of a thousand candidate shots to be evaluated in a single millisecond on a GPU. This dramatic acceleration is what makes self‑play data generation feasible at the scale required to train a reliable p(win) model.

Why does this matter beyond the felt‑covered table? The approach demonstrates a practical pathway for any AI system that must evaluate a massive combinatorial action space under strict time constraints. By separating “what the world must do” from “how to make it happen,” the pipeline isolates the physics‑heavy component into an offline lookup and relegates the remaining inference to a small, trainable network. This mirrors the architecture of modern autonomous‑driving stacks, where high‑resolution maps provide static constraints and learned models handle dynamic control. For spreadsheet‑centric AI, a similar separation could let a transformer predict the probability of a desired outcome while a lightweight evaluator rapidly checks feasibility against business rules, dramatically improving responsiveness without sacrificing accuracy.

The editorial also highlights a disciplined training regimen: the author employs curriculum learning, beginning with single‑ball scenarios where the win condition is trivial, then progressively adding complexity up to full‑rack play. This mirrors the incremental skill acquisition seen in human coaching and in reinforcement‑learning curricula that start with simplified environments before exposing agents to the full state space. The use of symmetry to augment data—mirroring shots left‑right and exploiting rotational invariance—further illustrates how domain knowledge can amplify data efficiency, a lesson that directly applies to data‑centric AI tools where table structures often contain built‑in redundancies.

Looking ahead, the most exciting frontier is the integration of safety and execution robustness into the selection loop. The author already clusters candidate shots and validates only representative members with noisy physics simulations, avoiding the trap of “perfect‑on‑paper” shots that cannot be reproduced by a human hand. Extending this idea, future systems could incorporate user‑specific execution profiles, dynamically adapting the candidate set to individual skill levels—a concept that could transform how AI assistants propose spreadsheet formulas or data visualizations, ensuring suggestions are not only optimal on paper but also practical for the end user.

In sum, ArithmosDev’s work offers a concrete blueprint for building AI agents that balance deep physical insight with scalable inference. As we continue to embed AI into everyday productivity tools, the question becomes: how many other domains can benefit from this “pre‑compute, index, then lightly learn” pattern, and what new user experiences will emerge when AI can evaluate thousands of nuanced options in the blink of an eye?

Building a 9-ball AI player: Candidate generation for direct cut shots [P]

I'm building a 9-ball-player to help with pattern play. There are many ways to make the next ball, and sometimes in more than one obvious pocket. Which should should you choose depends on probability of making that shot AND ending up in a favorable spot for the next shot, that is also amenable to getting good position for the shot after. To that end, I have built the following components:

  • A transformer based model that learns p(win) given a table layout.
  • Candidate shot generator that includes cut shots, bank shots, kick shots, caroms and combination shots as well as safeties.
  • An evaluator that will pick the best shots based on the p(win) model on the resulting state of each candidate shot.

The ground truth: pooltool

Pool physics is well-modeled but expensive. I use pooltool python library, a solid open-source billiards simulator with accurate ball-cushion-pocket-felt interactions. A single shot takes ~5–15 ms to simulate end-to-end on one CPU thread for the typical 1–3 object-ball layouts that come up in shot evaluation; full racks (9 object balls) push that to ~20–50 ms because there are more pairwise collisions to track.

Sounds fast until you do the math. For each layout I want candidate shots into 6 pockets, and each pocket has a 5-dimensional parameter space to search: speed, aim angle, elevation of cue stick, side spin, follow/draw.

A naive grid sweep over even a coarse 10 steps per dimension is 100K combinations × 10 ms = ~17 minutes per pocket per decision. Iterative optimizers like CMA-ES bring that down to ~500–1000 sims per pocket, but that's still ~5–10 seconds per pocket, ~30–60 seconds per layout. For training a value network with millions of decisions, that's months of compute.

Faster evaluation of candidates

The shot selection needs to know if the shot will go without simulating every possible shot. But we don't need the final position of the table just yet.

I approached the problem by splitting the shot into what the object ball needs to do and how to hit the cue ball to accomplish that. So the first component for shot making is an Acceptance window lookup. It is pre-computed offline per (object ball position, pocket, speed): the range of OB (object ball)-departure angles that actually drop the ball at different speeds into the selected pocket. This is the "what does the ball need to do" specification; it captures the pocket jaw geometry, the down-the-rail effect, all of it.

Then I created a Shot-index lookup table. Given the desired OB-departure angle (measured as deflection from the cue-to-OB line) and the cue-to-OB distance, look up shots that produce that geometry from a pre-computed index using no elevation shots simulated using pooltool sampled on a discrete grid of (distance, speed, aim-offset, spin, draw) keyed by OB departure angle. Lookup returns candidate (speed, aim_offset, spin, draw) tuples that send the OB in the desired angle (distance is fixed by the layout).

That was an improvement but it has holes due to discretization. To cover these holes, I built a throw model for continuous space generalization. It is a small MLP to predict OB-departure deviation given (cue→OB distance, speed, aim angle, spin, draw, elevation). It generalizes the shot-index data into the continuous space. Architecture is fairly straightforward. The features are aim_offset, distance, speed, side spin, draw and elevation. Output is deviation from cue-object ball angle. It has 4 hidden layers with 128 dimensions for hidden layers, ReLU activation, ~50k parameters in total. I trained the model over 5M shots (took about 6 hours to generate) and measured the Mean Angle Error over the validation set (~1.1M) which was around 0.2 degrees. I also used the left/right symmetry for the model to use 2x the data so I don't have to worry about taking care of mirroring during play.

The beauty of it is that, I can use the shot index to get decent starting parameter set for shots and apply small perturbations across different parameters and evaluate them in a batch using the throw model on a GPU really fast. Speed up in my setup was around 10000x compared to simulating all those shots through the physics engine which makes a world of difference in generating enough self play data. Batch of 1000 candidate shots takes 1 ms to evaluate. Compare that to 1000 simulations x 10 ms on average.

I then cluster all the shots that are predicted to fall within the acceptance window of the intended pocket using bucketing around speed, spin and draw. I evaluate representatives from each cluster using the physics engine using noisy simulation that adds execution noise to the shots. We don't want to find that 1-in-a-million shot that can't be executed reliably. Then I use the maximum expected value of the table state after the shot using the p(win) model (which I did not go into in this post) for shot selection.

Given I still do physics simulations once I find my candidates, the end-to-end speedup was around 50-100x.

Shot selection visualization

To make things more concrete, I set up a 8-9 ball layout where cue ball is in the center of the table, 8 ball is towards the top left and 9 ball is at the bottom rail. The colors represent p(win) given the 9-ball position (provided 9-ball is not moved during the shot). For this post, I simulated the selected 10 shots 20 times. 6/10 shots made all 20, 3 of them 19/20 and 1 of them 15/20. Colors of the cue ball paths reflect the make rate on those 20 shots. I only plotted one of the 20 noisy sims for each of the 10, others will end up pretty close.

The black region around the 9-ball is all less than 1 ball away from the 9-ball and represents invalid positions for the cue ball as it would infringe on the 9-ball space.

In this post I only talked about direct shots but I do have templated bank shots, kick shots, carom and combination shots as well that is baked into the p(win) heatmap plot - obviously carom and combination shots don't apply here for the 9-ball only case.

What's next?

I'm working on curriculum learning. P(win) model using only the 9-ball is straightforward: pocket the 9 and you win (if you don't scratch). If you scratch, you lose since any half decent opponent will make the 9-ball with a ball in hand. If you miss, the reward is (1-p(win)) from the resulting state. I have simulated ~100k shots with full shot selection options and used 4x symmetry for the p(win) model. I re-do the shot selection for any shot that's not 100% make as my model updates and could lead to different shot selection / safety positions.

Once the single ball scenario is "solved", I'll move to 2 ball scenarios where making the on-ball results in a solved state where we look up the value from the model. Misses gets re-evaluated between iterations of the model. I'll advance the curriculum as it masters <n ball scenarios and master n ball setups all the way up to 9.

Tried lots of things that didn't work. For example, bank model improved quite a bit when i gave it the ghost pocket angle (based on mirroring) as a feature (physics informed ML). Happy to share details about any of it if there's interest.

submitted by /u/ArithmosDev
[link] [comments]

Read on the original site

Open the publisher's page for the full experience

View original article

Tagged with

#generative AI for data analysis#Excel alternatives for data analysis#natural language processing for spreadsheets#no-code spreadsheet solutions#financial modeling with spreadsheets#intelligent data visualization#data visualization tools#big data management in spreadsheets#conversational data analysis#cloud-based spreadsheet applications#real-time data collaboration#enterprise data management#big data performance#data analysis tools#data cleaning solutions#AI formula generation techniques#rows.com#self-service analytics tools#machine learning in spreadsheet applications#formula generator