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