Dice Odds

Imagine that before we go on vacation to Vegas we want to bone up on some of the relevant odds. Let's start with the frequency of various outcomes when rolling a pair of dice. We could do this by rolling a pair of fair dice many times and recording (counting!) how many times each outcome occurs. There are 11 possible outcomes because we can observe anywhere from 2 to 12 spots on the pair of dice. This means we need to record how many twos occur, how many threes occur, how many fours occur, and so on up to how many twelves occur.

Solution 1: Without lists

Without using lists we could do it like this:

import random
ROLLS = 1000

# Initialize counters to 0.
twos = 0
threes = 0
fours = 0
fives = 0
sixes = 0
sevens = 0
eights = 0
nines = 0
tens = 0
elevens = 0
twelves = 0

# Roll dice many times and record frequency of outcomes.
for roll in range(ROLLS):
    outcome = random.randint(1, 6) + random.randint(1, 6)
    if outcome == 2:
        twos = twos + 1
    elif outcome == 3:
        threes = threes + 1
    elif outcome == 4:
        fours = fours + 1
    elif outcome == 5:
        fives = fives + 1
    elif outcome == 6:
        sixes = sixes + 1
    elif outcome == 7:
        sevens = sevens + 1
    elif outcome == 8:
        eights = eights + 1
    elif outcome == 9:
        nines = nines + 1
    elif outcome == 10:
        tens = tens + 1
    elif outcome == 11:
        elevens = elevens + 1
    else:
        twelves = twelves + 1

# Display results.
print("  =====================")
print("  Outcome | Occurrences")
print("  --------+------------")
print(f"      2   |{twos:8d}")
print(f"      3   |{threes:8d}")
print(f"      4   |{fours:8d}")
print(f"      5   |{fives:8d}")
print(f"      6   |{sixes:8d}")
print(f"      7   |{sevens:8d}")
print(f"      8   |{eights:8d}")
print(f"      9   |{nines:8d}")
print(f"     10   |{tens:8d}")
print(f"     11   |{elevens:8d}")
print(f"     12   |{twelves:8d}")
print("  ---------------------")

which produces output like this,

>>>
  =====================
  Outcome | Occurrences
  --------+------------
  2   |      29
  3   |      66
  4   |      71
  5   |     100
  6   |     137
  7   |     173
  8   |     132
  9   |     122
 10   |      78
 11   |      59
 12   |      33
  ---------------------
>>>

The code is straightforward but lengthy, and relatively slow, because of the cascade of ifs. On average it will take 5 and a half comparisons before finding the correct counter to increment. (We could do somewhat better if we reordered the tests in decreasing order of frequency, but if we knew their frequencies, we probably wouldn't be writing the code in the first place!).

Solution 2: Using lists

These operations can be done more compactly and quickly using a list of counters. We'll let each item in the list count one of the outcomes so we'll need eleven entries in the list all initialized to 0. Then instead of using logic tests to identify the counter to increment we can use the outcome value as an index to directly access the appropriate counter.

import random

ROLLS = 1000

# Initialize counters to 0.
counters = [0] * 11

# Roll dice many times and record frequency of outcomes.
for roll in range(ROLLS):
    outcome = random.randint(1, 6) + random.randint(1, 6)
    # Now increment the appropriate counter.
    # Notice that no testing is needed because we can calculate the index of the matching entry.
    counters[outcome-2] = counters[outcome-2] + 1

# Display results.
print("  =====================")
print("  Outcome | Occurrences")
print("  --------+------------")
for posn in range(11):
    print(f"{posn+2:7d}   |{counters[posn]:8d}")
print("  ---------------------")

Notes:

The verdict

Without list Using list
52 lines of code 12 lines of code
Average 5.5 tests to select counter to increment. Exactly one calculation to select counter to increment.