0

I'm working on a way to display dice statistics like you can see at the site https://anydice.com/ , I've spent a bit looking through the source code but it's pretty thick alltogether so i decided to ask here. Basically, all i need help with is making a function that:

  • Lets you pick a dice with a certain amount sides, for example: 6.
  • Lets you pick how many times you want to roll this dice.
  • Returns the percentages of rolling each possible number with said dice.

I know the question might be a bit shitty, but this is kind of my last resort.

So far, I've tried finding the functions and stumbled upon this medium blog however I was wondering if it could maybe be done with percentages.

ixNoah
  • 21
  • 6
  • This sounds like more Math's stats question than a coding one. Do you understand the reason why 7 is the most popular number with 2 dice?.. – Keith Feb 08 '23 at 13:04
  • @Keith I do, and i agree with your point of this being a bit of a maths question haha. I'll add the tag. I do understand why 7 is the most common, yes. It's just that i'm working on a project where users can input their own values for checking these odds and it'd be highly convenient to just have it be a function. I should have clarified in the initial thread. – ixNoah Feb 08 '23 at 13:11
  • FWIW this question has been asked before; for example see: https://stackoverflow.com/questions/29854866/dice-sum-probability-with-different-types-of-dice/29855688#29855688 I think there are other instances on SO. – Robert Dodier Feb 08 '23 at 22:27

1 Answers1

1

Here's a way.

// Two 6-sided dice, one 8-sided
const dice = [
  [1, 2, 3, 4, 5, 6],
  [1, 2, 3, 4, 5, 6],
  [1, 2, 3, 4, 5, 6, 7, 8],
];

// Function to get all combinations of two arrays
function cartesianProduct(a, b) {
  return a.flatMap(c => b.map(d => [c, d].flat()));
}

// Function to get sum of two numbers
function sum(a, b) { return a + b; }

// All combinations of all dice
const allPossibleRolls = dice.reduce(cartesianProduct);

// Sum for each set of rolls
const sums = allPossibleRolls.map(rolls => rolls.reduce(sum));

// Count how many times each sum appears
const counts = sums.reduce((acc, n) => Object.assign(acc, {
  [n]: (acc[n] || 0) + 1
}), {});

// Convert each count into a percent by dividing by length of allPossibleRolls
const percents = Object.fromEntries(Object.entries(counts).map(
  ([sum, count]) => [sum, count / allPossibleRolls.length]));

Object.entries(percents).forEach(([k,v]) => {
  console.log(`${k} = ${(v * 100).toFixed(5)}%`);
});

Doesn't dedupe equivalent rolls like the Medium post you linked to mentions, so the rolls [1, 2] and [2, 1] and treated as separate possibilites. Not sure if that throws off the math. But this returns the same answer as AnyDice.

Trevor Dixon
  • 23,216
  • 12
  • 72
  • 109
  • The dupes here are part of the stats, so no you wound't want to de-dupe.. – Keith Feb 08 '23 at 13:34
  • @Keith If I add `uniqueRolls = Array.from(new Set(allPossibleRolls.map(rolls => JSON.stringify(rolls.sort()))), k => JSON.parse(k))` and use that instead of `allPossibleRows`, I get different values, so it does seem to affect it. – Trevor Dixon Feb 08 '23 at 14:03
  • Yes, that's why I said you don't want to. – Keith Feb 08 '23 at 14:16
  • I don't understand the math well enough to know which is more correct. Sounds like unique combinations is better according to the Medium post from OP. Let me know if you think my latest edit is wrong. – Trevor Dixon Feb 08 '23 at 14:18
  • Your current answer is 100% correct, for example if you do 2 rolls on the `anydice.com` that the OP links to, it's the exact same answer. I think the dedupe in the Medium link is not relevant here, as he's asking for the number of combinations no matter the order, were as probability takes all combinations in account. – Keith Feb 08 '23 at 14:29
  • Sorry, didn't notice you have now edited, no that's wrong it was correct as you originally had it.. :) – Keith Feb 08 '23 at 14:31
  • 1
    I'll take your word and AnyDice's for it :) Went back. – Trevor Dixon Feb 08 '23 at 14:41