I think I got the loopless version working. The mark probability can be seen as a function of the number of modifying steps. In this way, it is similar to the probability of getting two heads in a row after n throws of an unfair coin (in this case 1/3 heads, 2/3 tails). This probability I took from (Two Heads in A Row: With Unequal Probability | ELEC424 Wiki | Fandom), although there’s not a derivation so I’m not entirely sure it’s correct. Nonetheless, here’s my revised code.
using Distributions
D(x) = rand(1:x)
P(m) = m <= 1 ? 0 : P(m - 1) + (1 - P(m - 1)) / 3 - (1 - P(m - 2)) * (2 / 9)
function O(x)
roll, modifier = D(x), rand(Geometric(0.5))
if (roll == x || roll == 1) && rand() <= P(modifier)
println(roll == x ? "$(roll + modifier) critical" : "$(roll - modifier) fumble")
else
println(roll == x ? roll + modifier : roll == 1 ? roll - modifier : roll)
end
end
Unfortunately, it’s still not smaller than the looped version, and it certainly makes it less readable, so not sure if there’s any real benefit to this version