This post was originally released in two parts and since combined into one.
The final outcome of this project is a CLI tool written in NodeJS. The user is prompted to provide a list of Site cards from the game Sorcery: Contested Realm alongside two parameters. The app returns the probability of success given the list and parameters, with options for both simulated and calculated probabilities for comparison. To use an analogy, the app answers the following question: given a deck of playing cards, what would be the probability you would see at least one heart in a draw of three?
Sorcery Threshold Calculator, the most simple use case
Sorcery
Lately I have been playing a collectible card game called Sorcery: Contested Realm. I have heard it described as "Magic the Gathering x Chess". In a game of Sorcery, a player has two decks. One of these decks is called the Atlas, and is comprised of thirty cards called Sites. During the course of the game, a player will draw these Sites and play them to the board. Sites passively grant affinity to one (or more) elements: Earth, Air, Fire, and Water. In order to cast a spell, you must meet its elemental threshold by having the corresponding number of symbols represented on the board.
As I learned to play the game I wondered a question that would kick this entire project off: what were the chances I could reliably play a certain spell on turn four? As is often the case, my ignorance of the complexity of this question was my bliss.
How It Works
An admission: I am not a mathematically-minded human. I knew from the start that if I attempted to learn the math behind this problem, I'd always have doubts about whether it was accurate or not. I needed a way to corroborate the calculations, so I opted to start by writing a simulation.
Monte Carlo
The name for this approach is a Monte Carlo Simulation, and thankfully, it was much easier to reason about than the later math. The simulation sets up the Atlas deck as an array, and randomly chooses N numbers (where N is the draw count). Those random numbers are used to select cards from the array, and the selection is checked against the criteria. Number of successes divided by the number of iterations gives the simulated probability.
Running a simulation instead of calculation
Calculating...
Hang around competitive Magic the Gathering players long enough and the term "hypergeo" might come up. A multivariate hypergeometric distribution is the fancy name given to the math needed to answer this type of problem. It is a giant equation that boils down to the following question: for every unique combination of cards drawn that satisfy the criteria, what is the probability of drawing that exact combination?
That single probability is cumulatively added along with every other unique combination to arrive at the final probability. Finding all of those combinations is the hard part.
Generating Combinations
The core of the application is in generating all of the combinations needed to feed the hypergeometric calculation. I settled on a recursive walk of the card array, testing each combination as it went. I settled on using a 'pointer' array to track which combination of cards was being looked at, a task made difficult by the variable number of cards being drawn. The recursive function calls itself over and over, passing in the accumulated data from the previous run until it meets the exit condition.
Humorously, I hit a developer milestone: the Stack Overflow. Node has a built-in stack limit that I was blowing through with the sheer number of possible combinations, and so I had to add a way to clear the stack during the recursion to continue. And on that day I earned my badge as a Real Developer.
The End?
I started this project back in June of 2025 with an imperfect first attempt. After a break I revisited it, refining the original version into the current 2.0. Funny enough, I rarely use it for my actual constructed Sorcery decks, but every now and then I run it against my list to get an idea of what I can expect on game day. To my knowledge there aren't tools catered to Sorcery like there are Magic the Gathering, yet; perhaps v3.0 will be a web app for others to use.
In the meantime, if you're interested, feel free to browse the Github page and try it for yourself!