Problem 458693 · medium · Level 04 Non-Linear Data Structures

Dice That Keep Their Own Luck

py-composition · py-classes · random number generators · discrete distributions

A board-game simulator needs loaded dice. A die has faces 1, 2, ..., k with weights w1, ..., wk (a face with twice the weight comes up twice as often). Each die must give the same rolls for the same seed no matter what other dice do in between, so that games can be replayed.

Write two classes:

  • Die(weights, seed):
    • roll() draws one number u = rng.random() from the die's own generator random.Random(seed) (exactly one draw per roll) and returns the first face whose cumulative weight w1 + ... + wj is larger than u * total.
    • roll_many(n) returns a list of n rolls.
    • counts() returns a dictionary from every face to how often it has been rolled so far.
    • expected() returns the mean face value sum(j * wj) / total.
    • Weights that are negative, or add up to zero, raise ValueError.
  • Pool(dice), a pool made of a list of Die objects:
    • roll() rolls every die once, in list order, and returns the total;
    • spread(n) rolls the pool n times and returns a dictionary from each total that occurred to its count.

The helper raises(fn, *args) returns the name of the exception a call raises (or None), and replayed(weights, seed, other, n) checks the replay promise: it rolls a die n times on its own, then again with a second die (other weights) rolled between its rolls, and returns both lists.

Examples

Input:  d = Die([1, 1, 1, 1, 1, 1], 7); d.roll_many(8), d.counts()[6], d.expected()
Output: ([2, 1, 4, 1, 4, 3, 1, 4], 0, 3.5)

Input:  Die([0, 3, 1], 1).expected()
Output: 2.25

Constraints

  • 1 <= k <= 20; weights are non-negative numbers.
  • Up to 3 * 10**4 rolls per test.
  • Do not use the module-level random functions: they share one generator between all dice.

Goals

  • Give every object its own random number generator, so objects do not disturb each other
  • Build a pool of dice out of dice objects and delegate the work to them
  • Sample a face from unequal weights with one uniform number
Starting Python…