mtlstats/src/Mtlstats/Types.hs

461 lines
11 KiB
Haskell
Raw Normal View History

{- |
mtlstats
Copyright (C) 2019 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
2019-08-22 13:05:25 -04:00
{-# LANGUAGE LambdaCase, OverloadedStrings, TemplateHaskell #-}
2019-08-09 11:06:13 -04:00
module Mtlstats.Types (
-- * Types
2019-08-23 09:22:32 -04:00
Action,
2019-08-13 10:11:10 -04:00
ProgState (..),
2019-08-22 01:18:02 -04:00
GameState (..),
2019-08-20 01:40:59 -04:00
ProgMode (..),
2019-08-22 01:18:02 -04:00
GameType (..),
2019-08-16 11:49:04 -04:00
Database (..),
2019-08-09 11:06:13 -04:00
Player (..),
PlayerStats (..),
2019-08-11 10:24:39 -04:00
Goalie (..),
GoalieStats (..),
2019-08-24 16:23:56 -04:00
Prompt (..),
2019-08-09 11:06:13 -04:00
-- * Lenses
2019-08-19 23:58:18 -04:00
-- ** ProgState Lenses
database,
2019-08-20 01:40:59 -04:00
progMode,
2019-08-24 19:02:29 -04:00
inputBuffer,
2019-08-22 01:18:02 -04:00
-- ** GameState Lenses
gameType,
otherTeam,
2019-08-22 01:18:02 -04:00
homeScore,
2019-08-22 03:10:22 -04:00
awayScore,
2019-08-22 13:05:25 -04:00
-- ** ProgMode Lenses
gameTypeL,
otherTeamL,
2019-08-22 14:19:43 -04:00
homeScoreL,
2019-08-22 14:33:39 -04:00
awayScoreL,
2019-08-16 11:49:04 -04:00
-- ** Database Lenses
dbPlayers,
dbGoalies,
2019-08-19 09:31:24 -04:00
dbGames,
2019-08-09 11:06:13 -04:00
-- ** Player Lenses
pNumber,
pName,
pPosition,
pYtd,
pLifetime,
-- ** PlayerStats Lenses
psGoals,
psAssists,
psPMin,
2019-08-11 10:24:39 -04:00
-- ** Goalie Lenses
gNumber,
gName,
gYtd,
gLifetime,
-- ** GoalieStats Lenses
gsGames,
gsMinsPlayed,
gsGoalsAllowed,
gsGoalsAgainst,
gsWins,
gsLosses,
gsTies,
2019-08-09 11:06:13 -04:00
-- * Constructors
2019-08-19 23:58:18 -04:00
newProgState,
2019-08-22 01:18:02 -04:00
newGameState,
2019-08-16 11:49:04 -04:00
newDatabase,
2019-08-09 11:06:13 -04:00
newPlayer,
newPlayerStats,
2019-08-11 10:24:39 -04:00
newGoalie,
newGoalieStats,
2019-08-22 03:06:36 -04:00
-- * Helper Functions
-- ** ProgState Helpers
teamScore,
2019-08-22 03:06:36 -04:00
-- ** Player Helpers
2019-08-09 11:06:13 -04:00
pPoints
) where
2019-08-23 09:22:32 -04:00
import Control.Monad.Trans.State (StateT)
2019-08-10 10:01:36 -04:00
import Data.Aeson
( FromJSON
, ToJSON
, object
, pairs
, parseJSON
, toEncoding
, toJSON
, withObject
, (.:)
, (.=)
)
2019-08-22 13:05:25 -04:00
import Lens.Micro (Lens', lens, (&), (^.), (.~))
2019-08-09 11:06:13 -04:00
import Lens.Micro.TH (makeLenses)
2019-08-24 16:23:56 -04:00
import UI.NCurses (Curses, Update)
2019-08-23 09:22:32 -04:00
-- | Action which maintains program state
type Action a = StateT ProgState Curses a
2019-08-09 11:06:13 -04:00
2019-08-13 10:11:10 -04:00
-- | Represents the program state
2019-08-20 01:40:59 -04:00
data ProgState = ProgState
2019-08-24 19:02:29 -04:00
{ _database :: Database
2019-08-23 10:10:49 -04:00
-- ^ The data to be saved
2019-08-24 19:02:29 -04:00
, _progMode :: ProgMode
2019-08-23 10:10:49 -04:00
-- ^ The program's mode
2019-08-24 19:02:29 -04:00
, _inputBuffer :: String
-- ^ Buffer for user input
2019-08-19 23:58:18 -04:00
} deriving (Eq, Show)
2019-08-13 10:11:10 -04:00
2019-08-22 01:18:02 -04:00
-- | The game state
data GameState = GameState
2019-08-22 03:10:22 -04:00
{ _gameType :: Maybe GameType
2019-08-23 10:10:49 -04:00
-- ^ The type of game (home/away)
, _otherTeam :: String
-- ^ The name of the other team
2019-08-22 03:10:22 -04:00
, _homeScore :: Maybe Int
2019-08-23 10:10:49 -04:00
-- ^ The home team's score
2019-08-22 03:10:22 -04:00
, _awayScore :: Maybe Int
2019-08-23 10:10:49 -04:00
-- ^ The away team's score
2019-08-22 01:18:02 -04:00
} deriving (Eq, Show)
2019-08-20 01:40:59 -04:00
-- | The program mode
2019-08-20 11:17:24 -04:00
data ProgMode
= MainMenu
| NewSeason
2019-08-22 01:18:02 -04:00
| NewGame GameState
deriving (Eq, Show)
-- | The type of game
data GameType
= HomeGame
| AwayGame
2019-08-20 11:17:24 -04:00
deriving (Eq, Show)
2019-08-20 01:40:59 -04:00
2019-08-16 11:49:04 -04:00
-- | Represents the database
data Database = Database
{ _dbPlayers :: [Player]
-- ^ The list of players
, _dbGoalies :: [Goalie]
2019-08-23 10:35:59 -04:00
-- ^ The list of goalies
2019-08-19 09:31:24 -04:00
, _dbGames :: Int
-- ^ The number of games recorded
2019-08-16 11:49:04 -04:00
} deriving (Eq, Show)
instance FromJSON Database where
parseJSON = withObject "Database" $ \v -> Database
<$> v .: "players"
<*> v .: "goalies"
2019-08-19 09:31:24 -04:00
<*> v .: "games"
2019-08-16 11:49:04 -04:00
instance ToJSON Database where
2019-08-19 09:31:24 -04:00
toJSON (Database players goalies games) = object
[ "players" .= players
, "goalies" .= goalies
, "games" .= games
2019-08-16 11:49:04 -04:00
]
2019-08-19 09:31:24 -04:00
toEncoding (Database players goalies games) = pairs $
"players" .= players <>
"goalies" .= goalies <>
"games" .= games
2019-08-16 11:49:04 -04:00
2019-08-09 11:06:13 -04:00
-- | Represents a (non-goalie) player
data Player = Player
{ _pNumber :: Int
-- ^ The player's number
, _pName :: String
-- ^ The player's name
, _pPosition :: String
-- ^ The player's position
, _pYtd :: PlayerStats
-- ^ The Player's year-to-date stats
, _pLifetime :: PlayerStats
-- ^ The player's lifetime stats
} deriving (Eq, Show)
2019-08-10 10:01:36 -04:00
instance FromJSON Player where
parseJSON = withObject "Player" $ \v -> Player
<$> v .: "number"
<*> v .: "name"
<*> v .: "position"
<*> v .: "ytd"
<*> v .: "lifetime"
instance ToJSON Player where
toJSON (Player num name pos ytd lt) = object
[ "number" .= num
, "name" .= name
, "position" .= pos
, "ytd" .= ytd
, "lifetime" .= lt
]
toEncoding (Player num name pos ytd lt) = pairs $
"number" .= num <>
"name" .= name <>
"position" .= pos <>
"ytd" .= ytd <>
"lifetime" .= lt
2019-08-09 11:06:13 -04:00
-- | Represents a (non-goalie) player's stats
data PlayerStats = PlayerStats
{ _psGoals :: Int
-- ^ The number of goals
, _psAssists :: Int
-- ^ The number of assists
, _psPMin :: Int
-- ^ The number of penalty minutes
} deriving (Eq, Show)
2019-08-10 10:01:36 -04:00
instance FromJSON PlayerStats where
parseJSON = withObject "PlayerStats" $ \v -> PlayerStats
<$> v .: "goals"
<*> v .: "assists"
<*> v .: "penalty_mins"
instance ToJSON PlayerStats where
toJSON (PlayerStats g a pm) = object
[ "goals" .= g
, "assists" .= a
, "penalty_mins" .= pm
]
toEncoding (PlayerStats g a pm) = pairs $
"goals" .= g <>
"assists" .= a <>
"penalty_mins" .= pm
2019-08-11 10:24:39 -04:00
-- | Represents a goalie
data Goalie = Goalie
{ _gNumber :: Int
-- ^ The goalie's number
, _gName :: String
-- ^ The goalie's name
, _gYtd :: GoalieStats
-- ^ The goalie's year-to-date stats
, _gLifetime :: GoalieStats
-- ^ The goalie's lifetime stats
} deriving (Eq, Show)
instance FromJSON Goalie where
parseJSON = withObject "Goalie" $ \v -> Goalie
<$> v .: "number"
<*> v .: "name"
<*> v .: "ytd"
<*> v .: "lifetime"
instance ToJSON Goalie where
toJSON (Goalie num name ytd lt) = object
[ "number" .= num
, "name" .= name
, "ytd" .= ytd
, "lifetime" .= lt
]
toEncoding (Goalie num name ytd lt) = pairs $
"number" .= num <>
"name" .= name <>
"ytd" .= ytd <>
"lifetime" .= lt
-- | Represents a goalie's stats
data GoalieStats = GoalieStats
{ _gsGames :: Int
-- ^ The number of games played
, _gsMinsPlayed :: Int
-- ^ The number of minutes played
, _gsGoalsAllowed :: Int
-- ^ The number of goals allowed
, _gsGoalsAgainst :: Int
-- ^ The number of goals against
, _gsWins :: Int
-- ^ The number of wins
, _gsLosses :: Int
-- ^ The number of losses
, _gsTies :: Int
-- ^ The number of ties
} deriving (Eq, Show)
instance FromJSON GoalieStats where
parseJSON = withObject "GoalieStats" $ \v -> GoalieStats
<$> v .: "games"
<*> v .: "mins_played"
<*> v .: "goals_allowed"
<*> v .: "goals_against"
<*> v .: "wins"
<*> v .: "losses"
<*> v .: "ties"
instance ToJSON GoalieStats where
toJSON (GoalieStats g m al ag w l t) = object
[ "games" .= g
, "mins_played" .= m
, "goals_allowed" .= al
, "goals_against" .= ag
, "wins" .= w
, "losses" .= l
, "ties" .= t
]
toEncoding (GoalieStats g m al ag w l t) = pairs $
"games" .= g <>
"mins_played" .= m <>
"goals_allowed" .= al <>
"goals_against" .= ag <>
"wins" .= w <>
"losses" .= l <>
"ties" .= t
2019-08-24 16:23:56 -04:00
-- | Defines a user prompt
data Prompt = Prompt
{ promptDrawer :: ProgState -> Update ()
-- ^ Draws the prompt to thr screen
, promptCharCheck :: Char -> Bool
-- ^ Determines whether or not the character is valid
, promptAction :: String -> Action ()
-- ^ Action to perform when the value is entered
, promptFunctionKey :: Integer -> Action ()
-- ^ Action to perform when a function key is pressed
}
2019-08-19 23:58:18 -04:00
makeLenses ''ProgState
2019-08-22 01:18:02 -04:00
makeLenses ''GameState
2019-08-16 11:49:04 -04:00
makeLenses ''Database
2019-08-09 11:06:13 -04:00
makeLenses ''Player
makeLenses ''PlayerStats
2019-08-11 10:24:39 -04:00
makeLenses ''Goalie
makeLenses ''GoalieStats
2019-08-09 11:06:13 -04:00
2019-08-22 13:05:25 -04:00
gameTypeL :: Lens' ProgMode (Maybe GameType)
gameTypeL = lens
(\case
NewGame gs -> gs ^. gameType
_ -> Nothing)
(\m gt -> case m of
NewGame gs -> NewGame $ gs & gameType .~ gt
_ -> NewGame $ newGameState & gameType .~ gt)
otherTeamL :: Lens' ProgMode String
otherTeamL = lens
(\case
NewGame gs -> gs ^. otherTeam
_ -> "")
(\m ot -> case m of
NewGame gs -> NewGame $ gs & otherTeam .~ ot
_ -> NewGame $ newGameState & otherTeam .~ ot)
2019-08-22 14:19:43 -04:00
homeScoreL :: Lens' ProgMode (Maybe Int)
homeScoreL = lens
(\case
NewGame gs -> gs ^. homeScore
_ -> Nothing)
(\m hs -> case m of
NewGame gs -> NewGame $ gs & homeScore .~ hs
_ -> NewGame $ newGameState & homeScore .~ hs)
2019-08-22 14:33:39 -04:00
awayScoreL :: Lens' ProgMode (Maybe Int)
awayScoreL = lens
(\case
NewGame gs -> gs ^. awayScore
_ -> Nothing)
(\m as -> case m of
NewGame gs -> NewGame $ gs & awayScore .~ as
_ -> NewGame $ newGameState & awayScore .~ as)
2019-08-22 01:18:02 -04:00
-- | Constructor for a 'ProgState'
2019-08-19 23:58:18 -04:00
newProgState :: ProgState
newProgState = ProgState
2019-08-24 19:02:29 -04:00
{ _database = newDatabase
, _progMode = MainMenu
, _inputBuffer = ""
2019-08-19 23:58:18 -04:00
}
2019-08-22 01:18:02 -04:00
-- | Constructor for a 'GameState'
newGameState :: GameState
newGameState = GameState
2019-08-22 03:10:22 -04:00
{ _gameType = Nothing
, _otherTeam = ""
2019-08-22 03:10:22 -04:00
, _homeScore = Nothing
, _awayScore = Nothing
2019-08-22 01:18:02 -04:00
}
2019-08-16 11:49:04 -04:00
-- | Constructor for a 'Database'
newDatabase :: Database
newDatabase = Database
{ _dbPlayers = []
, _dbGoalies = []
2019-08-19 09:31:24 -04:00
, _dbGames = 0
2019-08-16 11:49:04 -04:00
}
2019-08-09 11:06:13 -04:00
-- | Constructor for a 'Player'
newPlayer
:: Int
-- ^ The player's number
-> String
-- ^ The player's name
-> String
-- ^ The player's position
-> Player
newPlayer num name pos = Player
{ _pNumber = num
, _pName = name
, _pPosition = pos
, _pYtd = newPlayerStats
, _pLifetime = newPlayerStats
}
-- | Constructor for a 'PlayerStats' value
newPlayerStats :: PlayerStats
newPlayerStats = PlayerStats
{ _psGoals = 0
, _psAssists = 0
, _psPMin = 0
}
2019-08-11 10:24:39 -04:00
-- | Constructor for a 'Goalie'
newGoalie
:: Int
-- ^ The goalie's number
-> String
-- ^ The goalie's name
-> Goalie
newGoalie num name = Goalie
{ _gNumber = num
, _gName = name
, _gYtd = newGoalieStats
, _gLifetime = newGoalieStats
}
-- | Constructor for a 'GoalieStats' value
newGoalieStats :: GoalieStats
newGoalieStats = GoalieStats
{ _gsGames = 0
, _gsMinsPlayed = 0
, _gsGoalsAllowed = 0
, _gsGoalsAgainst = 0
, _gsWins = 0
, _gsLosses = 0
, _gsTies = 0
}
2019-08-22 03:06:36 -04:00
-- | Determines the team's points
teamScore :: ProgState -> Maybe Int
teamScore s = case s ^. progMode . gameTypeL of
Just HomeGame -> s ^. progMode . homeScoreL
Just AwayGame -> s ^. progMode . awayScoreL
Nothing -> Nothing
2019-08-22 03:06:36 -04:00
2019-08-09 11:06:13 -04:00
-- | Calculates a player's points
pPoints :: PlayerStats -> Int
pPoints s = s^.psGoals + s^.psAssists