Codementor Events

Combinatorics — Counting dice combinations using JavaScript

Published May 27, 2019Last updated Nov 23, 2019

Quite frequently I got asked questions like:

“How can I get all possible combinations for a given dice roll?”

“How many combinations add up to 7 in a pair of dice?”

“Is it possible to use a recursive algorithm to count all dice combinations?”

To answer these questions (and variants of them that involve coins, cards decks, and whatnot) we can use combinatorics , a branch of mathematics that deals with combinations of objects belonging to a finite set of elements.

While I’m not an expert in the subject, in this post I’ll try to show you how to solve combinatorics problems using JavaScript.

But before jumping into the code, let’s disambiguate combinations from permutations. Two separate concepts that sometimes people use interchangeably.

Permutations are all possible combinations of a given list of ordered values. For instance, while calculating all possible permutations for two 6 sided dice, the pairs {1, 6} and {6,1} are considered to be different. The order matters.

When counting combinations , the pairs {1, 6} and {6, 1} are considered to be the same. So, as it happens when we are working with sets, the order doesn’t matter.

To hit two birds with one stone, we are not going to use loops. Performance wise, using recursive functions instead of loops is not the most efficient way to go (at least not in JavaScript) but since most people were asking for a recursive solution, that’s the route that we are going to take.

First off, let’s create a function that gives us all unique combinations for the given number of dice. Once we are done with that, we’ll all add a filter to include only those combinations that add up to some particular number.

const SIDES = 6;
function append(src, num) {
  res = Array.from(src);
  res.push(num);
  return res;
}

function diceCombinations(dc, acc, side, res) {
  if (dc < 1 || side >= (SIDES + 1))
    return;

if (dc == 1) {
    let set = append(acc, side);
    res.push(set);
  }
  else {
    diceCombinations(dc — 1, append(acc, side), side, res);
  }
  return diceCombinations(dc, acc, side + 1, res);
}

For 2 dice , the previous function returns 21 unique combinations.

Sure.

No, wait!

6 sides per die * 2 dice = 6**2 = 36 possible combinations!

Generally speaking, your math is right; But keep in mind that we are counting unique sets of values; In this setting , the pairs {1, 2} and {2, 1} are considered to be the same. And that’s why the correct answer is 21.

If we use 3 dice, it’ll be 56, and so on…

(If you are interested in the theory/math behind combinatorics, I recommend you to take a look at this short article. No worries, you don’t need a Ph.D. to understand it 😃)

Now that we know that our function counts the right number of combinations, let’s add a filter to include only those combinations that add up to a given number. For instance, how many unique combinations add up to 7 if we are using 2 dice, and stuff like that.

function diceCombinations(dc, acc, side, target, res) {
  if (dc < 1 || side >= (SIDES + 1))
    return;
   if (dc == 1) {
     let set = append(acc, side);
     if (sumSet(set, 0) == target)
       res.push(set);
     }
     else {
       diceCombinations(
         dc — 1, append(acc, side), side, target, res);
  }
  return diceCombinations(dc, acc, side + 1, target, res);
}

I also added a helper function to sum the elements of the set. (Just for fun, I made it recursive, too.)

// Sums the value of all members in the set.
function sumSet(set, idx) {
  if (idx >= set.length)
    return 0;
  return set[idx] + sumSet(set, idx + 1);
}

Now our function allows us to answer:

“How many combinations add up to 7 while rolling a pair of dice?”

{1, 6} {2, 5} {3, 4}

“What if we use 3?”

{1, 1, 5} {1, 2, 4} {1, 3, 3} {2, 2, 3}

So, that’s it for this short post. I hope it helps you to learn a bit about combinatorics.

Thanks for reading!

See you next time.

Before you go. If you are getting started with algorithms and data structures, you might want to take a look at my ebook “ Data Structures From Scratch — JS Edition ” (It free for Kindle Unlimited members.)


Data Structures from scratch — JS Edition

Discover and read more posts from Ale Miralles
get started
post commentsBe the first to share your opinion
Russell Winterbotham
5 years ago

This caught my eye because I was looking for a similar solution. I’m trying to check the accuracy of Average Scores published by a vendor of information. I do not believe the Averages are actually derived from the subset of scores which they claim to be using, which may be due to a bug in the Algorithm which they use. There can be from 3 to 10 scores listed. I need a way to Sum each possible Combination of Scores, then calculate the Average, then List the Averages of each of the Combinations, and show me which one Matches the Published Average. So, the flow would be like THIS: I enter the list of n Potential Scores in to a form. I enter in the Published Average into a form. The program then Calculates an Average for Every Combination of those Scores, and Lists the set of scores which Matches the Published Average which I entered into the form. How hard is it to do something like THAT?

Ale Miralles
5 years ago

I’m afraid to comment on this because it’s a bit out of my league. As I mentioned in the post, I’m not an expert on the field. I just write about it because lots of people were asking the same questions over and over, again. (And I have a spec from a mentee to back the results for each use-case.) I did shallow research on the subject and derivate everything from there.

I refrain from commenting because I might misguide you with my answer.

Thanks for commenting, though! Hope to be able to help the next time.

Russell Winterbotham
5 years ago

Seems to me that you already have almost solved the use case: "Now that we know that our function counts the right number of combinations, let’s add a filter to include only those combinations that add up to a given number. For instance, how many unique combinations add up to 7 if we are using 2 dice, " Instead of using the number 7, I want to be able to plug in whatever number (Average Score) which I choose (it will never be over 110). Then I simply want to know how many combinations of the original set which I specified could produce that Average (it will almost always only be ONE combination). So, I specify an Average = 85. Then I specify the potential scores used to make the Average: {80, 85, 90, 100, 105, 110}. Then the script tells me that the subset of {80, 85, 90} was the only combination that could have created the selected Average of 85.

Show more replies