#!/usr/bin/ruby
#
## https://rosettacode.org/wiki/Dice_game_probabilities
#
func combos(sides, n) {
n || return [1]
var ret = ([0] * (n*sides.max + 1))
combos(sides, n-1).each_kv { |i,v|
v && for s in sides { ret[i + s] += v }
}
return ret
}
func winning(sides1, n1, sides2, n2) {
var (p1, p2) = (combos(sides1, n1), combos(sides2, n2))
var (win,loss,tie) = (0,0,0)
p1.each_kv { |i, x|
win += x*p2.slice(0,i).sum
tie += x*p2.slice(i,1).sum
loss += x*p2.slice(i+1).sum
}
[win, tie, loss] »/» p1.sum*p2.sum
}
func display_results(String title, Array res) {
say "=> #{title}"
for name, prob in (%w(p₁\ win tie p₂\ win) ~Z res) {
say "P(#{'%6s' % name}) =~ #{prob.round(-11)} (#{prob.as_frac})"
}
print "\n"
}
display_results('9D4 vs 6D6', winning(1.. 4, 9, 1..6, 6))
display_results('5D10 vs 6D7', winning(1..10, 5, 1..7, 6))
assert_eq(
winning(1.. 4, 9, 1..6, 6),
[48679795/84934656, 144252007/2038431744, 725864657/2038431744]
)
assert_eq(
winning(1..10, 5, 1..7, 6),
[3781171969/5882450000, 523491347/11764900000, 735812943/2352980000]
)