My post on probabilities of Marvel Heroic Roleplaying dice pools has gotten a lot of attention, so I’ve decided to share some code that can be used to compute the expected results of dice pools for Cortex+ games. The code is in C# and was written as a very basic console application that prints out the results for a hard-coded set of dice (I was too lazy to add command line support since I had originally intended the code to be a throwaway project that I was just using to crunch numbers while writing the mixed dice pools post).
Here’s the code:
using System; using System.Collections.Generic; namespace CortexPlusMath { class Program { static void Main(string[] args) { // Captain America: // Solo, Enhanced Strength, Weapon, Combat Master int[] dice = { 6, 8, 8, 10 }; //int[] dice = { 6, 8, 8, 10, 4 }; //int[] dice = { 6, 8, 8, 10, 8 }; //int[] dice = { 6, 8, 10, 10 }; double average = ComputeAverageResult(dice); double meanComplications = ComputeAverageComplications(dice); double chanceOfComplication = ComputeChanceOfComplications(dice); double averageEffectDie = ComputeAverageEffectDie(dice); string diceString = ""; foreach (int d in dice) { diceString += "d" + d.ToString() + " "; } Console.WriteLine("Cortex+ Average"); Console.WriteLine(" Dice Pool: " + diceString); Console.WriteLine(" Average Result: " + average.ToString()); Console.WriteLine(" Average Effect Die: " + averageEffectDie.ToString()); Console.WriteLine(" Average Number of Complications: " + meanComplications.ToString()); Console.WriteLine(" Probability of 1+ Complications: " + chanceOfComplication.ToString()); } static private List GetResultsTable(int[] dice) { List possibleResults = new List(); foreach (int sides in dice) { List clonedResults = new List(); if (possibleResults.Count == 0) { for (int i = 1; i <= sides; i++) { DicePool newPool = new DicePool(); newPool.AddDieRoll(new DieRoll(sides, i)); clonedResults.Add(newPool); } } else { for (int i = 1; i <= sides; i++) { foreach (DicePool oldPool in possibleResults) { DicePool newPool = oldPool.Clone(); newPool.AddDieRoll(new DieRoll(sides, i)); clonedResults.Add(newPool); } } } possibleResults = clonedResults; } return possibleResults; } static double ComputeAverageResult(int[] dice) { List possibleResults = GetResultsTable(dice); int possibilities = possibleResults.Count; int total = 0; foreach (DicePool result in possibleResults) { total += result.GetResult(); } double average = (double)total / (double)possibilities; return average; } static double ComputeAverageComplications(int[] dice) { List possibleResults = GetResultsTable(dice); int possibilities = possibleResults.Count; int total = 0; foreach (DicePool result in possibleResults) { total += result.GetComplications(); } double average = (double)total / (double)possibilities; return average; } static double ComputeChanceOfComplications(int[] dice) { List possibleResults = GetResultsTable(dice); int possibilities = possibleResults.Count; int total = 0; foreach (DicePool result in possibleResults) { if (result.GetComplications() > 0) { total++; } } double probability = (double)total / (double)possibilities; return probability; } static double ComputeAverageEffectDie(int[] dice) { List possibleResults = GetResultsTable(dice); int possibilities = possibleResults.Count; int total = 0; foreach (DicePool result in possibleResults) { total += result.GetEffectDie(); } double average = (double)total / (double)possibilities; return average; } } class DieRoll { public DieRoll(int sides) { Sides = sides; Randomize(); } public DieRoll(int sides, int result) { Sides = sides; Result = result; } public int Sides { get; set; } public int Result { get; set; } public void Randomize() { Result = s_rand.Next(1, Sides + 1); } private static Random s_rand = new Random(); } class DieRollComparer : IComparer { public int Compare(DieRoll x, DieRoll y) { if (x.Result > y.Result) { return -1; } else if (x.Result < y.Result) { return 1; } else { if (x.Sides < y.Sides) { return -1; } else if (x.Sides > y.Sides) { return 1; } else { return 0; } } } } class DicePool { public DicePool() { _dice = new List(); } public void AddDie(int sides) { DieRoll roll = new DieRoll(sides); _dice.Add(roll); } public void AddDieRoll(DieRoll roll) { _dice.Add(roll); } public int GetResult() { SortDice(); if (_dice.Count >= 2) { int result = 0; if (_dice[0].Result != 1) { result += _dice[0].Result; } if (_dice[1].Result != 1) { result += _dice[1].Result; } return result; } else if (_dice.Count == 1) { if (_dice[0].Result == 1) { return 0; } else { return _dice[0].Result; } } else { return 0; } } public int GetComplications() { int complications = 0; foreach (DieRoll d in _dice) { if (d.Result == 1) { complications++; } } return complications; } public int GetEffectDie() { SortDice(); if (_dice.Count < 3 || _dice[0].Result == 1 || _dice[1].Result == 1 || _dice[2].Result == 1) { // Default to d4 effect die return 4; } else { List remainingDice = new List(); for (int i = 2; i < _dice.Count; i++) { if (_dice[i].Result != 1) { remainingDice.Add(_dice[i].Sides); } } if (remainingDice.Count >= 2) { remainingDice.Sort(); remainingDice.Reverse(); } return remainingDice[0]; } } public DicePool Clone() { DicePool clone = new DicePool(); foreach (DieRoll d in _dice) { clone._dice.Add(new DieRoll(d.Sides, d.Result)); } return clone; } private void SortDice() { _dice.Sort(new DieRollComparer()); } private List _dice; } }
3 replies on “Cortex+ Dice Pool Helper”
I’m more of a Mathematica/Matlab guy… 😉
I’m ported your program to javascript, and created a nifty web form to assist Cortex+ players:
https://ramblurr.github.io/firefly-rpg-generator/probability.html
Awesome!