diff --git a/src/Data/TickLeiste.hs b/src/Data/TickLeiste.hs index 4f0211d..cede4aa 100644 --- a/src/Data/TickLeiste.hs +++ b/src/Data/TickLeiste.hs @@ -2,113 +2,144 @@ -- Module: TickLeiste -- Description: Short Implementation of Splittermonds Tickleiste -- Stability: experimental -module Data.TickLeiste ( - TickLeiste, - newTickLeiste, - addPlayer, - addTicksToPlayer, - isAbwarten, - isBereithalten, - Player, - getPlayerTick, - getTickPlayers, - getTickValue, - Tick (..) - ) where - import Data.Maybe (fromMaybe) - import qualified Data.Map.Strict as M - import qualified Data.Text as T +module Data.TickLeiste + ( TickLeiste, + newTickLeiste, + addTicksToPlayer, + isAbwarten, + isBereithalten, + Player, + getPlayerTick, + getTickPlayers, + getTickValue, + setPlayerTick, + toList, + fromList, + toMap, + fromMap, + Tick (..), + ) +where - -- |A Tick is just a number - data Tick = Abwarten | Bereithalten | Tick Int - deriving (Show, Eq, Ord) +import qualified Data.Map.Strict as M +import Data.Maybe (fromMaybe) +import qualified Data.Text as T - isAbwarten :: Tick -> Bool - isAbwarten Abwarten = True - isAbwarten _ = False +-- | A Tick is just a number +data Tick = Abwarten | Bereithalten | Tick Int + deriving (Show, Eq, Ord) - isBereithalten :: Tick -> Bool - isBereithalten Bereithalten = True - isBereithalten _ = False +-- | test if 'Tick' is constructed using 'Abwarten' +isAbwarten :: Tick -> Bool +isAbwarten Abwarten = True +isAbwarten _ = False - getTickValue :: Tick -> Maybe Int - getTickValue (Tick n) = Just n - getTickValue _ = Nothing - -- |A Player has a name as identifier - type Player = T.Text +-- | test if 'Tick' is constructed using 'Bereithalten' +isBereithalten :: Tick -> Bool +isBereithalten Bereithalten = True +isBereithalten _ = False - -- |The TickLeiste consists of a List of Ticks and for each Tick a - -- Queue of players, that play at that turn. +-- | if 'Tick' is costructed with 'Tick' we get the 'Int' value, else 'Nothing' +getTickValue :: Tick -> Maybe Int +getTickValue (Tick n) = Just n +getTickValue _ = Nothing - -- This is a bit wierd as it introduces redundancy, but I don't have a - -- better idea. - -- NOTE: the first player in the list is the first to move. - data TickLeiste = TickLeiste { leiste :: M.Map Tick [Player], player :: M.Map Player Tick } - deriving (Show) +-- | A Player has a name as identifier +type Player = T.Text - -- |Empty Tickleiste - newTickLeiste :: TickLeiste - newTickLeiste = TickLeiste M.empty M.empty +-- | The TickLeiste consists of a List of Ticks and for each Tick a +-- Queue of players, that play at that turn. - -- |Add a 'Player' to the 'TickLeiste' - addPlayer :: Player -- ^ the Player to add - -> Tick -- ^ the Tick we add the Player to - -> TickLeiste -- ^ the TickLeiste we add the player to - -> TickLeiste -- ^ the resulting TickLeiste - addPlayer p t (TickLeiste l pl) = TickLeiste tlm pm - where - tlm :: M.Map Tick [Player] - tlm = insertPlayerToLeiste p t l - pm :: M.Map Player Tick - pm = setPlayerTickToPlayer p t pl +-- This is a bit wierd as it introduces redundancy, but I don't have a +-- better idea. +-- NOTE: the first player in the list is the first to move. +data TickLeiste = TickLeiste {leiste :: M.Map Tick [Player], player :: M.Map Player Tick} + deriving (Show) - -- | Adds a number of ticks to the player, if the player is not on - -- the TickLeiste, Abwarten or Bereithalten then this function returns - -- Nothing +-- | Empty Tickleiste +newTickLeiste :: TickLeiste +newTickLeiste = TickLeiste M.empty M.empty - -- Would it be better to return the original 'TickLeiste' instead of 'Nothing'? - addTicksToPlayer :: Player -- ^ the Player we want to add ticks to - -> Int -- ^ the number of Ticks we want to add - -> TickLeiste -- ^ the TickLeiste we want to modify - -> Maybe TickLeiste -- ^ the result +-- | Adds a number of ticks to the player, if the player is not on +-- the TickLeiste, Abwarten or Bereithalten then this function returns +-- Nothing - addTicksToPlayer p t tl@(TickLeiste l pl) = {- fromMaybe tl $ -}do - pt <- pl M.!? p - ptv <- getTickValue pt - let npt = Tick $ ptv + t - tlm = (insertPlayerToLeiste p npt . removePlayerFromLeiste p pt) l - pm = setPlayerTickToPlayer p npt pl - return $ TickLeiste tlm pm +-- Would it be better to return the original 'TickLeiste' instead of 'Nothing'? +addTicksToPlayer :: + -- | the Player we want to add ticks to + Player -> + -- | the number of Ticks we want to add + Int -> + -- | the TickLeiste we want to modify + TickLeiste -> + -- | the result + Maybe TickLeiste +addTicksToPlayer p t tl = {- fromMaybe tl $ -} do + pt <- getPlayerTick p tl + ptv <- getTickValue pt + let nt = Tick $ ptv + t + return $ setPlayerTick p nt tl +-- | We get the tick a 'Player' is on +getPlayerTick :: + Player -> + TickLeiste -> + Maybe Tick +getPlayerTick p (TickLeiste _ pl) = pl M.!? p - -- |We get the tick a 'Player' is on - getPlayerTick :: Player -- ^ the 'Player' - -> TickLeiste - -> Maybe Tick - getPlayerTick p (TickLeiste _ pl) = pl M.!? p +-- | get a list of 'Player' that move at a tick in order. +getTickPlayers :: + Tick -> + TickLeiste -> + [Player] +getTickPlayers t (TickLeiste l _) = fromMaybe [] $ l M.!? t - -- |get a list of 'Player' that move at a tick in order. - getTickPlayers :: Tick - -> TickLeiste - -> [Player] - getTickPlayers t (TickLeiste l _) = fromMaybe [] $ l M.!? t - +-- | set the tick of a 'Player', if the 'Player' is does not exist we add them. +setPlayerTick :: + Player -> + Tick -> + TickLeiste -> + TickLeiste +setPlayerTick p t tl@(TickLeiste l pl) = TickLeiste (insertPlayerToLeiste p t l') (setPlayerTickToPlayer p t pl) + where + l' :: M.Map Tick [Player] + l' = fromMaybe l $ do + ot <- getPlayerTick p tl + return $ removePlayerFromLeiste p ot l - - -- this is just an internal helper - -- it removes a player from a specific tick, if the player - -- wasn't at the tick it is the identity. - removePlayerFromLeiste :: Player -> Tick -> M.Map Tick [Player] -> M.Map Tick [Player] - removePlayerFromLeiste p t l = fromMaybe l $ do - list <- l M.!? t - let list' = filter ( /= p) list - if null list' then - return $ M.delete t l - else - return $ M.insert t list' l +-- | convert the Tick[eiste to a list of 'Tick' and 'Player' list pairs. These list are ordered +toList :: TickLeiste -> [(Tick, [Player])] +toList (TickLeiste l _) = M.toAscList l - insertPlayerToLeiste :: Player -> Tick -> M.Map Tick [Player] -> M.Map Tick [Player] - insertPlayerToLeiste p t l = M.insert t (M.findWithDefault [] t l ++ [p]) l +-- | convert from list to TickLeiste, if a player is at multiple 'Tick' this returns +-- 'Nothing' - setPlayerTickToPlayer :: Player -> Tick -> M.Map Player Tick -> M.Map Player Tick - setPlayerTickToPlayer = M.insert +-- TODO +fromList :: [(Tick, [Player])] -> Maybe TickLeiste +fromList = error "not implemented" + +-- | convert from 'TickLeiste' to a map from 'Tick' to list of 'Player' +toMap :: TickLeiste -> M.Map Tick [Player] +toMap = leiste + +-- TODO +fromMap :: M.Map Tick [Player] -> Maybe TickLeiste +fromMap = error "not implemented" + +-- these are just internal helpers + +-- it removes a player from a specific tick, if the player +-- wasn't at the tick it is the identity. +removePlayerFromLeiste :: Player -> Tick -> M.Map Tick [Player] -> M.Map Tick [Player] +removePlayerFromLeiste p t l = fromMaybe l $ do + list <- l M.!? t + let list' = filter (/= p) list + if null list' + then return $ M.delete t l + else return $ M.insert t list' l + +insertPlayerToLeiste :: Player -> Tick -> M.Map Tick [Player] -> M.Map Tick [Player] +insertPlayerToLeiste p t l = M.insert t (M.findWithDefault [] t l ++ [p]) l + +setPlayerTickToPlayer :: Player -> Tick -> M.Map Player Tick -> M.Map Player Tick +setPlayerTickToPlayer = M.insert