123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- {-# LANGUAGE OverloadedStrings #-}
- module Types where
- import qualified Data.Map.Strict as Map
- import qualified Data.Text as Text
- import qualified Data.Text.IO as Text
- import qualified System.Random as Rand
- data Range = Range { rFrom :: Int, rTo :: Int }
- deriving (Eq, Show)
- type TableMap = Map.Map Text.Text Table
- data Table = Table
- { tableName :: Text.Text
- , tableChoices :: [(Range, Result)]
- } deriving (Eq, Show)
- data Fragment
- = FragText Text.Text
- | FragRoll Text.Text
- deriving (Eq, Show)
- data Result = Result { fromResult :: [Fragment] }
- deriving (Eq, Show)
- data Value = Value
- { valueMsg :: Text.Text
- } deriving (Eq, Show)
- stripValue :: Value -> Value
- stripValue = Value . Text.strip . valueMsg
- data Context = Context
- { ctxMap :: TableMap
- , ctxRoll :: Int
- , ctxSelf :: Text.Text
- }
- findTable :: Text.Text -> Context -> Maybe Table
- findTable name ctx = Map.lookup name (ctxMap ctx)
- computeFragments :: Context -> Fragment -> IO Value
- computeFragments _ (FragText msg) = pure (Value msg)
- computeFragments ctx (FragRoll name) =
- let absolute = case Text.stripPrefix "self" name of
- Just rest -> ctxSelf ctx <> rest
- Nothing -> name
- in case findTable absolute ctx of
- Just t -> rollTable (ctxMap ctx) t
- Nothing -> error ("no such table: " ++ show absolute)
- computeResult :: Context -> Result -> IO Value
- computeResult ctx (Result msgs) = do
- vs <- mapM (computeFragments ctx) msgs
- pure (Value (foldMap valueMsg vs))
- tableDie :: Table -> Int
- tableDie t = maximum [ x | (Range _ x, _) <- tableChoices t ]
- rollTable :: TableMap -> Table -> IO Value
- rollTable tables t = do
- roll <- Rand.randomRIO (1, tableDie t)
- let ctx = Context
- { ctxMap = tables
- , ctxRoll = roll
- , ctxSelf = tableName t
- }
- case [ result
- | (range, result) <- tableChoices t
- , roll >= rFrom range && roll <= rTo range
- ] of
- [choice] -> stripValue <$> computeResult ctx choice
- _ -> error $ unwords
- [ "bad table "
- , Text.unpack (tableName t)
- , "(roll of"
- , show roll
- , "has no matching result)"
- ]
|