Two players have a set of dice each. The first player has nine dice with four faces each, with numbers one to four. The second player has six normal dice with six faces each, each face has the usual numbers from one to six.

They roll their dice and sum the totals of the faces. The player with the highest total wins (it's a draw if the totals are the same). What's the probability of the first player beating the second player?

Later the two players use a different set of dice each. Now the first player has five dice with ten faces each, and the second player has six dice with seven faces each. Now what's the probability of the first player beating the second player?

This task was adapted from the Project Euler Problem n.205:
https://projecteuler.net/problem=205

#lang racket
 
(define probs# (make-hash))
 
(define (NdD n d)
  (hash-ref!
   probs# (cons n d)
   (λ ()
     (cond
       [(= n 0) ; every chance of nothing!
        (hash 0 1)]
       [else
        (for*/fold ((hsh (hash))) (((i p) (in-hash (NdD (sub1 n) d))) (r (in-range 1 (+ d 1))))
          (hash-update hsh (+ r i) (λ (p+) (+ p+ (/ p d))) 0))]))))
 
(define (game-probs N1 D1 N2 D2)
  (define P1 (NdD N1 D1))
  (define P2 (NdD N2 D2))  
  (define-values (W D L)
    (for*/fold ((win 0) (draw 0) (lose 0)) (((r1 p1) (in-hash P1)) ((r2 p2) (in-hash P2)))
      (define p (* p1 p2))
      (cond
        [(< r1 r2) (values win draw (+ lose p))]
        [(= r1 r2) (values win (+ draw p) lose)]
        [(> r1 r2) (values (+ win p) draw lose)])))
 
  (printf "P(P1 win): ~a~%" (real->decimal-string W 6))
  (printf "P(draw):   ~a~%" (real->decimal-string D 6))
  (printf "P(P2 win): ~a~%" (real->decimal-string L 6))  
  (list W D L))
 
(printf "GAME 1 (9D4 vs 6D6)~%")
(game-probs 9 4 6 6)
(newline)
 
(printf "GAME 2 (5D10 vs 6D7) [what is a D7?]~%")
(game-probs 5 10 6 7)