Combinatorics
Probability
Dice Outcomes
Mathematics
Permutations

Generate a matrix of all possible outcomes for throwing n dice ignoring order

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If order does not matter, rolling 1, 3, 5 is the same outcome as rolling 5, 1, 3. That changes the problem from generating all ordered sequences to generating combinations with repetition. The cleanest representation is a matrix whose rows are nondecreasing dice values, because each unordered outcome appears exactly once in that form.

Reframe the Problem as Nondecreasing Sequences

For n dice, each value is between 1 and 6. If order is ignored, every valid outcome can be written as a nondecreasing sequence:

text
11 1 1
21 1 2
31 1 3
4...
54 5 6
65 6 6
76 6 6

That representation solves the duplication problem automatically. You never generate both 2, 5, 6 and 6, 2, 5 because the canonical form is always sorted.

For two dice, the unordered outcomes are:

text
11 1
21 2
31 3
41 4
51 5
61 6
72 2
82 3
92 4
102 5
112 6
123 3
133 4
143 5
153 6
164 4
174 5
184 6
195 5
205 6
216 6

That is the "matrix" most programs want: one row per distinct unordered roll outcome.

Generate the Matrix with Backtracking

The standard algorithm is recursive backtracking with a lower bound. At each step, choose the next die value from the current value up to 6. That guarantees the row stays nondecreasing.

python
1def dice_combinations(n, start=1, current=None):
2    if current is None:
3        current = []
4
5    if len(current) == n:
6        yield current.copy()
7        return
8
9    for face in range(start, 7):
10        current.append(face)
11        yield from dice_combinations(n, face, current)
12        current.pop()
13
14
15for row in dice_combinations(3):
16    print(row)

The key detail is yield from dice_combinations(n, face, current). Passing face as the next lower bound prevents smaller values from appearing later in the row, so duplicates never arise.

Materialize the Matrix When Needed

If you truly need a matrix object instead of a generator, collect the rows.

python
matrix = list(dice_combinations(3))
print(len(matrix))
print(matrix[:10])

That works well for small n, but the row count grows as n increases. The number of unordered outcomes for n six-sided dice is the combinations-with-repetition count C(n + 5, 5). You do not need to memorize the formula to write the algorithm, but it is useful for estimating size before materializing a large matrix.

Use the Matrix for Counting, Probability, or Sums

Once each unordered roll is represented once, you can attach whatever derived information you need:

  1. Count the rows.
  2. Compute the sum of each row.
  3. Group rows by repeated values.
  4. Convert rows into histograms such as "two threes and one six."

For example, to compute row sums:

python
1rows = list(dice_combinations(3))
2sums = [(row, sum(row)) for row in rows]
3
4for row, total in sums[:5]:
5    print(row, total)

Be careful here: this matrix is not the same as the ordered sample space used for ordinary dice probabilities. If you want exact probabilities of sums from fair dice, each unordered row carries a different multiplicity. For example, [1, 1, 2] represents three ordered rolls, while [1, 2, 3] represents six.

Know When Ignoring Order Is the Right Model

Ignoring order is correct when the problem cares only about the multiset of faces, not the sequence in which dice are imagined to have landed. Examples include:

  1. Listing unique hand-like outcomes.
  2. Enumerating states for a combinatorics problem.
  3. Building canonical rows for later grouping.

If the task is standard probability on independent dice, ordered outcomes are often still the correct base space even if you later collapse them into equivalence classes.

Common Pitfalls

  • Generating all ordered rolls first and then trying to deduplicate them after the fact.
  • Forgetting that unordered rows have different multiplicities when you later compute probabilities.
  • Treating sums as the same thing as unordered roll combinations.
  • Materializing a huge matrix without estimating how fast the row count grows.
  • Using a generator that allows values to decrease, which reintroduces duplicate rows in different orders.

Summary

  • Ignoring order means generating nondecreasing sequences of die values.
  • A backtracking algorithm with a lower-bound parameter generates each unordered outcome exactly once.
  • The resulting matrix is useful for combinatorics and state enumeration.
  • It is not automatically the correct weighted sample space for probability calculations.
  • Use a generator for scalability and collect rows only when you truly need the full matrix in memory.

Course illustration
Course illustration