module Roller.Core (main) where import Roller.Types import Roller.Parse import Roller.CLI import System.Environment (getArgs) import System.Random (randomRIO) import Control.Applicative import Control.Monad (join, replicateM, replicateM_) import Data.Word positiveRoll :: Word8 -> IO Integer positiveRoll x = randomRIO $ (1, fromIntegral x) negativeRoll :: Word8 -> IO Integer negativeRoll x = (*(-1)) <$> positiveRoll x positiveRolls :: Word8 -> Word8 -> IO [Integer] positiveRolls x y = replicateM (fromIntegral x) . positiveRoll $ y negativeRolls :: Word8 -> Word8 -> IO [Integer] negativeRolls x y = replicateM (fromIntegral x) . negativeRoll $ y rolls :: [DiceExpression] -> IO [[Integer]] rolls expressions = foldl (\x y -> (++) <$> x <*> (extractDiceExpressionValue y)) (pure [[]]) expressions extractDiceExpressionValue :: DiceExpression -> IO [[Integer]] extractDiceExpressionValue expression = case expression of DieTerm x y -> return <$> positiveRolls x y AddedDieTerm x y -> return <$> positiveRolls x y SubtractedDieTerm x y -> return <$> negativeRolls x y ConstantTerm x -> return [[fromIntegral x]] AddedConstantTerm x -> return [[fromIntegral x]] SubtractedConstantTerm x -> return [[(-1) * (fromIntegral x)]] rollEm :: CLI (IO ()) rollEm verbose n args = maybe parseFail rollMany (parse input) where input = concat args rollMany = replicateM_ n . rollOnce rollOnce exp = fmap summary (rolls exp) >>= putStrLn summary = if verbose then show else show . sumRolls sumRolls = sum . map sum parseFail = putStrLn $ "Could not parse \"" ++ input ++ "\" as dice expression!" main :: IO () main = join . withOpts $ rollEm