posita / dyce

Simple Python tools for exploring dice outcomes and other finite discrete probabilities
https://posita.github.io/dyce/
Other
34 stars 2 forks source link

`H.substitute` has no way to change coalesce behaviors during expansion #8

Closed posita closed 2 years ago

posita commented 2 years ago

Here's a contrived example for which dyce doesn't provide a convenient interface:

  1. Start with a total of zero.
  2. Roll a six-sided die. If the face was a six, go to step 3 (i.e., replace with whatever that produces). Otherwise add the face to the total and stop.
  3. Roll a four-sided die. Add the face to the total. If the face was a one, go to step 2. Otherwise stop.

Maybe the ability for expand to return an optional coalesce override would work?

from operator import __add__
from dyce import H
from dyce.h import coalesce_replace

def expand(h: H, outcome):
  if h == d6:
    if outcome == 6:
      return d4  # uses default passed to substitute
    else:
      return outcome, __add__  # overrides coalesce for this phase
  elif h == d4:
    if outcome == 1:
      return d6, lambda: h, __: h + outcome  # like coalesce_replace, but adds the outcome from the d4
    else:
      return outcome, __add__
  else:
    assert False, f"unrecognized histogram {h}"

H(6).substitute(expand, coalesce_replace, max_depth=4)
posita commented 2 years ago

AnyDice has a pretty compact syntax for this, partially because it manages recursion base cases implicitly (via its global maximum recursion depth parameter).

function: doit six VAL:n {
  if VAL = 6 { result: [doit four d4] }
  else { result: VAL }
}

function: doit four VAL:n {
  if VAL = 1 { result: VAL + [doit six d6] }
  else { result: VAL }
}

output [doit six d6]

I wonder if we need to tackle this at the recursion management level rather than continue to fiddle with the separation between expand and coalesce. 🤔