A loot table
How games pick a random drop: weighted chances, a seeded random generator so the results repeat, and a tally of a thousand drops.
What to look at
The weights in LOOT are not percentages. Each item's chance is its weight divided by the total of all weights. random.seed(7) makes the "random" numbers the same on every run, which is how games replay a level or let you test drop rates.
Run it: a thousand drops
Run it, read it, change it. Open in playground keeps your own copy.
main.py to run
import random
LOOT = {
"coin": 60,
"potion": 25,
"shield": 10,
"golden sword": 4,
"dragon egg": 1,
}
def drop(table):
total = sum(table.values())
roll = random.randint(1, total)
for item, weight in table.items():
if roll <= weight:
return item
roll -= weight
random.seed(7)
tally = {item: 0 for item in LOOT}
for _ in range(1000):
tally[drop(LOOT)] += 1
total = sum(LOOT.values())
for item, n in sorted(tally.items(), key=lambda kv: -kv[1]):
expected = LOOT[item] / total * 1000
print(f"{item:<13} {n:>4} (about {expected:.0f} expected)")
Change it
- Give the dragon egg a weight of 0. Does
drop()still work, and can the egg ever drop? - Remove
random.seed(7)and run it three times. Which numbers move the most? - Add a
"rare_mode"table where the weights are flipped (rare things common). Reusedrop()without changing it. - Change the loop to stop at the first golden sword and print how many drops it took.