Skip to content

Instantly share code, notes, and snippets.

@mrphlip
Created August 13, 2021 15:53
Show Gist options
  • Save mrphlip/a55d09f9b6caea37f73cf670b03897ac to your computer and use it in GitHub Desktop.
Save mrphlip/a55d09f9b6caea37f73cf670b03897ac to your computer and use it in GitHub Desktop.
Riddler Classic solution for 2021-08-13
{-# OPTIONS_GHC -Wno-tabs #-}
import Data.List
import Data.Ratio
-- https://fivethirtyeight.com/features/are-you-clever-enough/
-- calcEV n = expected value of playing the game, rolling n dice
calcEV :: Integer -> Rational
calcEV 0 = 0 -- base case
calcEV n = ev
where
-- consider every possible roll of n dice
buildRolls :: Integer -> [[Rational]]
buildRolls 0 = [[]]
buildRolls n = [i:rest | i <- [1,2,3,4,5,6], rest <- buildRolls (n-1)]
rolls :: [[Rational]]
rolls = map (reverse.sort) $ buildRolls n
-- calculate the value of each roll
values :: [Rational]
values = map calcValue rolls
-- we have to keep the best die, and possibly keep more
calcValue :: [Rational] -> Rational
calcValue rolls = maximum $ map calcKeepValue [1..n]
where calcKeepValue i = sum (genericTake i rolls) + getEV (n - i)
-- average to get our EV
ev = sum values / (6^n)
-- memoisation
evs = map calcEV [0..] :: [Rational]
getEV = genericIndex evs :: Integer -> Rational
main = mapM_ (putStrLn.outputLine) [0..10]
where outputLine i = show i ++ ": " ++ show (getEV i) ++ " = " ++ show (fromRational (getEV i) :: Float)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment