Build 01
Gacha Pull Planner
Relates to any system that reports a result and expects the person to figure out the next move alone: dashboards, analytics tools, monitoring platforms. The harder, more useful version doesn't just tell someone where they stand, it tells them what changed and what to do about it.
A gacha probability simulator can tell someone their odds. That's the easy part, run the Monte Carlo simulation, report the numbers. What it usually can't tell them is what to actually do with those odds. Given where they stand right now, is a different strategy worth switching to, and what would that switch actually change? A raw probability output answers "what are my chances," not "what should I do next," and those are fundamentally different questions.
A full-stack tool. A backend running Monte Carlo simulations over configurable pull strategies and parameters, with a React frontend for interacting with it, along with an AI agent for scenario planning and interpreting results.
- Simulation engine, modeling pull outcomes across strategies with adjustable parameters rather than fixed presets
- Visualization for how each run went
- Stats for both successful runs and failed runs, showing what the runs had in common
- An overall deterministic, non-AI read on the statistics


- Run comparison, letting a user change a parameter and see the result against their prior run rather than a fresh, disconnected number

The simulation answers the question "What are my odds?" and the comparison answers "How big of an impact do the budget and goal levers change my odds?", but I would argue the harder question is in asking "How can I make sense of my odds as the situation unfolds?"
This meant that I had to come up with a way to parse the user's complex and sometimes branching requests into a common language that could be deterministically parsed and calculated. The result leveraged my university experience in compilers with abstract syntax trees for parsing grammar.
- A structured extraction schema, the shared structure between a free-text question and the deterministic layer beneath it. An LLM call reports facts into this schema; it never does the math itself.
- Fuzzy language, normalized to fields, since gacha phrasing for the same fact varies too much to hardcode: "won at 30 pity" names the pity counter itself, "won after 50 pulls" names pulls spent this run, and a "character copy" gets called five different things depending on the game and the player. The model's only job is reading intent into the right field.
- Deterministic reconciliation, a plain function, not a model, that checks every extracted fact and calculated result against the parameters defined in Advanced Settings and asks a clarifying question the moment the math doesn't add up, rather than guessing past it
Parsing an initial input of 100 starting pulls, 22 previous pulls (pity) already used, and the user input stating
"I won the character banner after 82 pulls, should I continue on with pulling on the weapon banner?"
and a system-prompted clarification request resulting in a confirmation that 82 pity was reached, not 82 additional pulls (infeasible given current setting parameters). Calculating the number of pulls leftover in order to run simulations is as follows:


A second situation or beyond means a second, separate tree, never a branch grafted onto this one. Each represents its own potential path to calculate, as the user intends on running hypothetical "what if" scenarios in order to compare and plan ahead.
Parsing an initial input of 150 starting pulls, 15 previous pulls on the character banner, 8 previous pulls on the weapon banner, and the user input stating
"If I pull for the character and win at early pity around 30, I want to go for another copy of the character and then the weapon. If I lose at soft pity around 75, is it worth still getting the weapon after the character? What are my odds for each?"
Branching (2x) due to hypothetical scenario detected, two trees and two lines of calculation for number of pulls leftover and executing the simulation for resulting odds are required:
Parsed Scenario 1
Parsed Scenario 2

- User-adjustable advanced settings, originally hardcoded, later exposed as configurable parameters to make the app game-agnostic
The first version of this advisor read a single simulation result and explained it in prose. That was solving the wrong problem. Users don't get stuck reading a percentage, they get stuck describing what actually happened to them in a way that stays trustworthy once it hits the math.
My core product sense is: A number by itself isn't an answer. The answer is what changed, and what that means for what to do next.
So the model's authority got narrowed, not widened. It does what it does best: fuzzy interpretation. It sorts out the many ways to refer to the same concept and it asks the user for clarity when an ambiguous interpretation arises. It ultimately gets information extracted into a deterministic structure, at which point calculation is a trivial problem.
Every number after that, the running pull total, whether a claim fits the banner's actual pity ceiling, the odds at each spending tier, comes from a deterministic function or is a simulation run that agent has the authority to call. This way, there is no chance of producing a hand-wavy result that tends towards purchasing more pulls to increase the odds by an unknown degree. There are clear tools to use and clear answers we can obtain and present to the user to entrust them with their own decisions.
I built the simulation, the reconciliation logic, and the extraction schema myself. For the frontend, I wrote specs and technical contracts and directed Claude Code to implement against them, reviewing and modifying the output rather than accepting it as delivered.
Reporting a result is the beginning of the problem, not the end of it. Any system that hands someone a number, a score, a probability, a status, faces the same next question. Compared to what, and what should change because of it. The useful version of an AI-assisted tool isn't the one that describes state most accurately. It's the one that helps someone decide what to do differently.
I used the same instinct, don't just report the current state, surface what changed and what it implies, in the Data SITREP, which tracks entities over time and flags drift rather than showing a snapshot.
The same boundary matters anywhere a model sits next to a system that has to stay correct: let it extract and normalize language, never let it compute or decide. I drew that same line in document automation's deterministic validation layer, keeping the model responsible for reading, never for the numbers underneath it.