129 Commits

Author SHA1 Message Date
Jonathan Lamothe
994087a0e6 version 0.11.0 2020-01-23 17:18:39 -05:00
Jonathan Lamothe
7fbeaac933 Merge pull request #66 from mtlstats/master-menu
Master menu
2020-01-22 21:53:09 -05:00
Jonathan Lamothe
de56f4f94d updated change log 2020-01-22 21:43:09 -05:00
Jonathan Lamothe
04ba17324e centre menus horizontally 2020-01-22 21:23:32 -05:00
Jonathan Lamothe
d6ae171dc8 pad menu selections to same width 2020-01-22 21:10:21 -05:00
Jonathan Lamothe
72b6f05700 changed menu style
...to be closer to the original program's menu style
2020-01-22 20:59:09 -05:00
Jonathan Lamothe
4c7a756c5e updated change log 2020-01-22 16:30:19 -05:00
Jonathan Lamothe
ea3ca4e578 Merge pull request #65 from mtlstats/title-screen
Title screen
2020-01-22 13:58:12 -05:00
Jonathan Lamothe
179a864cfa added header to title page 2020-01-22 13:48:34 -05:00
Jonathan Lamothe
f2b2ff3fef centred title screen 2020-01-22 13:43:58 -05:00
Jonathan Lamothe
9c2e2291c8 draw box around title 2020-01-22 08:49:13 -05:00
Jonathan Lamothe
abad72ce01 built basic title screen 2020-01-22 00:39:06 -05:00
Jonathan Lamothe
a9d4d3351f implemented title screen controller 2020-01-21 22:55:22 -05:00
Jonathan Lamothe
45aea607b2 added title screen logic branch 2020-01-21 22:20:01 -05:00
Jonathan Lamothe
be9d7d80bb updated change log 2020-01-16 22:16:20 -05:00
Jonathan Lamothe
683c36e2b6 Merge pull request #64 from mtlstats/edit-standings
Edit standings
2020-01-16 21:52:41 -05:00
Jonathan Lamothe
83c408cea2 implemented editing prompts 2020-01-16 21:46:35 -05:00
Jonathan Lamothe
dcbd68cdda implemented editHomeStandingsC and editAwayStandingsC 2020-01-16 21:10:14 -05:00
Jonathan Lamothe
717f2d5932 made standings table prettier 2020-01-16 19:58:07 -05:00
Jonathan Lamothe
d5de834510 implemented edit functions in Mtlstats.Actions.EditState module 2020-01-16 19:47:12 -05:00
Jonathan Lamothe
75a47ca852 implemented Mtlstats.Menu.EditStandings.subMenu 2020-01-16 17:54:05 -05:00
Jonathan Lamothe
d4de7c6f8b implemented editHomeStandings and editAwayStandings 2020-01-16 17:43:53 -05:00
Jonathan Lamothe
d50d055b0b implemented editHomeStandings and editAwayStandings 2020-01-16 17:17:24 -05:00
Jonathan Lamothe
9c7c295a4b implemented editAwayStandings 2020-01-16 15:00:08 -05:00
Jonathan Lamothe
49963277be implemented editHomeStandings 2020-01-16 12:42:33 -05:00
Jonathan Lamothe
264d9f81e2 moved editStandings to Mtlstats.Actions.EditStandings module 2020-01-16 00:03:31 -05:00
Jonathan Lamothe
6a0d1f7203 implemented editStandingsMenu 2020-01-15 23:21:37 -05:00
Jonathan Lamothe
18683c1c6e implemented Mtlstats.Control.EditStandings.valsFor 2020-01-15 01:05:45 -05:00
Jonathan Lamothe
107ed507e2 implemented Mtlstats.Control.EditStandings.header 2020-01-15 01:00:26 -05:00
Jonathan Lamothe
baf040deea implemented editStandingsC 2020-01-15 00:43:48 -05:00
Jonathan Lamothe
c3bac5e624 created Mtlstats.Control.EditStandings module 2020-01-15 00:34:45 -05:00
Jonathan Lamothe
119cb873eb implemented editStandings 2020-01-15 00:26:46 -05:00
Jonathan Lamothe
82603ba504 added "Edit Standings" to edit menu 2020-01-15 00:15:58 -05:00
Jonathan Lamothe
a909b9ba7a added EditStandings mode 2020-01-15 00:08:04 -05:00
Jonathan Lamothe
802bf7314e fixed formatting of change log 2020-01-14 23:33:39 -05:00
Jonathan Lamothe
a3124aca58 Merge pull request #63 from mtlstats/save-db
save a copy of the database on new season
2020-01-14 03:29:52 -05:00
Jonathan Lamothe
f113e46564 updated change log 2020-01-14 03:23:39 -05:00
Jonathan Lamothe
39646f3fa7 save a copy of the database on start of new season 2020-01-14 03:21:40 -05:00
Jonathan Lamothe
2bf8d15bd4 logic branch for database saving on new season 2020-01-14 02:42:30 -05:00
Jonathan Lamothe
3009a8f60c Merge pull request #62 from mtlstats/clear-rookies
clear rookies on new (regular) season
2020-01-11 02:39:41 -05:00
Jonathan Lamothe
3b4ce50ae8 clear rookies on new (regular) season 2020-01-11 02:30:09 -05:00
Jonathan Lamothe
fcfbcea72f Merge pull request #61 from mtlstats/active-col
Added active field to players/goalies
2020-01-11 01:59:51 -05:00
Jonathan Lamothe
d132ebd502 updated change log 2020-01-11 01:52:40 -05:00
Jonathan Lamothe
75cd253f3f allow user to toggle active flag for Player/Goalie 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
063bebfbb5 test active field in JSON for Player/Goalie 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
7923827d22 flag inactive goalies in goalieName 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
461fb5d942 mark inactive players in playerName 2020-01-11 01:27:01 -05:00
Jonathan Lamothe
e38275aefe added active field to Player and Goalie 2020-01-11 01:21:16 -05:00
Jonathan Lamothe
dd6f604cd7 version 0.10.0 2020-01-11 00:30:51 -05:00
Jonathan Lamothe
1763f142f1 updated copyright 2020-01-11 00:29:45 -05:00
Jonathan Lamothe
b442b6a360 updated change log 2020-01-09 01:55:57 -05:00
Jonathan Lamothe
119c28ef18 Merge pull request #60 from mtlstats/rookie-col
Add rookie flag to players/goalies
2020-01-09 01:54:48 -05:00
Jonathan Lamothe
b69b3fce7a fixed editSelectedGoalie test labels 2020-01-09 01:43:35 -05:00
Jonathan Lamothe
59026de077 use editSelectedGoalie for all goalie editing 2020-01-09 01:35:37 -05:00
Jonathan Lamothe
52f1e34d49 implemented rookie flag toggling for goalies 2020-01-09 01:31:24 -05:00
Jonathan Lamothe
2c561e9807 use editSelectedPlayer for all player edits 2020-01-09 01:23:20 -05:00
Jonathan Lamothe
e2aeb5bfa4 enable toggling of rookie flag for players 2020-01-09 01:23:20 -05:00
Jonathan Lamothe
5b40a5942b mark rookies in reports 2020-01-09 00:00:05 -05:00
Jonathan Lamothe
ee3cea5643 mark rookies in goalieSummary 2020-01-08 23:54:16 -05:00
Jonathan Lamothe
5209c4a296 mark rookies in playerSummary 2020-01-04 12:10:19 -05:00
Jonathan Lamothe
e077c32956 implemented goalieName 2020-01-04 11:02:58 -05:00
Jonathan Lamothe
8dcef502be implemented playerName 2020-01-03 22:01:09 -05:00
Jonathan Lamothe
3ee97406f1 make database less brittle when something's wrong with the JSON file 2020-01-03 21:37:33 -05:00
Jonathan Lamothe
2768934c7c added rookie field to Player and Goalie values 2020-01-03 21:33:39 -05:00
Jonathan Lamothe
6c8ec21ffe Merge pull request #59 from mtlstats/line-numbers
add line numbers to lifetime player/goalie reports
2020-01-02 23:57:52 -05:00
Jonathan Lamothe
ba3f8a5a6c updated change log 2020-01-02 23:51:36 -05:00
Jonathan Lamothe
3a71dc1e62 add line numbers to lifetime goalie report 2020-01-02 23:50:21 -05:00
Jonathan Lamothe
d14f2ba527 line numbers on lifetime player report 2020-01-02 23:43:44 -05:00
Jonathan Lamothe
acd45229e7 Merge pull request #58 from mtlstats/edit-shutouts
allow user to edit goalie shutouts
2020-01-02 00:48:05 -05:00
Jonathan Lamothe
aff1d5c255 allow user to edit goalie shutouts 2020-01-02 00:42:04 -05:00
Jonathan Lamothe
0448a4beee updated change log 2020-01-02 00:20:26 -05:00
Jonathan Lamothe
ddb9394ab7 Merge pull request #57 from mtlstats/batch-edit
Allow editing of player/goalie YTD/lifetime stats at once
2020-01-02 00:16:39 -05:00
Jonathan Lamothe
071aa3bd8e allow batch editing of goalie YTD/lifetime stats 2020-01-02 00:07:29 -05:00
Jonathan Lamothe
ac95601609 removed (redundant) Mtlstats.Actions.EditGoalie module 2020-01-01 23:40:24 -05:00
Jonathan Lamothe
9606436e9e don't edit goalie stats when no input entered 2020-01-01 23:36:37 -05:00
Jonathan Lamothe
30807b7e2e implemented batch editing of all player ytd/lifetime stats 2020-01-01 23:09:07 -05:00
Jonathan Lamothe
34b743a55b don't edit player values when no new value entered 2020-01-01 23:09:07 -05:00
Jonathan Lamothe
63bd9a6de4 implemented numPromptWithFallback 2019-12-31 22:44:37 -05:00
Jonathan Lamothe
1f3ff5912c Merge pull request #56 from mtlstats/edit-return
make player edit prompts return to the appropriate menus
2019-12-28 21:58:35 -05:00
Jonathan Lamothe
7bb0981ed6 make player edit prompts return to the appropriate menus 2019-12-28 21:53:23 -05:00
Jonathan Lamothe
eb4107365c Merge pull request #55 from mtlstats/fix-case
force player/goalie names to correct case when editing
2019-12-28 21:36:24 -05:00
Jonathan Lamothe
6238e39f69 force player/goalie names to correct case when editing 2019-12-28 21:31:42 -05:00
Jonathan Lamothe
1adf6de990 Merge pull request #54 from mtlstats/player-zero
don't show player zero in reports
2019-12-28 21:05:23 -05:00
Jonathan Lamothe
2840298467 don't show player zero in reports 2019-12-28 20:59:04 -05:00
Jonathan Lamothe
89fe646d0e version 0.9.0 2019-12-27 00:54:08 -05:00
Jonathan Lamothe
b35136944c Merge pull request #53 from mtlstats/edit-menu
implement edit menu
2019-12-17 22:57:42 -05:00
Jonathan Lamothe
4d41c454a1 updated change log 2019-12-17 22:52:21 -05:00
Jonathan Lamothe
18ba758c0c changed return wording on player/goalie edit menus 2019-12-17 22:50:39 -05:00
Jonathan Lamothe
3aedd01b08 make player/goalie edit return to edit menu on completion 2019-12-17 22:47:17 -05:00
Jonathan Lamothe
235dd4e611 return to edit menu after player/goalie creation 2019-12-17 12:30:55 -05:00
Jonathan Lamothe
adf09c2cc4 moved player/goalie creation to edit menu 2019-12-17 12:23:53 -05:00
Jonathan Lamothe
a44ecc5e24 implemented edit 2019-12-17 12:16:26 -05:00
Jonathan Lamothe
9980a095ed added edit menu to main menu 2019-12-17 12:05:10 -05:00
Jonathan Lamothe
1d6a4aa7f3 implemented editMenu 2019-12-17 12:05:10 -05:00
Jonathan Lamothe
8988ad9146 implemented Mtlstats.Control.editMenuC 2019-12-17 11:38:35 -05:00
Jonathan Lamothe
59d48ec154 added EditMenu mode 2019-12-17 11:32:32 -05:00
Jonathan Lamothe
be990538bc Merge pull request #52 from mtlstats/hlint
hlint suggestions
2019-12-17 11:27:41 -05:00
Jonathan Lamothe
55c8806186 hlint suggestions
hlint didn't like reverse, and suggested using Data.Ord Down instead
2019-12-17 11:19:38 -05:00
Jonathan Lamothe
0ecf899b56 Merge pull request #51 from mtlstats/sort-players
sort players in YTD/lifetime reports by points
2019-12-15 13:30:47 -05:00
Jonathan Lamothe
2f06fd221d sort descending 2019-12-15 13:26:22 -05:00
Jonathan Lamothe
f1227da9ca sort players in YTD/lifetime reports by points 2019-12-15 13:19:12 -05:00
Jonathan Lamothe
38db3c8d8f Merge pull request #50 from mtlstats/no-totals
don't show totals in lifetime stats
2019-12-15 12:33:30 -05:00
Jonathan Lamothe
2b9a21c28b don't show totals in lifetime stats 2019-12-15 12:27:06 -05:00
Jonathan Lamothe
84c487dba5 typo in change log 2019-12-15 11:05:22 -05:00
Jonathan Lamothe
6345e3d5d8 Merge pull request #49 from mtlstats/auto-capitalize
Auto capitalize player/goalie names
2019-12-14 01:25:44 -05:00
Jonathan Lamothe
0ca03b7f21 updated change log 2019-12-14 01:19:18 -05:00
Jonathan Lamothe
482f42dca7 force proper name capitalization on player/goalie creation 2019-12-14 01:15:00 -05:00
Jonathan Lamothe
996bad94f1 force capitalization of player/goalie names in player selection 2019-12-14 01:09:40 -05:00
Jonathan Lamothe
4ca0b54de2 Merge pull request #48 from mtlstats/bugfix
Bugfix: display lifetime statistics in report instead of year-to-date
2019-12-14 00:16:55 -05:00
Jonathan Lamothe
3738088dde display lifetime stats in report 2019-12-13 11:43:22 -05:00
Jonathan Lamothe
1ec9e93f16 hlint recommenfations 2019-12-13 11:42:49 -05:00
Jonathan Lamothe
9534218797 version 0.8.0 2019-12-12 18:24:30 -05:00
Jonathan Lamothe
d7d3d1a4fd Merge pull request #47 from mtlstats/goalie-average
correctly calculate goalie average
2019-12-02 20:53:59 -05:00
Jonathan Lamothe
86c4fe316e correctly calculate goalie average 2019-12-02 20:48:09 -05:00
Jonathan Lamothe
d5ac42268f Merge pull request #46 from mtlstats/remove-extra-stats
removed unnecessary goalie stats from game report
2019-12-02 20:23:58 -05:00
Jonathan Lamothe
df26e9d265 removed unnecessary goalie stats from game report 2019-12-02 20:17:19 -05:00
Jonathan Lamothe
cb5f2d7d15 Merge pull request #45 from mtlstats/filter-game-stats
filter out players without points from game report
2019-12-02 15:20:03 -05:00
Jonathan Lamothe
152ea76bda filter out players without points from game report 2019-12-02 15:08:18 -05:00
Jonathan Lamothe
36ab31a17c Merge pull request #44 from mtlstats/bugfix-uppercase-team
bugfix: force other team name to uppercase
2019-12-02 14:54:07 -05:00
Jonathan Lamothe
768cb47fac bugfix: force other team name to uppercase 2019-12-02 14:43:08 -05:00
Jonathan Lamothe
427ad12603 Merge pull request #43 from mtlstats/bugfix-uc-hangs
bugfix: uppercase prompt hangs
2019-12-02 14:34:39 -05:00
Jonathan Lamothe
1ca2ffc378 bugfix: uppercase prompt hangs 2019-12-02 13:46:43 -05:00
Jonathan Lamothe
9e6b71c464 Merge pull request #42 from mtlstats/lower-case
allow lower case player names
2019-11-30 21:53:07 -05:00
Jonathan Lamothe
2f4e963e41 update change log 2019-11-30 21:09:24 -05:00
Jonathan Lamothe
05af939963 force player position to upper case 2019-11-30 13:02:42 -05:00
Jonathan Lamothe
8af7974c8f made playerSearch and goalieSearch case insensitive 2019-11-30 12:54:50 -05:00
Jonathan Lamothe
f7cfd5d835 allow lower case
- allow strPrompt to accept lower case letters
- implemented ucStrPrompt which forces characters to upper case
2019-11-30 11:52:06 -05:00
Jonathan Lamothe
cc495fa589 Merge pull request #41 from mtlstats/bugfix
bugfix: removed quotation makrks from goalie name in report
2019-11-29 20:20:06 -05:00
Jonathan Lamothe
9c5d166f31 bugfix: removed quotation makrks from goalie name in report 2019-11-29 20:12:45 -05:00
50 changed files with 1891 additions and 1256 deletions

View File

@@ -1,5 +1,36 @@
# Changelog for mtlstats # Changelog for mtlstats
## 0.11.0
- Added active flag to players/goalies
- Clear rookie flag on new (regular) season
- Save a copy of the database on new season
- Implemented game standings editing
- Added title screen
- Changed sytling of menus
## 0.10.0
- Don't show player number zero in reports
- Fixed player/goalie name capitalisation on edit
- Return to correct edit menus after editing player stats
- Enabled batch editing of player/goalie YTD/lifetime stats
- Bugfix: allow user to edit goalie shutouts
- Added line numbers to lifetime player/goalie reports
- Implemented rookie flag
## 0.9.0
- Bugfix: Display lifetime stats in report, not YTD
- Force expected capitalization on player/goalie names
- Don't show lifetime totals in report
- Sort players in YTD and lifetime reports by points
- Moved player/goalie creation/editing to edit submenu
## 0.8.0
- Bugfix: removed quotation marks from goalie names in report
- Allow lower case player names
- Don't show players without points in game report
- Removed unnecessary goalie statistics from game report
- Fixed goalie average calculation
## 0.7.0 ## 0.7.0
- Shortened views to fit within 25 lines - Shortened views to fit within 25 lines
- Implemented goalie reports - Implemented goalie reports
@@ -10,24 +41,20 @@
- Reset game standings on new season - Reset game standings on new season
## 0.5.0 ## 0.5.0
- Fixed player creation bug - Fixed player creation bug
- Prompt for goalie informaiton on game data entry - Prompt for goalie informaiton on game data entry
- Implemented player editing - Implemented player editing
## v0.4.0 ## v0.4.0
- Record penalty minutes - Record penalty minutes
- Calculate total game statistics - Calculate total game statistics
- Generate year-to-date statistics report - Generate year-to-date statistics report
## v0.3.0 ## v0.3.0
- Record goals and assists - Record goals and assists
- Track goals for and goals against - Track goals for and goals against
## v0.2.0 ## v0.2.0
- Overtime losses don't count in the loss column - Overtime losses don't count in the loss column
- Confirm game data with user before updating stats - Confirm game data with user before updating stats
- Implemented player creation - Implemented player creation

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
name: mtlstats name: mtlstats
version: 0.7.0 version: 0.11.0
github: "mtlstats/mtlstats" github: "mtlstats/mtlstats"
license: GPL-3 license: GPL-3
author: "Jonathan Lamothe" author: "Jonathan Lamothe"

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -24,14 +24,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module Mtlstats.Actions module Mtlstats.Actions
( startNewSeason ( startNewSeason
, resetYtd , resetYtd
, clearRookies
, resetStandings , resetStandings
, startNewGame , startNewGame
, addChar , addChar
, removeChar , removeChar
, createPlayer , createPlayer
, createGoalie , createGoalie
, edit
, editPlayer , editPlayer
, editSelectedPlayer
, editGoalie , editGoalie
, editSelectedGoalie
, addPlayer , addPlayer
, addGoalie , addGoalie
, resetCreatePlayerState , resetCreatePlayerState
@@ -39,17 +43,29 @@ module Mtlstats.Actions
, backHome , backHome
, scrollUp , scrollUp
, scrollDown , scrollDown
, saveDatabase
) where ) where
import Control.Monad.Trans.State (modify) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.State (gets, modify)
import Data.Aeson (encodeFile)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Lens.Micro ((^.), (&), (.~), (%~)) import Lens.Micro ((^.), (&), (.~), (%~))
import System.EasyFile
( createDirectoryIfMissing
, getAppUserDataDirectory
, (</>)
)
import Mtlstats.Config
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Util
-- | Starts a new season -- | Starts a new season
startNewSeason :: ProgState -> ProgState startNewSeason :: ProgState -> ProgState
startNewSeason = (progMode .~ NewSeason) . (database . dbGames .~ 0) startNewSeason
= (progMode .~ NewSeason False)
. (database.dbGames .~ 0)
-- | Resets all players year-to-date stats -- | Resets all players year-to-date stats
resetYtd :: ProgState -> ProgState resetYtd :: ProgState -> ProgState
@@ -57,6 +73,12 @@ resetYtd
= (database . dbPlayers %~ map (pYtd .~ newPlayerStats)) = (database . dbPlayers %~ map (pYtd .~ newPlayerStats))
. (database . dbGoalies %~ map (gYtd .~ newGoalieStats)) . (database . dbGoalies %~ map (gYtd .~ newGoalieStats))
-- | Clears the rookie flag from all players/goalies
clearRookies :: ProgState -> ProgState
clearRookies = database
%~ (dbPlayers %~ map (pRookie .~ False))
. (dbGoalies %~ map (gRookie .~ False))
-- | Resets game standings -- | Resets game standings
resetStandings :: ProgState -> ProgState resetStandings :: ProgState -> ProgState
resetStandings = database resetStandings = database
@@ -82,7 +104,7 @@ removeChar = inputBuffer %~ \case
-- | Starts player creation mode -- | Starts player creation mode
createPlayer :: ProgState -> ProgState createPlayer :: ProgState -> ProgState
createPlayer = let createPlayer = let
callback = modify $ progMode .~ MainMenu callback = modify edit
cps = newCreatePlayerState cps = newCreatePlayerState
& cpsSuccessCallback .~ callback & cpsSuccessCallback .~ callback
& cpsFailureCallback .~ callback & cpsFailureCallback .~ callback
@@ -91,20 +113,50 @@ createPlayer = let
-- | Starts goalie creation mode -- | Starts goalie creation mode
createGoalie :: ProgState -> ProgState createGoalie :: ProgState -> ProgState
createGoalie = let createGoalie = let
callback = modify $ progMode .~ MainMenu callback = modify edit
cgs = newCreateGoalieState cgs = newCreateGoalieState
& cgsSuccessCallback .~ callback & cgsSuccessCallback .~ callback
& cgsFailureCallback .~ callback & cgsFailureCallback .~ callback
in progMode .~ CreateGoalie cgs in progMode .~ CreateGoalie cgs
-- | Launches the edit menu
edit :: ProgState -> ProgState
edit = progMode .~ EditMenu
-- | Starts the player editing process -- | Starts the player editing process
editPlayer :: ProgState -> ProgState editPlayer :: ProgState -> ProgState
editPlayer = progMode .~ EditPlayer newEditPlayerState editPlayer = progMode .~ EditPlayer newEditPlayerState
-- | Edits the selected 'Player'
editSelectedPlayer
:: (Player -> Player)
-- ^ The modification to be made to the 'Player'
-> ProgState
-> ProgState
editSelectedPlayer f s = fromMaybe s $ do
n <- s^.progMode.editPlayerStateL.epsSelectedPlayer
let
players = s^.database.dbPlayers
players' = modifyNth n f players
Just $ s & database.dbPlayers .~ players'
-- | Starts the 'Goalie' editing process -- | Starts the 'Goalie' editing process
editGoalie :: ProgState -> ProgState editGoalie :: ProgState -> ProgState
editGoalie = progMode .~ EditGoalie newEditGoalieState editGoalie = progMode .~ EditGoalie newEditGoalieState
-- | Edits the selected 'Goalie'
editSelectedGoalie
:: (Goalie -> Goalie)
-- ^ The modification to be made to the 'Goalie'
-> ProgState
-> ProgState
editSelectedGoalie f s = fromMaybe s $ do
n <- s^.progMode.editGoalieStateL.egsSelectedGoalie
let
goalies = s^.database.dbGoalies
goalies' = modifyNth n f goalies
Just $ s & database.dbGoalies .~ goalies'
-- | Adds the entered player to the roster -- | Adds the entered player to the roster
addPlayer :: ProgState -> ProgState addPlayer :: ProgState -> ProgState
addPlayer s = fromMaybe s $ do addPlayer s = fromMaybe s $ do
@@ -155,3 +207,13 @@ scrollUp = scrollOffset %~ max 0 . pred
-- | Scrolls the display down -- | Scrolls the display down
scrollDown :: ProgState -> ProgState scrollDown :: ProgState -> ProgState
scrollDown = scrollOffset %~ succ scrollDown = scrollOffset %~ succ
-- | Saves the database
saveDatabase :: String -> Action ()
saveDatabase fn = do
db <- gets (^.database)
liftIO $ do
dir <- getAppUserDataDirectory appName
let dbFile = dir </> fn
createDirectoryIfMissing True dir
encodeFile dbFile db

View File

@@ -1,164 +0,0 @@
{- |
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/>.
-}
module Mtlstats.Actions.EditGoalie
( editGoalieNumber
, editGoalieName
, editGoalieYtdGames
, editGoalieYtdMins
, editGoalieYtdGoals
, editGoalieYtdWins
, editGoalieYtdLosses
, editGoalieYtdTies
, editGoalieLtGames
, editGoalieLtMins
, editGoalieLtGoals
, editGoalieLtWins
, editGoalieLtLosses
, editGoalieLtTies
) where
import Control.Monad (void)
import Data.Maybe (fromMaybe)
import Lens.Micro ((^.), (&), (.~), (%~))
import Mtlstats.Types
import Mtlstats.Util
-- | Edits a goalie's number
editGoalieNumber
:: Int
-- ^ New goalie number
-> ProgState
-> ProgState
editGoalieNumber num = editGoalie (gNumber .~ num) EGMenu
-- | Edits a goalie's name
editGoalieName
:: String
-- ^ The new name
-> ProgState
-> ProgState
editGoalieName name = editGoalie (gName .~ name) EGMenu
-- | Edits a goalie's YTD games
editGoalieYtdGames
:: Int
-- ^ The number of games played
-> ProgState
-> ProgState
editGoalieYtdGames games = editGoalie (gYtd.gsGames .~ games) EGYtd
-- | Edits a goalie's YTD minutes
editGoalieYtdMins
:: Int
-- ^ The number of minutes played
-> ProgState
-> ProgState
editGoalieYtdMins mins = editGoalie (gYtd.gsMinsPlayed .~ mins) EGYtd
-- | Edits a goalie's YTD goals allowed
editGoalieYtdGoals
:: Int
-- ^ The number of goals
-> ProgState
-> ProgState
editGoalieYtdGoals goals = editGoalie (gYtd.gsGoalsAllowed .~ goals) EGYtd
-- | Edits a goalie's YTD wins
editGoalieYtdWins
:: Int
-- ^ The number of wins
-> ProgState
-> ProgState
editGoalieYtdWins wins = editGoalie (gYtd.gsWins .~ wins) EGYtd
-- | Edits a goalie's YTD losses
editGoalieYtdLosses
:: Int
-- ^ The number of losses
-> ProgState
-> ProgState
editGoalieYtdLosses losses = editGoalie (gYtd.gsLosses .~ losses) EGYtd
-- | Edits a goalie's YTD ties
editGoalieYtdTies
:: Int
-- ^ The number of ties
-> ProgState
-> ProgState
editGoalieYtdTies ties = editGoalie (gYtd.gsTies .~ ties) EGYtd
-- | Edits a goalie's lifetime games played
editGoalieLtGames
:: Int
-- ^ The number of games
-> ProgState
-> ProgState
editGoalieLtGames games = editGoalie (gLifetime.gsGames .~ games) EGLifetime
-- | Edits a goalie's lifetime minutes played
editGoalieLtMins
:: Int
-- ^ The number of minutes
-> ProgState
-> ProgState
editGoalieLtMins mins = editGoalie (gLifetime.gsMinsPlayed .~ mins) EGLifetime
-- | Edits a goalie's lifetime goals allowed
editGoalieLtGoals
:: Int
-- ^ The number of goals
-> ProgState
-> ProgState
editGoalieLtGoals goals = editGoalie (gLifetime.gsGoalsAllowed .~ goals) EGLifetime
-- | Edits a goalie's lifetime wins
editGoalieLtWins
:: Int
-- ^ The number of wins
-> ProgState
-> ProgState
editGoalieLtWins wins = editGoalie (gLifetime.gsWins .~ wins) EGLifetime
-- | Edits a goalie's lifetime losses
editGoalieLtLosses
:: Int
-- ^ The number of losses
-> ProgState
-> ProgState
editGoalieLtLosses losses = editGoalie (gLifetime.gsLosses .~ losses) EGLifetime
-- | Edits a goalie's lifetime ties
editGoalieLtTies
:: Int
-- ^ The number of ties
-> ProgState
-> ProgState
editGoalieLtTies ties = editGoalie (gLifetime.gsTies .~ ties) EGLifetime
editGoalie :: (Goalie -> Goalie) -> EditGoalieMode -> ProgState -> ProgState
editGoalie f mode s = fromMaybe s $ do
gid <- s^.progMode.editGoalieStateL.egsSelectedGoalie
void $ nth gid $ s^.database.dbGoalies
Just $ s
& database.dbGoalies %~ modifyNth gid f
& progMode.editGoalieStateL.egsMode .~ mode

View File

@@ -0,0 +1,70 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
module Mtlstats.Actions.EditStandings
( editStandings
, editHomeStandings
, editAwayStandings
, editWins
, editLosses
, editOvertime
, editGoalsFor
, editGoalsAgainst
) where
import Lens.Micro ((.~))
import Mtlstats.Types
-- | Enters edit standings mode
editStandings :: ProgState -> ProgState
editStandings = progMode .~ EditStandings ESMMenu
-- | Edits the home standings
editHomeStandings :: ProgState -> ProgState
editHomeStandings = progMode .~ EditStandings (ESMHome ESMSubMenu)
-- | Edits the road standings
editAwayStandings :: ProgState -> ProgState
editAwayStandings = progMode .~ EditStandings (ESMAway ESMSubMenu)
-- | Changes to edit wins mode
editWins :: ProgState -> ProgState
editWins = doEdit ESMEditWins
-- | Changes to edit losses mode
editLosses :: ProgState -> ProgState
editLosses = doEdit ESMEditLosses
-- | Changes to edit overtime mode
editOvertime :: ProgState -> ProgState
editOvertime = doEdit ESMEditOvertime
-- | Changes to edit goals for mode
editGoalsFor :: ProgState -> ProgState
editGoalsFor = doEdit ESMEditGoalsFor
-- | Changes to edit goals against mode
editGoalsAgainst :: ProgState -> ProgState
editGoalsAgainst = doEdit ESMEditGoalsAgainst
doEdit :: ESMSubMode -> ProgState -> ProgState
doEdit = (progMode.editStandingsModeL.esmSubModeL .~)

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -29,8 +29,10 @@ import Lens.Micro.Extras (view)
import qualified UI.NCurses as C import qualified UI.NCurses as C
import Mtlstats.Actions import Mtlstats.Actions
import Mtlstats.Control.TitleScreen
import Mtlstats.Control.EditGoalie import Mtlstats.Control.EditGoalie
import Mtlstats.Control.EditPlayer import Mtlstats.Control.EditPlayer
import Mtlstats.Control.EditStandings
import Mtlstats.Control.NewGame import Mtlstats.Control.NewGame
import Mtlstats.Handlers import Mtlstats.Handlers
import Mtlstats.Menu import Mtlstats.Menu
@@ -41,9 +43,11 @@ import Mtlstats.Types
-- run -- run
dispatch :: ProgState -> Controller dispatch :: ProgState -> Controller
dispatch s = case s^.progMode of dispatch s = case s^.progMode of
TitleScreen -> titleScreenC
MainMenu -> mainMenuC MainMenu -> mainMenuC
NewSeason -> newSeasonC NewSeason flag -> newSeasonC flag
NewGame gs -> newGameC gs NewGame gs -> newGameC gs
EditMenu -> editMenuC
CreatePlayer cps CreatePlayer cps
| null $ cps^.cpsNumber -> getPlayerNumC | null $ cps^.cpsNumber -> getPlayerNumC
| null $ cps^.cpsName -> getPlayerNameC | null $ cps^.cpsName -> getPlayerNameC
@@ -55,6 +59,7 @@ dispatch s = case s^.progMode of
| otherwise -> confirmCreateGoalieC | otherwise -> confirmCreateGoalieC
EditPlayer eps -> editPlayerC eps EditPlayer eps -> editPlayerC eps
EditGoalie egs -> editGoalieC egs EditGoalie egs -> editGoalieC egs
(EditStandings esm) -> editStandingsC esm
mainMenuC :: Controller mainMenuC :: Controller
mainMenuC = Controller mainMenuC = Controller
@@ -62,13 +67,12 @@ mainMenuC = Controller
, handleController = menuHandler mainMenu , handleController = menuHandler mainMenu
} }
newSeasonC :: Controller newSeasonC :: Bool -> Controller
newSeasonC = Controller newSeasonC False = promptController newSeasonPrompt
{ drawController = const $ drawMenu newSeasonMenu newSeasonC True = menuController newSeasonMenu
, handleController = \e -> do
menuHandler newSeasonMenu e editMenuC :: Controller
return True editMenuC = menuController editMenu
}
getPlayerNumC :: Controller getPlayerNumC :: Controller
getPlayerNumC = Controller getPlayerNumC = Controller

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -51,17 +51,19 @@ editC = \case
EGName -> nameC EGName -> nameC
EGYtd -> ytdMenuC EGYtd -> ytdMenuC
EGLifetime -> lifetimeMenuC EGLifetime -> lifetimeMenuC
EGYtdGames -> ytdGamesC EGYtdGames b -> ytdGamesC b
EGYtdMins -> ytdMinsC EGYtdMins b -> ytdMinsC b
EGYtdGoals -> ytdGoalsC EGYtdGoals b -> ytdGoalsC b
EGYtdWins -> ytdWinsC EGYtdShutouts b -> ytdShutoutsC b
EGYtdLosses -> ytdLossesC EGYtdWins b -> ytdWinsC b
EGYtdLosses b -> ytdLossesC b
EGYtdTies -> ytdTiesC EGYtdTies -> ytdTiesC
EGLtGames -> ltGamesC EGLtGames b -> ltGamesC b
EGLtMins -> ltMinsC EGLtMins b -> ltMinsC b
EGLtGoals -> ltGoalsC EGLtGoals b -> ltGoalsC b
EGLtWins -> ltWinsC EGLtShutouts b -> ltShutoutsC b
EGLtLosses -> ltLossesC EGLtWins b -> ltWinsC b
EGLtLosses b -> ltLossesC b
EGLtTies -> ltTiesC EGLtTies -> ltTiesC
menuC :: Controller menuC :: Controller
@@ -79,38 +81,44 @@ ytdMenuC = menuControllerWith header editGoalieYtdMenu
lifetimeMenuC :: Controller lifetimeMenuC :: Controller
lifetimeMenuC = menuControllerWith header editGoalieLtMenu lifetimeMenuC = menuControllerWith header editGoalieLtMenu
ytdGamesC :: Controller ytdGamesC :: Bool -> Controller
ytdGamesC = promptController editGoalieYtdGamesPrompt ytdGamesC = promptController . editGoalieYtdGamesPrompt
ytdMinsC :: Controller ytdMinsC :: Bool -> Controller
ytdMinsC = promptController editGoalieYtdMinsPrompt ytdMinsC = promptController . editGoalieYtdMinsPrompt
ytdGoalsC :: Controller ytdGoalsC :: Bool -> Controller
ytdGoalsC = promptController editGoalieYtdGoalsPrompt ytdGoalsC = promptController . editGoalieYtdGoalsPrompt
ytdWinsC :: Controller ytdShutoutsC :: Bool -> Controller
ytdWinsC = promptController editGoalieYtdWinsPrompt ytdShutoutsC = promptController . editGoalieYtdShutoutsPrompt
ytdLossesC :: Controller ytdWinsC :: Bool -> Controller
ytdLossesC = promptController editGoalieYtdLossesPrompt ytdWinsC = promptController . editGoalieYtdWinsPrompt
ytdLossesC :: Bool -> Controller
ytdLossesC = promptController . editGoalieYtdLossesPrompt
ytdTiesC :: Controller ytdTiesC :: Controller
ytdTiesC = promptController editGoalieYtdTiesPrompt ytdTiesC = promptController editGoalieYtdTiesPrompt
ltGamesC :: Controller ltGamesC :: Bool -> Controller
ltGamesC = promptController editGoalieLtGamesPrompt ltGamesC = promptController . editGoalieLtGamesPrompt
ltMinsC :: Controller ltMinsC :: Bool -> Controller
ltMinsC = promptController editGoalieLtMinsPrompt ltMinsC = promptController . editGoalieLtMinsPrompt
ltGoalsC :: Controller ltGoalsC :: Bool -> Controller
ltGoalsC = promptController editGoalieLtGoalsPrompt ltGoalsC = promptController . editGoalieLtGoalsPrompt
ltWinsC :: Controller ltShutoutsC :: Bool -> Controller
ltWinsC = promptController editGoalieLtWinsPrompt ltShutoutsC = promptController . editGoalieLtShutoutsPrompt
ltLossesC :: Controller ltWinsC :: Bool -> Controller
ltLossesC = promptController editGoalieLtLossesPrompt ltWinsC = promptController . editGoalieLtWinsPrompt
ltLossesC :: Bool -> Controller
ltLossesC = promptController . editGoalieLtLossesPrompt
ltTiesC :: Controller ltTiesC :: Controller
ltTiesC = promptController editGoalieLtTiesPrompt ltTiesC = promptController editGoalieLtTiesPrompt

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -44,11 +44,11 @@ editPlayerC eps
EPPosition -> positionC EPPosition -> positionC
EPYtd -> ytdC EPYtd -> ytdC
EPLifetime -> lifetimeC EPLifetime -> lifetimeC
EPYtdGoals -> ytdGoalsC EPYtdGoals b -> ytdGoalsC b
EPYtdAssists -> ytdAssistsC EPYtdAssists b -> ytdAssistsC b
EPYtdPMin -> ytdPMinC EPYtdPMin -> ytdPMinC
EPLtGoals -> ltGoalsC EPLtGoals b -> ltGoalsC b
EPLtAssists -> ltAssistsC EPLtAssists b -> ltAssistsC b
EPLtPMin -> ltPMinC EPLtPMin -> ltPMinC
selectPlayerC :: Controller selectPlayerC :: Controller
@@ -72,20 +72,20 @@ ytdC = menuControllerWith header editPlayerYtdMenu
lifetimeC :: Controller lifetimeC :: Controller
lifetimeC = menuControllerWith header editPlayerLtMenu lifetimeC = menuControllerWith header editPlayerLtMenu
ytdGoalsC :: Controller ytdGoalsC :: Bool -> Controller
ytdGoalsC = promptController editPlayerYtdGoalsPrompt ytdGoalsC = promptController . editPlayerYtdGoalsPrompt
ytdAssistsC :: Controller ytdAssistsC :: Bool -> Controller
ytdAssistsC = promptController editPlayerYtdAssistsPrompt ytdAssistsC = promptController . editPlayerYtdAssistsPrompt
ytdPMinC :: Controller ytdPMinC :: Controller
ytdPMinC = promptController editPlayerYtdPMinPrompt ytdPMinC = promptController editPlayerYtdPMinPrompt
ltGoalsC :: Controller ltGoalsC :: Bool -> Controller
ltGoalsC = promptController editPlayerLtGoalsPrompt ltGoalsC = promptController . editPlayerLtGoalsPrompt
ltAssistsC :: Controller ltAssistsC :: Bool -> Controller
ltAssistsC = promptController editPlayerLtAssistsPrompt ltAssistsC = promptController . editPlayerLtAssistsPrompt
ltPMinC :: Controller ltPMinC :: Controller
ltPMinC = promptController editPlayerLtPMinPrompt ltPMinC = promptController editPlayerLtPMinPrompt

View File

@@ -0,0 +1,87 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
{-# LANGUAGE LambdaCase #-}
module Mtlstats.Control.EditStandings (editStandingsC) where
import Lens.Micro ((^.))
import qualified UI.NCurses as C
import Mtlstats.Format
import Mtlstats.Menu
import Mtlstats.Menu.EditStandings
import Mtlstats.Prompt
import Mtlstats.Prompt.EditStandings
import Mtlstats.Types
import Mtlstats.Types.Menu
-- | Controller for the edit standings menu
editStandingsC :: EditStandingsMode -> Controller
editStandingsC = \case
ESMMenu -> menuControllerWith header editStandingsMenu
ESMHome m -> editHomeStandingsC m
ESMAway m -> editAwayStandingsC m
editHomeStandingsC :: ESMSubMode -> Controller
editHomeStandingsC = \case
ESMSubMenu -> menuC editHomeStandingsMenu
ESMEditWins -> promptC editHomeWinsPrompt
ESMEditLosses -> promptC editHomeLossesPrompt
ESMEditOvertime -> promptC editHomeOvertimePrompt
ESMEditGoalsFor -> promptC editHomeGoalsForPrompt
ESMEditGoalsAgainst -> promptC editHomeGoalsAgainstPrompt
editAwayStandingsC :: ESMSubMode -> Controller
editAwayStandingsC = \case
ESMSubMenu -> menuC editAwayStandingsMenu
ESMEditWins -> promptC editAwayWinsPrompt
ESMEditLosses -> promptC editAwayLossesPrompt
ESMEditOvertime -> promptC editAwayOvertimePrompt
ESMEditGoalsFor -> promptC editAwayGoalsForPrompt
ESMEditGoalsAgainst -> promptC editAwayGoalsAgainstPrompt
menuC :: Menu () -> Controller
menuC = menuControllerWith header
promptC :: Prompt -> Controller
promptC = promptControllerWith header
header :: ProgState -> C.Update ()
header = do
db <- (^.database)
let
home = db^.dbHomeGameStats
away = db^.dbAwayGameStats
table = numTable [" W", " L", " OT", " GF", " GA"]
[ ( "HOME", valsFor home )
, ( "ROAD", valsFor away )
]
return $ C.drawString $ unlines $ table ++ [""]
valsFor :: GameStats -> [Int]
valsFor gs =
[ gs^.gmsWins
, gs^.gmsLosses
, gs^.gmsOvertime
, gs^.gmsGoalsFor
, gs^.gmsGoalsAgainst
]

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -0,0 +1,142 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
{-# LANGUAGE LambdaCase #-}
module Mtlstats.Control.TitleScreen (titleScreenC) where
import Control.Monad.Trans.State (modify)
import Data.Char (chr)
import qualified UI.NCurses as C
import Mtlstats.Actions
import Mtlstats.Format
import Mtlstats.Types
titleScreenC :: Controller
titleScreenC = Controller
{ drawController = const $ do
(_, cols) <- C.windowSize
C.drawString $ unlines $ map (centre $ fromIntegral $ pred cols)
$ [ ""
, "MONTREAL CANADIENS STATISTICS"
]
++ titleText
++ [ ""
, "Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe"
, "<rheal.lamothe@gmail.com>"
, ""
, "Press any key to continue..."
]
return C.CursorInvisible
, handleController = \case
C.EventCharacter _ -> modify backHome >> return True
C.EventSpecialKey _ -> modify backHome >> return True
_ -> return True
}
titleText :: [String]
titleText = box $ map (map blockify) $ foldl joinBlocks (repeat "")
[chM, chT, chL, chS, chT, chA, chT, chS]
box :: [String] -> [String]
box strs
= [[tl] ++ replicate width horiz ++ [tr]]
++ map (\str -> [vert] ++ str ++ [vert]) strs
++ [[bl] ++ replicate width horiz ++ [br]]
where
width = length $ head strs
tl = chr 0x2554
tr = chr 0x2557
bl = chr 0x255a
br = chr 0x255d
horiz = chr 0x2550
vert = chr 0x2551
blockify :: Char -> Char
blockify = \case
'#' -> chr 0x2588
'>' -> chr 0x2590
'<' -> chr 0x258c
ch -> ch
joinBlocks :: [String] -> [String] -> [String]
joinBlocks = zipWith (++)
chM :: [String]
chM =
[ "##< >##"
, ">## ##<"
, ">##< >##<"
, ">### ###<"
, ">#######<"
, ">#<###>#<"
, ">#<>#<>#<"
, "##< >##"
]
chT :: [String]
chT =
[ ">########<"
, ">## ## ##<"
, ">#< ## >#<"
, " ## "
, " ## "
, " ## "
, " ## "
, " >##< "
]
chL :: [String]
chL =
[ "### "
, ">#< "
, ">#< "
, ">#< "
, ">#< "
, ">#< ##"
, ">#< >##"
, "#######"
]
chS :: [String]
chS =
[ " #####< "
, ">#< ## "
, "## "
, " #####< "
, " >#<"
, " ##"
, ">#< >#<"
, " ###### "
]
chA :: [String]
chA =
[ " >##< "
, " ## "
, " >##< "
, " #### "
, " >#<>#< "
, " ###### "
, ">#< >#<"
, "### ###"
]

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -26,6 +26,7 @@ module Mtlstats.Format
, left , left
, right , right
, centre , centre
, padRight
, overlay , overlay
, month , month
, labelTable , labelTable
@@ -87,6 +88,16 @@ centre n str = let
pad = replicate pLen ' ' pad = replicate pLen ' '
in take n $ pad ++ str ++ repeat ' ' in take n $ pad ++ str ++ repeat ' '
-- | Pads text on the right with spaces to fit a minimum width
padRight
:: Int
-- ^ The width to pad to
-> String
-- ^ The text to pad
-> String
padRight width str =
overlay str $ replicate width ' '
-- | Overlays one string on top of another -- | Overlays one string on top of another
overlay overlay
:: String :: String

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-} -}
module Mtlstats.Helpers.Goalie (goalieDetails) where module Mtlstats.Helpers.Goalie (goalieDetails, goalieName) where
import Lens.Micro ((^.)) import Lens.Micro ((^.))
@@ -31,7 +31,7 @@ goalieDetails :: Goalie -> String
goalieDetails g = let goalieDetails g = let
header = unlines $ labelTable header = unlines $ labelTable
[ ( "Number", show $ g^.gNumber ) [ ( "Number", show $ g^.gNumber )
, ( "Name", g^.gName ) , ( "Name", goalieName g )
] ]
body = unlines $ numTable ["YTD", "Lifetime"] $ map body = unlines $ numTable ["YTD", "Lifetime"] $ map
@@ -39,9 +39,24 @@ goalieDetails g = let
[ ( "Games played", gsGames ) [ ( "Games played", gsGames )
, ( "Mins played", gsMinsPlayed ) , ( "Mins played", gsMinsPlayed )
, ( "Goals allowed", gsGoalsAllowed ) , ( "Goals allowed", gsGoalsAllowed )
, ( "Shutouts", gsShutouts )
, ( "Wins", gsWins ) , ( "Wins", gsWins )
, ( "Losses", gsLosses ) , ( "Losses", gsLosses )
, ( "Ties", gsTies ) , ( "Ties", gsTies )
] ]
in header ++ "\n" ++ body in header ++ "\n" ++ body
-- | Returns the goalie name, modified if they are a rookie
goalieName :: Goalie -> String
goalieName g = let
prefix = if g^.gActive
then ""
else "*"
suffix = if g^.gRookie
then "*"
else ""
in prefix ++ g^.gName ++ suffix

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-} -}
module Mtlstats.Helpers.Player (playerDetails) where module Mtlstats.Helpers.Player (playerDetails, playerName) where
import Lens.Micro ((^.)) import Lens.Micro ((^.))
@@ -32,7 +32,7 @@ playerDetails p = unlines $ top ++ [""] ++ table
where where
top = labelTable top = labelTable
[ ( "Number", show $ p^.pNumber ) [ ( "Number", show $ p^.pNumber )
, ( "Name", p^.pName ) , ( "Name", playerName p )
, ( "Position", p^.pPosition ) , ( "Position", p^.pPosition )
] ]
@@ -43,3 +43,18 @@ playerDetails p = unlines $ top ++ [""] ++ table
, ( "Assists", psAssists ) , ( "Assists", psAssists )
, ( "Penalty mins", psPMin ) , ( "Penalty mins", psPMin )
] ]
-- | Presents a modified version of the player's name indicating
-- whether or not they're a rookie
playerName :: Player -> String
playerName p = let
prefix = if p^.pActive
then ""
else "*"
suffix = if p^.pRookie
then "*"
else ""
in prefix ++ p^.pName ++ suffix

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -31,27 +31,22 @@ module Mtlstats.Menu (
newSeasonMenu, newSeasonMenu,
gameMonthMenu, gameMonthMenu,
gameTypeMenu, gameTypeMenu,
gameGoalieMenu gameGoalieMenu,
editMenu
) where ) where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.State (gets, modify) import Control.Monad.Trans.State (gets, modify)
import Data.Aeson (encodeFile)
import Data.Char (toUpper) import Data.Char (toUpper)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Lens.Micro ((^.), (?~)) import Lens.Micro ((^.), (?~))
import Lens.Micro.Extras (view)
import System.EasyFile
( createDirectoryIfMissing
, getAppUserDataDirectory
, (</>)
)
import qualified UI.NCurses as C import qualified UI.NCurses as C
import Mtlstats.Actions import Mtlstats.Actions
import qualified Mtlstats.Actions.NewGame.GoalieInput as GI import qualified Mtlstats.Actions.NewGame.GoalieInput as GI
import Mtlstats.Actions.EditStandings
import Mtlstats.Config import Mtlstats.Config
import Mtlstats.Format
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Types.Menu import Mtlstats.Types.Menu
import Mtlstats.Util import Mtlstats.Util
@@ -95,7 +90,11 @@ menuStateController menuFunc = Controller
-- | The draw function for a 'Menu' -- | The draw function for a 'Menu'
drawMenu :: Menu a -> C.Update C.CursorMode drawMenu :: Menu a -> C.Update C.CursorMode
drawMenu m = do drawMenu m = do
C.drawString $ show m (_, cols) <- C.windowSize
let
width = fromIntegral $ pred cols
menuText = map (centre width) $ lines $ show m
C.drawString $ unlines menuText
return C.CursorInvisible return C.CursorInvisible
-- | The event handler for a 'Menu' -- | The event handler for a 'Menu'
@@ -108,67 +107,56 @@ menuHandler m _ = return $ m^.menuDefault
-- | The main menu -- | The main menu
mainMenu :: Menu Bool mainMenu :: Menu Bool
mainMenu = Menu "*** MAIN MENU ***" True mainMenu = Menu "MASTER MENU" True
[ MenuItem '1' "New Season" $ [ MenuItem 'A' "NEW SEASON" $
modify startNewSeason >> return True modify startNewSeason >> return True
, MenuItem '2' "New Game" $ , MenuItem 'B' "NEW GAME" $
modify startNewGame >> return True modify startNewGame >> return True
, MenuItem '3' "Create Player" $ , MenuItem 'C' "EDIT MENU" $
modify createPlayer >> return True modify edit >> return True
, MenuItem '4' "Create Goalie" $ , MenuItem 'E' "EXIT" $
modify createGoalie >> return True saveDatabase dbFname >> return False
, MenuItem '5' "Edit Player" $
modify editPlayer >> return True
, MenuItem '6' "Edit Goalie" $
modify editGoalie >> return True
, MenuItem 'X' "Exit" $ do
db <- gets $ view database
liftIO $ do
dir <- getAppUserDataDirectory appName
let dbFile = dir </> dbFname
createDirectoryIfMissing True dir
encodeFile dbFile db
return False
] ]
-- | The new season menu -- | The new season menu
newSeasonMenu :: Menu () newSeasonMenu :: Menu ()
newSeasonMenu = Menu "*** SEASON TYPE ***" () newSeasonMenu = Menu "SEASON TYPE" ()
[ MenuItem 'R' "Regular Season" $ modify [ MenuItem 'R' "REGULAR SEASON" $ modify
$ resetYtd $ resetYtd
. clearRookies
. resetStandings . resetStandings
. startNewGame . startNewGame
, MenuItem 'P' "Playoffs" $ modify , MenuItem 'P' "PLAYOFFS" $ modify
$ resetStandings $ resetStandings
. startNewGame . startNewGame
] ]
-- | Requests the month in which the game took place -- | Requests the month in which the game took place
gameMonthMenu :: Menu () gameMonthMenu :: Menu ()
gameMonthMenu = Menu "Month:" () $ map gameMonthMenu = Menu "MONTH:" () $ map
(\(ch, name, val) -> (\(ch, name, val) ->
MenuItem ch name $ MenuItem ch name $
modify $ progMode.gameStateL.gameMonth ?~ val) modify $ progMode.gameStateL.gameMonth ?~ val)
[ ( 'A', "January", 1 ) [ ( 'A', "JANUARY", 1 )
, ( 'B', "February", 2 ) , ( 'B', "FEBRUARY", 2 )
, ( 'C', "March", 3 ) , ( 'C', "MARCH", 3 )
, ( 'D', "April", 4 ) , ( 'D', "APRIL", 4 )
, ( 'E', "May", 5 ) , ( 'E', "MAY", 5 )
, ( 'F', "June", 6 ) , ( 'F', "JUNE", 6 )
, ( 'G', "July", 7 ) , ( 'G', "JULY", 7 )
, ( 'H', "August", 8 ) , ( 'H', "AUGUST", 8 )
, ( 'I', "September", 9 ) , ( 'I', "SEPTEMBER", 9 )
, ( 'J', "October", 10 ) , ( 'J', "OCTOBER", 10 )
, ( 'K', "November", 11 ) , ( 'K', "NOVEMBER", 11 )
, ( 'L', "December", 12 ) , ( 'L', "DECEMBER", 12 )
] ]
-- | The game type menu (home/away) -- | The game type menu (home/away)
gameTypeMenu :: Menu () gameTypeMenu :: Menu ()
gameTypeMenu = Menu "Game type:" () gameTypeMenu = Menu "GAME TYPE:" ()
[ MenuItem '1' "Home Game" $ [ MenuItem 'H' "HOME GAME" $
modify $ progMode.gameStateL.gameType ?~ HomeGame modify $ progMode.gameStateL.gameType ?~ HomeGame
, MenuItem '2' "Away Game" $ , MenuItem 'A' "AWAY GAME" $
modify $ progMode.gameStateL.gameType ?~ AwayGame modify $ progMode.gameStateL.gameType ?~ AwayGame
] ]
@@ -186,3 +174,20 @@ gameGoalieMenu s = let
(\(ch, (gid, goalie)) -> MenuItem ch (goalieSummary goalie) $ (\(ch, (gid, goalie)) -> MenuItem ch (goalieSummary goalie) $
modify $ GI.setGameGoalie gid) $ modify $ GI.setGameGoalie gid) $
zip ['1'..] goalies zip ['1'..] goalies
-- | The edit menu
editMenu :: Menu ()
editMenu = Menu "EDIT MENU" ()
[ MenuItem 'A' "CREATE PLAYER" $
modify createPlayer
, MenuItem 'B' "CREATE GOALIE" $
modify createGoalie
, MenuItem 'C' "EDIT PLAYER" $
modify editPlayer
, MenuItem 'D' "EDIT GOALIE" $
modify editGoalie
, MenuItem 'E' "EDIT STANDINGS" $
modify editStandings
, MenuItem 'R' "RETURN TO MAIN MENU" $
modify backHome
]

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -26,52 +26,61 @@ module Mtlstats.Menu.EditGoalie
) where ) where
import Control.Monad.Trans.State (modify) import Control.Monad.Trans.State (modify)
import Data.Maybe (maybe) import Lens.Micro ((.~), (%~))
import Lens.Micro ((.~))
import Mtlstats.Actions
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Types.Menu import Mtlstats.Types.Menu
-- | The 'Goalie' edit menu -- | The 'Goalie' edit menu
editGoalieMenu :: Menu () editGoalieMenu :: Menu ()
editGoalieMenu = Menu "*** EDIT GOALTENDER ***" () $ map editGoalieMenu = Menu "EDIT GOALTENDER" () $ map
(\(key, label, val) -> MenuItem key label $ modify $ maybe (\(ch, label, action) -> MenuItem ch label $ modify action)
(progMode .~ MainMenu)
(progMode.editGoalieStateL.egsMode .~)
val)
-- key, label, value -- key, label, value
[ ( '1', "Edit number", Just EGNumber ) [ ( 'A', "EDIT NUMBER", set EGNumber )
, ( '2', "Edit name", Just EGName ) , ( 'B', "EDIT NAME", set EGName )
, ( '3', "Edit YTD stats", Just EGYtd ) , ( 'C', "TOGGLE ROOKIE FLAG", toggleRookie )
, ( '4', "Edit Lifetime stats", Just EGLifetime ) , ( 'D', "TOGGLE ACTIVE FLAG", toggleActive )
, ( 'R', "Return to Main Menu", Nothing ) , ( 'E', "EDIT YTD STATS", set EGYtd )
, ( 'F', "EDIT LIFETIME STATS", set EGLifetime )
, ( 'R', "RETURN TO EDIT MENU", edit )
] ]
where
set mode = progMode.editGoalieStateL.egsMode .~ mode
toggleRookie = editSelectedGoalie (gRookie %~ not)
toggleActive = editSelectedGoalie (gActive %~ not)
-- | The 'Goalie' YTD edit menu -- | The 'Goalie' YTD edit menu
editGoalieYtdMenu :: Menu () editGoalieYtdMenu :: Menu ()
editGoalieYtdMenu = editMenu "*** EDIT GOALTENDER YEAR-TO-DATE ***" editGoalieYtdMenu = editMenu "EDIT GOALTENDER YEAR-TO-DATE"
-- key, label, value -- key, label, value
[ ( '1', "Edit YTD games", EGYtdGames ) [ ( 'A', "EDIT ALL YTD STATS", EGYtdGames True )
, ( '2', "Edit YTD minutes", EGYtdMins ) , ( 'B', "EDIT YTD GAMES", EGYtdGames False )
, ( '3', "Edit YTD goals", EGYtdGoals ) , ( 'C', "EDIT YTD MINUTES", EGYtdMins False )
, ( '4', "Edit YTD wins", EGYtdWins ) , ( 'D', "EDIT YTD GOALS", EGYtdGoals False )
, ( '5', "Edit YTD losses", EGYtdLosses ) , ( 'E', "EDIT YTD SHUTOUTS", EGYtdShutouts False )
, ( '6', "Edit YTD ties", EGYtdTies ) , ( 'F', "EDIT YTD WINS", EGYtdWins False )
, ( 'R', "Return to edit menu", EGMenu ) , ( 'G', "EDIT YTD LOSSES", EGYtdLosses False )
, ( 'H', "EDIT YTD TIES", EGYtdTies )
, ( 'R', "RETURN TO EDIT MENU", EGMenu )
] ]
-- | The 'Goalie' lifetime edit menu -- | The 'Goalie' lifetime edit menu
editGoalieLtMenu :: Menu () editGoalieLtMenu :: Menu ()
editGoalieLtMenu = editMenu editGoalieLtMenu = editMenu
"*** EDIT GOALTENDER LIFETIME ***" "EDIT GOALTENDER LIFETIME"
-- key, label, value -- key, label, value
[ ( '1', "Edit lifetime games", EGLtGames ) [ ( 'A', "EDIT ALL LIFETIME STATS", EGLtGames True )
, ( '2', "Edit lifetime minutes", EGLtMins ) , ( 'B', "EDIT LIFETIME GAMES", EGLtGames False )
, ( '3', "Edit lifetime goals", EGLtGoals ) , ( 'C', "EDIT LIFETIME MINUTES", EGLtMins False )
, ( '4', "Edit lifetime wins", EGLtWins ) , ( 'D', "EDIT LIFETIME GOALS", EGLtGoals False )
, ( '5', "Edit lifetime losses", EGLtLosses ) , ( 'E', "EDIT LIFETIME SHUTOUTS", EGLtShutouts False )
, ( '6', "Edit lifetime ties", EGLtTies ) , ( 'F', "EDIT LIFETIME WINS", EGLtWins False )
, ( 'R', "Return to edit menu", EGMenu ) , ( 'G', "EDIT LIFETIME LOSSES", EGLtLosses False )
, ( 'H', "EDIT LIFETIME TIES", EGLtTies )
, ( 'R', "RETURN TO EDIT MENU", EGMenu )
] ]
editMenu :: String -> [(Char, String, EditGoalieMode)] -> Menu () editMenu :: String -> [(Char, String, EditGoalieMode)] -> Menu ()

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -26,46 +26,55 @@ module Mtlstats.Menu.EditPlayer
) where ) where
import Control.Monad.Trans.State (modify) import Control.Monad.Trans.State (modify)
import Lens.Micro ((.~)) import Lens.Micro ((.~), (%~))
import Mtlstats.Actions
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Types.Menu import Mtlstats.Types.Menu
-- | The 'Player' edit menu -- | The 'Player' edit menu
editPlayerMenu :: Menu () editPlayerMenu :: Menu ()
editPlayerMenu = Menu "*** EDIT PLAYER ***" () $ map editPlayerMenu = Menu "EDIT PLAYER" () $ map
(\(ch, label, mode) -> MenuItem ch label $ case mode of (\(ch, label, action) -> MenuItem ch label $ modify action)
Nothing -> modify $ progMode .~ MainMenu
Just m -> modify $ progMode.editPlayerStateL.epsMode .~ m)
-- key, label, value -- key, label, value
[ ( '1', "Edit number", Just EPNumber ) [ ( 'A', "EDIT NUMBER", set EPNumber )
, ( '2', "Edit name", Just EPName ) , ( 'B', "EDIT NAME", set EPName )
, ( '3', "Edit position", Just EPPosition ) , ( 'C', "EDIT POSITION", set EPPosition )
, ( '4', "Edit YTD stats", Just EPYtd ) , ( 'D', "TOGGLE ROOKIE FLAG", toggleRookie )
, ( '5', "Edit lifetime stats", Just EPLifetime ) , ( 'E', "TOGGLE ACTIVE FLAG", toggleActive )
, ( 'R', "Finished editing", Nothing ) , ( 'F', "EDIT YTD STATS", set EPYtd )
, ( 'G', "EDIT LIFETIME STATS", set EPLifetime )
, ( 'R', "RETURN TO EDIT MENU", edit )
] ]
where
set mode = progMode.editPlayerStateL.epsMode .~ mode
toggleRookie = editSelectedPlayer $ pRookie %~ not
toggleActive = editSelectedPlayer $ pActive %~ not
-- | The 'Player' YTD stats edit menu -- | The 'Player' YTD stats edit menu
editPlayerYtdMenu :: Menu () editPlayerYtdMenu :: Menu ()
editPlayerYtdMenu = editMenu editPlayerYtdMenu = editMenu
"*** EDIT PLAYER YEAR-TO-DATE ***" "EDIT PLAYER YEAR-TO-DATE"
-- key, label, value -- key, label, value
[ ( '1', "Edit YTD goals", EPYtdGoals ) [ ( 'A', "EDIT ALL YTD STATS", EPYtdGoals True )
, ( '2', "Edit YTD assists", EPYtdAssists ) , ( 'B', "EDIT YTD GOALS", EPYtdGoals False )
, ( '3', "Edit YTD penalty mins", EPYtdPMin ) , ( 'C', "EDIT YTD ASSISTS", EPYtdAssists False )
, ( 'R', "Return to player edit menu", EPMenu ) , ( 'D', "EDIT YTD PENALTY MINS", EPYtdPMin )
, ( 'R', "RETURN TO PLAYER EDIT MENU", EPMenu )
] ]
-- | The 'Player' lifetime stats edit menu -- | The 'Player' lifetime stats edit menu
editPlayerLtMenu :: Menu () editPlayerLtMenu :: Menu ()
editPlayerLtMenu = editMenu editPlayerLtMenu = editMenu
"*** EDIT PLAYER LIFETIME ***" "EDIT PLAYER LIFETIME"
-- key, label, value -- key, label, value
[ ( '1', "Edit lifetime goals", EPLtGoals ) [ ( 'A', "EDIT ALL LIFETIME STATS", EPLtGoals True )
, ( '2', "Edit lifetime assits", EPLtAssists ) , ( 'B', "EDIT LIFETIME GOALS", EPLtGoals False )
, ( '3', "Edit lifetime penalty mins", EPLtPMin ) , ( 'C', "EDIT LIFETIME ASSITS", EPLtAssists False )
, ( 'R', "Return to edit player menu", EPMenu ) , ( 'D', "EDIT LIFETIME PENALTY MINS", EPLtPMin )
, ( 'R', "RETURN TO EDIT PLAYER MENU", EPMenu )
] ]
editMenu :: String -> [(Char, String, EditPlayerMode)] -> Menu () editMenu :: String -> [(Char, String, EditPlayerMode)] -> Menu ()

View File

@@ -0,0 +1,64 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
module Mtlstats.Menu.EditStandings
( editStandingsMenu
, editHomeStandingsMenu
, editAwayStandingsMenu
) where
import Control.Monad.Trans.State (modify)
import Mtlstats.Actions
import Mtlstats.Actions.EditStandings
import Mtlstats.Types.Menu
editStandingsMenu :: Menu ()
editStandingsMenu = Menu "EDIT STANDINGS" ()
[ MenuItem 'A' "EDIT HOME STANDINGS" $
modify editHomeStandings
, MenuItem 'B' "EDIT ROAD STANDINGS" $
modify editAwayStandings
, MenuItem 'R' "RETURN TO MAIN MENU" $
modify backHome
]
editHomeStandingsMenu :: Menu ()
editHomeStandingsMenu = subMenu "HOME"
editAwayStandingsMenu :: Menu ()
editAwayStandingsMenu = subMenu "ROAD"
subMenu :: String -> Menu ()
subMenu str = Menu (str ++ " STANDINGS") ()
[ MenuItem 'W' "EDIT WINS" $
modify editWins
, MenuItem 'L' "EDIT LOSSES" $
modify editLosses
, MenuItem 'O' "EDIT OVERTIME GAMES" $
modify editOvertime
, MenuItem 'F' "EDIT GOALS FOR" $
modify editGoalsFor
, MenuItem 'A' "EDIT GOALS AGAINST" $
modify editGoalsAgainst
, MenuItem 'R' "RETURN TO EDIT STANDINGS MENU" $
modify editStandings
]

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -28,9 +28,13 @@ module Mtlstats.Prompt (
promptControllerWith, promptControllerWith,
promptController, promptController,
strPrompt, strPrompt,
ucStrPrompt,
namePrompt,
numPrompt, numPrompt,
numPromptWithFallback,
selectPrompt, selectPrompt,
-- * Individual prompts -- * Individual prompts
newSeasonPrompt,
playerNumPrompt, playerNumPrompt,
playerNamePrompt, playerNamePrompt,
playerPosPrompt, playerPosPrompt,
@@ -44,9 +48,8 @@ module Mtlstats.Prompt (
import Control.Monad (when) import Control.Monad (when)
import Control.Monad.Extra (whenJust) import Control.Monad.Extra (whenJust)
import Control.Monad.Trans.State (gets, modify) import Control.Monad.Trans.State (gets, modify)
import Data.Char (isDigit, toUpper) import Data.Char (isAlphaNum, isDigit, toUpper)
import Data.Foldable (forM_) import Lens.Micro ((^.), (&), (.~), (?~), (%~))
import Lens.Micro ((^.), (&), (.~), (?~))
import Lens.Micro.Extras (view) import Lens.Micro.Extras (view)
import Text.Read (readMaybe) import Text.Read (readMaybe)
import qualified UI.NCurses as C import qualified UI.NCurses as C
@@ -68,10 +71,8 @@ promptHandler p (C.EventCharacter '\n') = do
val <- gets $ view inputBuffer val <- gets $ view inputBuffer
modify $ inputBuffer .~ "" modify $ inputBuffer .~ ""
promptAction p val promptAction p val
promptHandler p (C.EventCharacter c) = let promptHandler p (C.EventCharacter c) =
c' = toUpper c modify $ inputBuffer %~ promptProcessChar p c
in when (promptCharCheck p c') $
modify $ addChar c'
promptHandler _ (C.EventSpecialKey C.KeyBackspace) = promptHandler _ (C.EventSpecialKey C.KeyBackspace) =
modify removeChar modify removeChar
promptHandler p (C.EventSpecialKey k) = promptHandler p (C.EventSpecialKey k) =
@@ -112,11 +113,32 @@ strPrompt
-> Prompt -> Prompt
strPrompt pStr act = Prompt strPrompt pStr act = Prompt
{ promptDrawer = drawSimplePrompt pStr { promptDrawer = drawSimplePrompt pStr
, promptCharCheck = const True , promptProcessChar = \ch -> (++ [ch])
, promptAction = act , promptAction = act
, promptSpecialKey = const $ return () , promptSpecialKey = const $ return ()
} }
-- | Creates an upper case string prompt
ucStrPrompt
:: String
-- ^ The prompt string
-> (String -> Action ())
-- ^ The callback function for the result
-> Prompt
ucStrPrompt pStr act = (strPrompt pStr act)
{ promptProcessChar = \ch -> (++ [toUpper ch]) }
-- | Creates a prompt which forces capitalization of input to
-- accomodate a player or goalie name
namePrompt
:: String
-- ^ The prompt string
-> (String -> Action ())
-- ^ The callback function for the result
-> Prompt
namePrompt pStr act = (strPrompt pStr act)
{ promptProcessChar = capitalizeName }
-- | Builds a numeric prompt -- | Builds a numeric prompt
numPrompt numPrompt
:: String :: String
@@ -124,13 +146,44 @@ numPrompt
-> (Int -> Action ()) -> (Int -> Action ())
-- ^ The callback function for the result -- ^ The callback function for the result
-> Prompt -> Prompt
numPrompt pStr act = Prompt numPrompt pStr = numPromptWithFallback pStr $ return ()
-- | Builds a numeric prompt with a fallback action
numPromptWithFallback
:: String
-- ^ The prompt string
-> Action ()
-- ^ The action to call on invalid (or blank) input
-> (Int -> Action ())
-- ^ The callback function for the result
-> Prompt
numPromptWithFallback pStr fallback act = Prompt
{ promptDrawer = drawSimplePrompt pStr { promptDrawer = drawSimplePrompt pStr
, promptCharCheck = isDigit , promptProcessChar = \ch str -> if isDigit ch
, promptAction = \inStr -> forM_ (readMaybe inStr) act then str ++ [ch]
else str
, promptAction = \inStr -> case readMaybe inStr of
Nothing -> fallback
Just n -> act n
, promptSpecialKey = const $ return () , promptSpecialKey = const $ return ()
} }
-- | Prompts the user for a filename to save a backup of the database
-- to
newSeasonPrompt :: Prompt
newSeasonPrompt = prompt
{ promptProcessChar = \ch str -> if isAlphaNum ch
then str ++ [toUpper ch]
else str
}
where
prompt = strPrompt "Filename to save database: " $ \fn ->
if null fn
then modify backHome
else do
saveDatabase $ fn ++ ".json"
modify $ progMode .~ NewSeason True
-- | Builds a selection prompt -- | Builds a selection prompt
selectPrompt :: SelectParams a -> Prompt selectPrompt :: SelectParams a -> Prompt
selectPrompt params = Prompt selectPrompt params = Prompt
@@ -146,7 +199,7 @@ selectPrompt params = Prompt
in "F" ++ show n ++ ") " ++ desc) in "F" ++ show n ++ ") " ++ desc)
results results
C.moveCursor row col C.moveCursor row col
, promptCharCheck = const True , promptProcessChar = spProcessChar params
, promptAction = \sStr -> if null sStr , promptAction = \sStr -> if null sStr
then spCallback params Nothing then spCallback params Nothing
else do else do
@@ -175,12 +228,12 @@ playerNumPrompt = numPrompt "Player number: " $
-- | Prompts for a new player's name -- | Prompts for a new player's name
playerNamePrompt :: Prompt playerNamePrompt :: Prompt
playerNamePrompt = strPrompt "Player name: " $ playerNamePrompt = namePrompt "Player name: " $
modify . (progMode.createPlayerStateL.cpsName .~) modify . (progMode.createPlayerStateL.cpsName .~)
-- | Prompts for a new player's position -- | Prompts for a new player's position
playerPosPrompt :: Prompt playerPosPrompt :: Prompt
playerPosPrompt = strPrompt "Player position: " $ playerPosPrompt = ucStrPrompt "Player position: " $
modify . (progMode.createPlayerStateL.cpsPosition .~) modify . (progMode.createPlayerStateL.cpsPosition .~)
-- | Prompts tor the goalie's number -- | Prompts tor the goalie's number
@@ -190,7 +243,7 @@ goalieNumPrompt = numPrompt "Goalie number: " $
-- | Prompts for the goalie's name -- | Prompts for the goalie's name
goalieNamePrompt :: Prompt goalieNamePrompt :: Prompt
goalieNamePrompt = strPrompt "Goalie name: " $ goalieNamePrompt = namePrompt "Goalie name: " $
modify . (progMode.createGoalieStateL.cgsName .~) modify . (progMode.createGoalieStateL.cgsName .~)
-- | Selects a player (creating one if necessary) -- | Selects a player (creating one if necessary)
@@ -207,6 +260,7 @@ selectPlayerPrompt pStr callback = selectPrompt SelectParams
, spSearch = \sStr db -> playerSearch sStr (db^.dbPlayers) , spSearch = \sStr db -> playerSearch sStr (db^.dbPlayers)
, spSearchExact = \sStr db -> fst <$> playerSearchExact sStr (db^.dbPlayers) , spSearchExact = \sStr db -> fst <$> playerSearchExact sStr (db^.dbPlayers)
, spElemDesc = playerSummary , spElemDesc = playerSummary
, spProcessChar = capitalizeName
, spCallback = callback , spCallback = callback
, spNotFound = \sStr -> do , spNotFound = \sStr -> do
mode <- gets (^.progMode) mode <- gets (^.progMode)
@@ -235,6 +289,7 @@ selectGoaliePrompt pStr callback = selectPrompt SelectParams
, spSearch = \sStr db -> goalieSearch sStr (db^.dbGoalies) , spSearch = \sStr db -> goalieSearch sStr (db^.dbGoalies)
, spSearchExact = \sStr db -> fst <$> goalieSearchExact sStr (db^.dbGoalies) , spSearchExact = \sStr db -> fst <$> goalieSearchExact sStr (db^.dbGoalies)
, spElemDesc = goalieSummary , spElemDesc = goalieSummary
, spProcessChar = capitalizeName
, spCallback = callback , spCallback = callback
, spNotFound = \sStr -> do , spNotFound = \sStr -> do
mode <- gets (^.progMode) mode <- gets (^.progMode)

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -26,12 +26,14 @@ module Mtlstats.Prompt.EditGoalie
, editGoalieYtdGamesPrompt , editGoalieYtdGamesPrompt
, editGoalieYtdMinsPrompt , editGoalieYtdMinsPrompt
, editGoalieYtdGoalsPrompt , editGoalieYtdGoalsPrompt
, editGoalieYtdShutoutsPrompt
, editGoalieYtdWinsPrompt , editGoalieYtdWinsPrompt
, editGoalieYtdLossesPrompt , editGoalieYtdLossesPrompt
, editGoalieYtdTiesPrompt , editGoalieYtdTiesPrompt
, editGoalieLtGamesPrompt , editGoalieLtGamesPrompt
, editGoalieLtMinsPrompt , editGoalieLtMinsPrompt
, editGoalieLtGoalsPrompt , editGoalieLtGoalsPrompt
, editGoalieLtShutoutsPrompt
, editGoalieLtWinsPrompt , editGoalieLtWinsPrompt
, editGoalieLtLossesPrompt , editGoalieLtLossesPrompt
, editGoalieLtTiesPrompt , editGoalieLtTiesPrompt
@@ -40,7 +42,7 @@ module Mtlstats.Prompt.EditGoalie
import Control.Monad.Trans.State (modify) import Control.Monad.Trans.State (modify)
import Lens.Micro ((.~)) import Lens.Micro ((.~))
import Mtlstats.Actions.EditGoalie import Mtlstats.Actions
import Mtlstats.Prompt import Mtlstats.Prompt
import Mtlstats.Types import Mtlstats.Types
@@ -51,70 +53,171 @@ goalieToEditPrompt = selectGoaliePrompt "Goalie to edit: " $
-- | Prompt to edit a goalie's number -- | Prompt to edit a goalie's number
editGoalieNumberPrompt :: Prompt editGoalieNumberPrompt :: Prompt
editGoalieNumberPrompt = numPrompt "Goalie number: " $ editGoalieNumberPrompt = editNum "Goalie number: " EGMenu
modify . editGoalieNumber (gNumber .~)
-- | Prompt to edit a goalie's name -- | Prompt to edit a goalie's name
editGoalieNamePrompt :: Prompt editGoalieNamePrompt :: Prompt
editGoalieNamePrompt = strPrompt "Goalie name: " $ editGoalieNamePrompt = namePrompt "Goalie name: " $ \name ->
modify . editGoalieName if null name
then goto EGMenu
else doEdit EGMenu $ gName .~ name
-- | Prompt to edit a goalie's YTD games played -- | Prompt to edit a goalie's YTD games played
editGoalieYtdGamesPrompt :: Prompt editGoalieYtdGamesPrompt
editGoalieYtdGamesPrompt = numPrompt "Year-to-date games played: " $ :: Bool
modify . editGoalieYtdGames -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdGamesPrompt batchMode =
editNum "Year-to-date games played: " mode
(gYtd.gsGames .~)
where
mode = if batchMode then EGYtdMins True else EGYtd
-- | Prompt to edit a goalie's YTD minutes played -- | Prompt to edit a goalie's YTD minutes played
editGoalieYtdMinsPrompt :: Prompt editGoalieYtdMinsPrompt
editGoalieYtdMinsPrompt = numPrompt "Year-to-date minutes played: " $ :: Bool
modify . editGoalieYtdMins -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdMinsPrompt batchMode =
editNum "Year-to-date minutes played: " mode
(gYtd.gsMinsPlayed .~)
where
mode = if batchMode then EGYtdGoals True else EGYtd
-- | Prompt to edit a goalie's YTD goales allowed -- | Prompt to edit a goalie's YTD goales allowed
editGoalieYtdGoalsPrompt :: Prompt editGoalieYtdGoalsPrompt
editGoalieYtdGoalsPrompt = numPrompt "Year-to-date goals allowed: " $ :: Bool
modify . editGoalieYtdGoals -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdGoalsPrompt batchMode =
editNum "Year-to-date goals allowed: " mode
(gYtd.gsGoalsAllowed .~)
where
mode = if batchMode then EGYtdShutouts True else EGYtd
-- | Prompt to edit a goalie's YTD shutouts
editGoalieYtdShutoutsPrompt
:: Bool
-- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdShutoutsPrompt batchMode =
editNum "Year-to-date shutouts: " mode
(gYtd.gsShutouts .~)
where
mode = if batchMode then EGYtdWins True else EGYtd
-- | Prompt to edit a goalie's YTD wins -- | Prompt to edit a goalie's YTD wins
editGoalieYtdWinsPrompt :: Prompt editGoalieYtdWinsPrompt
editGoalieYtdWinsPrompt = numPrompt "Year-to-date wins: " $ :: Bool
modify . editGoalieYtdWins -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdWinsPrompt batchMode =
editNum "Year-to-date wins: " mode
(gYtd.gsWins .~)
where
mode = if batchMode then EGYtdLosses True else EGYtd
-- | Prompt to edit a goalie's YTD losses -- | Prompt to edit a goalie's YTD losses
editGoalieYtdLossesPrompt :: Prompt editGoalieYtdLossesPrompt
editGoalieYtdLossesPrompt = numPrompt "Year-to-date losses: " $ :: Bool
modify . editGoalieYtdLosses -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieYtdLossesPrompt batchMode =
editNum "Year-to-date losses: " mode
(gYtd.gsLosses .~)
where
mode = if batchMode then EGYtdTies else EGYtd
-- | Prompt to edit a goalie's YTD ties -- | Prompt to edit a goalie's YTD ties
editGoalieYtdTiesPrompt :: Prompt editGoalieYtdTiesPrompt :: Prompt
editGoalieYtdTiesPrompt = numPrompt "Year-to-date ties: " $ editGoalieYtdTiesPrompt = editNum "Year-to-date ties: " EGYtd
modify . editGoalieYtdTies (gYtd.gsTies .~)
-- | Prompt to edit a goalie's lifetime games played -- | Prompt to edit a goalie's lifetime games played
editGoalieLtGamesPrompt :: Prompt editGoalieLtGamesPrompt
editGoalieLtGamesPrompt = numPrompt "Lifetime games played: " $ :: Bool
modify . editGoalieLtGames -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtGamesPrompt batchMode =
editNum "Lifetime games played: " mode
(gLifetime.gsGames .~)
where
mode = if batchMode then EGLtMins True else EGLifetime
-- | Prompt to edit a goalie's lifetime minutes played -- | Prompt to edit a goalie's lifetime minutes played
editGoalieLtMinsPrompt :: Prompt editGoalieLtMinsPrompt
editGoalieLtMinsPrompt = numPrompt "Lifetime minutes played: " $ :: Bool
modify . editGoalieLtMins -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtMinsPrompt batchMode =
editNum "Lifetime minutes played: " mode
(gLifetime.gsMinsPlayed .~)
where
mode = if batchMode then EGLtGoals True else EGLifetime
-- | Prompt to edit a goalie's lifetime goals allowed -- | Prompt to edit a goalie's lifetime goals allowed
editGoalieLtGoalsPrompt :: Prompt editGoalieLtGoalsPrompt
editGoalieLtGoalsPrompt = numPrompt "Lifetime goals allowed: " $ :: Bool
modify . editGoalieLtGoals -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtGoalsPrompt batchMode =
editNum "Lifetime goals allowed: " mode
(gLifetime.gsGoalsAllowed .~)
where
mode = if batchMode then EGLtShutouts True else EGLifetime
-- | Prompt to edit a goalie's lifetime shutouts
editGoalieLtShutoutsPrompt
:: Bool
-- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtShutoutsPrompt batchMode =
editNum "Lifetime shutouts: " mode
(gLifetime.gsShutouts .~)
where
mode = if batchMode then EGLtWins True else EGLifetime
-- | Prompt to edit a goalie's lifetime wins -- | Prompt to edit a goalie's lifetime wins
editGoalieLtWinsPrompt :: Prompt editGoalieLtWinsPrompt
editGoalieLtWinsPrompt = numPrompt "Lifetime wins: " $ :: Bool
modify . editGoalieLtWins -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtWinsPrompt batchMode =
editNum "Lifetime wins: " mode
(gLifetime.gsWins .~)
where
mode = if batchMode then EGLtLosses True else EGLifetime
-- | Prompt to edit a goalie's lifetime losses -- | Prompt to edit a goalie's lifetime losses
editGoalieLtLossesPrompt :: Prompt editGoalieLtLossesPrompt
editGoalieLtLossesPrompt = numPrompt "Lifetime losses: " $ :: Bool
modify . editGoalieLtLosses -- ^ Indicates whether or not we're in batch mode
-> Prompt
editGoalieLtLossesPrompt batchMode =
editNum "Lifetime losses: " mode
(gLifetime.gsLosses .~)
where
mode = if batchMode then EGLtTies else EGLifetime
-- | Prompt to edit a goalie's lifetime ties -- | Prompt to edit a goalie's lifetime ties
editGoalieLtTiesPrompt :: Prompt editGoalieLtTiesPrompt :: Prompt
editGoalieLtTiesPrompt = numPrompt "Lifetime ties: " $ editGoalieLtTiesPrompt = editNum "Lifetime ties: " EGLifetime
modify . editGoalieLtTies (gLifetime.gsTies .~)
editNum
:: String
-> EditGoalieMode
-> (Int -> Goalie -> Goalie)
-> Prompt
editNum pStr mode f = numPromptWithFallback pStr
(goto mode)
(doEdit mode . f)
doEdit :: EditGoalieMode -> (Goalie -> Goalie) -> Action ()
doEdit mode f = do
modify $ editSelectedGoalie f
goto mode
goto :: EditGoalieMode -> Action ()
goto = modify . (progMode.editGoalieStateL.egsMode .~)

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -31,62 +31,95 @@ module Mtlstats.Prompt.EditPlayer
, editPlayerLtPMinPrompt , editPlayerLtPMinPrompt
) where ) where
import Control.Monad.Extra (whenJustM) import Control.Monad.Trans.State (modify)
import Control.Monad.Trans.State (gets, modify) import Lens.Micro ((.~))
import Lens.Micro ((^.), (.~), (%~))
import Mtlstats.Actions
import Mtlstats.Prompt import Mtlstats.Prompt
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Util
-- | Prompt to edit a player's number -- | Prompt to edit a player's number
editPlayerNumPrompt :: Prompt editPlayerNumPrompt :: Prompt
editPlayerNumPrompt = numPrompt "Player number: " $ editPlayerNumPrompt = editNum "Player number: " EPMenu
editPlayer . (pNumber .~) (pNumber .~)
-- | Prompt to edit a player's name -- | Prompt to edit a player's name
editPlayerNamePrompt :: Prompt editPlayerNamePrompt :: Prompt
editPlayerNamePrompt = strPrompt "Player name: " $ editPlayerNamePrompt = namePrompt "Player name: " $ \name ->
editPlayer . (pName .~) if null name
then goto EPMenu
else doEdit EPMenu $ pName .~ name
-- | Prompt to edit a player's position -- | Prompt to edit a player's position
editPlayerPosPrompt :: Prompt editPlayerPosPrompt :: Prompt
editPlayerPosPrompt = strPrompt "Player position: " $ editPlayerPosPrompt = ucStrPrompt "Player position: " $ \pos ->
editPlayer . (pPosition .~) if null pos
then goto EPMenu
else doEdit EPMenu $ pPosition .~ pos
-- | Prompt to edit a player's year-to-date goals -- | Prompt to edit a player's year-to-date goals
editPlayerYtdGoalsPrompt :: Prompt editPlayerYtdGoalsPrompt
editPlayerYtdGoalsPrompt = numPrompt "Year-to-date goals: " $ :: Bool
editPlayer . (pYtd.psGoals .~) -- ^ Indicates wheter or not we're editing in batch mode
-> Prompt
editPlayerYtdGoalsPrompt batchMode = editNum "Year-to-date goals: " mode
(pYtd.psGoals .~)
where
mode = if batchMode then EPYtdAssists True else EPYtd
-- | Prompt to edit a player's year-to-date assists -- | Prompt to edit a player's year-to-date assists
editPlayerYtdAssistsPrompt :: Prompt editPlayerYtdAssistsPrompt
editPlayerYtdAssistsPrompt = numPrompt "Year-to-date assists: " $ :: Bool
editPlayer . (pYtd.psAssists .~) -- ^ Indicates wheter or not we're editing in batch mode
-> Prompt
editPlayerYtdAssistsPrompt batchMode = editNum "Year-to-date assists: " mode
(pYtd.psAssists .~)
where
mode = if batchMode then EPYtdPMin else EPYtd
-- | Prompt to edit a player's year-to-date penalty minutes -- | Prompt to edit a player's year-to-date penalty minutes
editPlayerYtdPMinPrompt :: Prompt editPlayerYtdPMinPrompt :: Prompt
editPlayerYtdPMinPrompt = numPrompt "Year-to-date penalty minutes: " $ editPlayerYtdPMinPrompt = editNum "Year-to-date penalty minutes: " EPYtd
editPlayer . (pYtd.psPMin .~) (pYtd.psPMin .~)
-- | Prompt to edit a player's lifetime goals -- | Prompt to edit a player's lifetime goals
editPlayerLtGoalsPrompt :: Prompt editPlayerLtGoalsPrompt
editPlayerLtGoalsPrompt = numPrompt "Lifetime goals: " $ :: Bool
editPlayer . (pLifetime.psGoals .~) -- ^ Indicates wheter or not we're editing in batch mode
-> Prompt
editPlayerLtGoalsPrompt batchMode = editNum "Lifetime goals: " mode
(pLifetime.psGoals .~)
where
mode = if batchMode then EPLtAssists True else EPLifetime
-- | Prompt to edit a player's lifetime assists -- | Prompt to edit a player's lifetime assists
editPlayerLtAssistsPrompt :: Prompt editPlayerLtAssistsPrompt
editPlayerLtAssistsPrompt = numPrompt "Lifetime assists: " $ :: Bool
editPlayer . (pLifetime.psAssists .~) -- ^ Indicates wheter or not we're editing in batch mode
-> Prompt
editPlayerLtAssistsPrompt batchMode = editNum "Lifetime assists: " mode
(pLifetime.psAssists .~)
where
mode = if batchMode then EPLtPMin else EPLifetime
-- | Prompt to edit a player's lifetime penalty minutes -- | Prompt to edit a player's lifetime penalty minutes
editPlayerLtPMinPrompt :: Prompt editPlayerLtPMinPrompt :: Prompt
editPlayerLtPMinPrompt = numPrompt "Lifetime penalty minutes: " $ editPlayerLtPMinPrompt = editNum "Lifetime penalty minutes: " EPLifetime
editPlayer . (pLifetime.psPMin .~) (pLifetime.psPMin .~)
editPlayer :: (Player -> Player) -> Action () editNum
editPlayer f = :: String
whenJustM (gets (^.progMode.editPlayerStateL.epsSelectedPlayer)) $ \pid -> -> EditPlayerMode
modify -> (Int -> Player -> Player)
$ (database.dbPlayers %~ modifyNth pid f) -> Prompt
. (progMode.editPlayerStateL.epsMode .~ EPMenu) editNum pStr mode f = numPromptWithFallback pStr
(goto mode)
(doEdit mode . f)
doEdit :: EditPlayerMode -> (Player -> Player) -> Action ()
doEdit mode f = do
modify $ editSelectedPlayer f
goto mode
goto :: EditPlayerMode -> Action ()
goto = modify . (progMode.editPlayerStateL.epsMode .~)

View File

@@ -0,0 +1,89 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
module Mtlstats.Prompt.EditStandings
( editHomeWinsPrompt
, editHomeLossesPrompt
, editHomeOvertimePrompt
, editHomeGoalsForPrompt
, editHomeGoalsAgainstPrompt
, editAwayWinsPrompt
, editAwayLossesPrompt
, editAwayOvertimePrompt
, editAwayGoalsForPrompt
, editAwayGoalsAgainstPrompt
) where
import Control.Monad.Trans.State (modify)
import Lens.Micro ((.~), (%~))
import Mtlstats.Prompt
import Mtlstats.Types
editHomeWinsPrompt :: Prompt
editHomeWinsPrompt =
mkPrompt "Home wins: " (dbHomeGameStats.gmsWins .~)
editHomeLossesPrompt :: Prompt
editHomeLossesPrompt =
mkPrompt "Home losses: " (dbHomeGameStats.gmsLosses .~)
editHomeOvertimePrompt :: Prompt
editHomeOvertimePrompt =
mkPrompt "Home overtime games: " (dbHomeGameStats.gmsOvertime .~)
editHomeGoalsForPrompt :: Prompt
editHomeGoalsForPrompt =
mkPrompt "Home goals for: " (dbHomeGameStats.gmsGoalsFor .~)
editHomeGoalsAgainstPrompt :: Prompt
editHomeGoalsAgainstPrompt =
mkPrompt "Home goals against: " (dbHomeGameStats.gmsGoalsAgainst .~)
editAwayWinsPrompt :: Prompt
editAwayWinsPrompt =
mkPrompt "Road wins: " (dbAwayGameStats.gmsWins .~)
editAwayLossesPrompt :: Prompt
editAwayLossesPrompt =
mkPrompt "Road losses: " (dbAwayGameStats.gmsLosses .~)
editAwayOvertimePrompt :: Prompt
editAwayOvertimePrompt =
mkPrompt "Road overtime games: " (dbAwayGameStats.gmsOvertime .~)
editAwayGoalsForPrompt :: Prompt
editAwayGoalsForPrompt =
mkPrompt "Road goals for: " (dbAwayGameStats.gmsGoalsFor .~)
editAwayGoalsAgainstPrompt :: Prompt
editAwayGoalsAgainstPrompt =
mkPrompt "Road goals against: " (dbAwayGameStats.gmsGoalsAgainst .~)
mkPrompt :: String -> (Int -> Database -> Database) -> Prompt
mkPrompt pStr f = numPromptWithFallback pStr
(modify subMenu)
(\n -> modify
$ (database %~ f n)
. subMenu)
subMenu :: ProgState -> ProgState
subMenu = progMode.editStandingsModeL.esmSubModeL .~ ESMSubMenu

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -55,7 +55,7 @@ gameDayPrompt = numPrompt "Day of month: " $
-- | Prompts for the other team name -- | Prompts for the other team name
otherTeamPrompt :: Prompt otherTeamPrompt :: Prompt
otherTeamPrompt = strPrompt "Other team: " $ otherTeamPrompt = ucStrPrompt "Other team: " $
modify . (progMode.gameStateL.otherTeam .~) modify . (progMode.gameStateL.otherTeam .~)
-- | Prompts for the home score -- | Prompts for the home score

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -21,12 +21,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module Mtlstats.Report (report, gameDate) where module Mtlstats.Report (report, gameDate) where
import Data.List (sortOn)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (fromMaybe, mapMaybe) import Data.Maybe (fromMaybe, mapMaybe)
import Data.Ord (Down (Down))
import Lens.Micro ((^.)) import Lens.Micro ((^.))
import Mtlstats.Config import Mtlstats.Config
import Mtlstats.Format import Mtlstats.Format
import Mtlstats.Helpers.Goalie
import Mtlstats.Helpers.Player
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Util import Mtlstats.Util
@@ -125,15 +129,18 @@ gameStatsReport width s = let
Just (g, stats)) Just (g, stats))
(M.toList $ gs^.gameGoalieStats) (M.toList $ gs^.gameGoalieStats)
in playerReport width "GAME" playerStats criteria (_, ps) = psPoints ps > 0
in filteredPlayerReport width "GAME" criteria True False playerStats
++ [""] ++ [""]
++ goalieReport width goalieStats ++ gameGoalieReport width goalieStats
yearToDateStatsReport :: Int -> ProgState -> [String] yearToDateStatsReport :: Int -> ProgState -> [String]
yearToDateStatsReport width s = let yearToDateStatsReport width s = let
db = s^.database db = s^.database
playerStats = map (\p -> (p, p^.pYtd)) playerStats = sortOn (Down . psPoints . snd)
$ map (\p -> (p, p^.pYtd))
$ filter playerIsActive $ filter playerIsActive
$ db^.dbPlayers $ db^.dbPlayers
@@ -141,23 +148,24 @@ yearToDateStatsReport width s = let
$ filter goalieIsActive $ filter goalieIsActive
$ db^.dbGoalies $ db^.dbGoalies
in playerReport width "YEAR TO DATE" playerStats in playerReport width "YEAR TO DATE" True False playerStats
++ [""] ++ [""]
++ goalieReport width goalieStats ++ goalieReport width True False goalieStats
lifetimeStatsReport :: Int -> ProgState -> [String] lifetimeStatsReport :: Int -> ProgState -> [String]
lifetimeStatsReport width s = let lifetimeStatsReport width s = let
db = s^.database db = s^.database
playerStats = map (\p -> (p, p^.pYtd)) playerStats = sortOn (Down . psPoints . snd)
$ map (\p -> (p, p^.pLifetime))
$ db^.dbPlayers $ db^.dbPlayers
goalieStats = map (\g -> (g, g^.gYtd)) goalieStats = map (\g -> (g, g^.gLifetime))
$ db^.dbGoalies $ db^.dbGoalies
in playerReport width "LIFETIME" playerStats in playerReport width "LIFETIME" False True playerStats
++ [""] ++ [""]
++ goalieReport width goalieStats ++ goalieReport width False True goalieStats
gameDate :: GameState -> String gameDate :: GameState -> String
gameDate gs = fromMaybe "" $ do gameDate gs = fromMaybe "" $ do
@@ -166,9 +174,28 @@ gameDate gs = fromMaybe "" $ do
d <- padNum 2 <$> gs^.gameDay d <- padNum 2 <$> gs^.gameDay
Just $ m ++ " " ++ d ++ " " ++ y Just $ m ++ " " ++ d ++ " " ++ y
playerReport :: Int -> String -> [(Player, PlayerStats)] -> [String] playerReport
playerReport width label ps = let :: Int
-> String
-> Bool
-> Bool
-> [(Player, PlayerStats)]
-> [String]
playerReport width label =
filteredPlayerReport width label (const True)
filteredPlayerReport
:: Int
-> String
-> ((Player, PlayerStats) -> Bool)
-> Bool
-> Bool
-> [(Player, PlayerStats)]
-> [String]
filteredPlayerReport width label criteria showTotals lineNumbers ps = let
tStats = foldl addPlayerStats newPlayerStats $ map snd ps tStats = foldl addPlayerStats newPlayerStats $ map snd ps
criteria' = (&&) <$> criteria <*> \(p, _) -> p^.pNumber /= 0
fps = filter criteria' ps
rHeader = rHeader =
[ centre width (label ++ " STATISTICS") [ centre width (label ++ " STATISTICS")
@@ -194,9 +221,9 @@ playerReport width label ps = let
body = map body = map
(\(p, stats) -> (\(p, stats) ->
[ CellText $ show (p^.pNumber) ++ " " [ CellText $ show (p^.pNumber) ++ " "
, CellText $ p^.pName , CellText $ playerName p
] ++ statsCells stats) ] ++ statsCells stats)
ps fps
separator = replicate 2 (CellText "") ++ replicate 4 (CellFill '-') separator = replicate 2 (CellText "") ++ replicate 4 (CellFill '-')
@@ -205,23 +232,41 @@ playerReport width label ps = let
, CellText "" , CellText ""
] ++ statsCells tStats ] ++ statsCells tStats
table = overlayLast (label ++ " TOTALS") olayText = if showTotals
$ map (centre width) then label ++ " TOTALS"
else ""
lnOverlay = if lineNumbers
then "" : [right 2 $ show x | x <- [(1 :: Int)..]]
else repeat ""
table = overlayLast olayText
$ map (\(ln, line) -> overlay ln $ centre width line)
$ zip lnOverlay
$ complexTable ([right, left] ++ repeat right) $ complexTable ([right, left] ++ repeat right)
$ tHeader : body ++ [separator, totals] $ tHeader : body ++ if showTotals
then [separator, totals]
else []
in rHeader ++ table in rHeader ++ table
goalieReport :: Int -> [(Goalie, GoalieStats)] -> [String] goalieReport
goalieReport width goalieData = let :: Int
olayText = "GOALTENDING TOTALS" -> Bool
-> Bool
-> [(Goalie, GoalieStats)]
-> [String]
goalieReport width showTotals lineNumbers goalieData = let
olayText = if showTotals
then "GOALTENDING TOTALS"
else ""
tData = foldl addGoalieStats newGoalieStats tData = foldl addGoalieStats newGoalieStats
$ map snd goalieData $ map snd goalieData
header = header =
[ CellText "NO." [ CellText "NO."
, CellText $ left (length olayText) "GOALTENDER" , CellText $ padRight (length olayText) "GOALTENDER"
, CellText "GP" , CellText "GP"
, CellText " MIN" , CellText " MIN"
, CellText " GA" , CellText " GA"
@@ -240,7 +285,7 @@ goalieReport width goalieData = let
body = map body = map
(\(goalie, stats) -> (\(goalie, stats) ->
[ CellText $ show (goalie^.gNumber) ++ " " [ CellText $ show (goalie^.gNumber) ++ " "
, CellText $ show $ goalie^.gName , CellText $ goalieName goalie
] ++ rowCells stats) ] ++ rowCells stats)
goalieData goalieData
@@ -250,7 +295,38 @@ goalieReport width goalieData = let
summary = replicate 2 (CellText "") ++ rowCells tData summary = replicate 2 (CellText "") ++ rowCells tData
in map (centre width) lnOverlay = if lineNumbers
then "" : [right 2 $ show x | x <- [(1 :: Int)..]]
else repeat ""
in map (\(ln, line) -> overlay ln $ centre width line)
$ zip lnOverlay
$ overlayLast olayText $ overlayLast olayText
$ complexTable ([right, left] ++ repeat right) $ complexTable ([right, left] ++ repeat right)
$ header : body ++ [separator, summary] $ header : body ++ if showTotals
then [separator, summary]
else []
gameGoalieReport :: Int -> [(Goalie, GoalieStats)] -> [String]
gameGoalieReport width goalieData = let
header =
[ CellText "NO."
, CellText "GOALTENDER"
, CellText " MIN"
, CellText " GA"
, CellText " AVE"
]
body = map
(\(goalie, stats) ->
[ CellText $ show (goalie^.gNumber) ++ " "
, CellText $ goalieName goalie
, CellText $ show $ stats^.gsMinsPlayed
, CellText $ show $ stats^.gsGoalsAllowed
, CellText $ showFloating $ gsAverage stats
])
goalieData
in map (centre width)
$ complexTable ([right, left] ++ repeat right)
$ header : body

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -35,6 +35,8 @@ module Mtlstats.Types (
EditPlayerMode (..), EditPlayerMode (..),
EditGoalieState (..), EditGoalieState (..),
EditGoalieMode (..), EditGoalieMode (..),
EditStandingsMode (..),
ESMSubMode (..),
Database (..), Database (..),
Player (..), Player (..),
PlayerStats (..), PlayerStats (..),
@@ -56,6 +58,9 @@ module Mtlstats.Types (
createGoalieStateL, createGoalieStateL,
editPlayerStateL, editPlayerStateL,
editGoalieStateL, editGoalieStateL,
editStandingsModeL,
-- ** EditStandingsMode Lenses
esmSubModeL,
-- ** GameState Lenses -- ** GameState Lenses
gameYear, gameYear,
gameMonth, gameMonth,
@@ -106,6 +111,8 @@ module Mtlstats.Types (
pNumber, pNumber,
pName, pName,
pPosition, pPosition,
pRookie,
pActive,
pYtd, pYtd,
pLifetime, pLifetime,
-- ** PlayerStats Lenses -- ** PlayerStats Lenses
@@ -115,6 +122,8 @@ module Mtlstats.Types (
-- ** Goalie Lenses -- ** Goalie Lenses
gNumber, gNumber,
gName, gName,
gRookie,
gActive,
gYtd, gYtd,
gLifetime, gLifetime,
-- ** GoalieStats Lenses -- ** GoalieStats Lenses
@@ -192,6 +201,7 @@ import Data.Aeson
, (.!=) , (.!=)
, (.=) , (.=)
) )
import Data.Char (toUpper)
import Data.List (isInfixOf) import Data.List (isInfixOf)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (listToMaybe) import Data.Maybe (listToMaybe)
@@ -226,22 +236,28 @@ data ProgState = ProgState
-- | The program mode -- | The program mode
data ProgMode data ProgMode
= MainMenu = TitleScreen
| NewSeason | MainMenu
| NewSeason Bool
| NewGame GameState | NewGame GameState
| EditMenu
| CreatePlayer CreatePlayerState | CreatePlayer CreatePlayerState
| CreateGoalie CreateGoalieState | CreateGoalie CreateGoalieState
| EditPlayer EditPlayerState | EditPlayer EditPlayerState
| EditGoalie EditGoalieState | EditGoalie EditGoalieState
| EditStandings EditStandingsMode
instance Show ProgMode where instance Show ProgMode where
show TitleScreen = "TitleScreen"
show MainMenu = "MainMenu" show MainMenu = "MainMenu"
show NewSeason = "NewSeason" show (NewSeason _) = "NewSeason"
show (NewGame _) = "NewGame" show (NewGame _) = "NewGame"
show EditMenu = "EditMenu"
show (CreatePlayer _) = "CreatePlayer" show (CreatePlayer _) = "CreatePlayer"
show (CreateGoalie _) = "CreateGoalie" show (CreateGoalie _) = "CreateGoalie"
show (EditPlayer _) = "EditPlayer" show (EditPlayer _) = "EditPlayer"
show (EditGoalie _) = "EditGoalie" show (EditGoalie _) = "EditGoalie"
show (EditStandings _) = "EditStandings"
-- | The game state -- | The game state
data GameState = GameState data GameState = GameState
@@ -344,11 +360,11 @@ data EditPlayerMode
| EPPosition | EPPosition
| EPYtd | EPYtd
| EPLifetime | EPLifetime
| EPYtdGoals | EPYtdGoals Bool
| EPYtdAssists | EPYtdAssists Bool
| EPYtdPMin | EPYtdPMin
| EPLtGoals | EPLtGoals Bool
| EPLtAssists | EPLtAssists Bool
| EPLtPMin | EPLtPMin
deriving (Eq, Show) deriving (Eq, Show)
@@ -366,20 +382,39 @@ data EditGoalieMode
| EGName | EGName
| EGYtd | EGYtd
| EGLifetime | EGLifetime
| EGYtdGames | EGYtdGames Bool
| EGYtdMins | EGYtdMins Bool
| EGYtdGoals | EGYtdGoals Bool
| EGYtdWins | EGYtdShutouts Bool
| EGYtdLosses | EGYtdWins Bool
| EGYtdLosses Bool
| EGYtdTies | EGYtdTies
| EGLtGames | EGLtGames Bool
| EGLtMins | EGLtMins Bool
| EGLtGoals | EGLtGoals Bool
| EGLtWins | EGLtShutouts Bool
| EGLtLosses | EGLtWins Bool
| EGLtLosses Bool
| EGLtTies | EGLtTies
deriving (Eq, Show) deriving (Eq, Show)
-- | Represents the standings edit mode
data EditStandingsMode
= ESMMenu
| ESMHome ESMSubMode
| ESMAway ESMSubMode
deriving (Eq, Show)
-- | Represents the standings edit sub-mode
data ESMSubMode
= ESMSubMenu
| ESMEditWins
| ESMEditLosses
| ESMEditOvertime
| ESMEditGoalsFor
| ESMEditGoalsAgainst
deriving (Eq, Show)
-- | Represents the database -- | Represents the database
data Database = Database data Database = Database
{ _dbPlayers :: [Player] { _dbPlayers :: [Player]
@@ -394,29 +429,6 @@ data Database = Database
-- ^ Statistics for away games -- ^ Statistics for away games
} deriving (Eq, Show) } deriving (Eq, Show)
instance FromJSON Database where
parseJSON = withObject "Database" $ \v -> Database
<$> v .: "players"
<*> v .: "goalies"
<*> v .: "games"
<*> v .: "home_game_stats"
<*> v .: "away_game_stats"
instance ToJSON Database where
toJSON (Database players goalies games hgs ags) = object
[ "players" .= players
, "goalies" .= goalies
, "games" .= games
, "home_game_stats" .= hgs
, "away_game_stats" .= ags
]
toEncoding (Database players goalies games hgs ags) = pairs $
"players" .= players <>
"goalies" .= goalies <>
"games" .= games <>
"home_game_stats" .= hgs <>
"away_game_stats" .= ags
-- | Represents a (non-goalie) player -- | Represents a (non-goalie) player
data Player = Player data Player = Player
{ _pNumber :: Int { _pNumber :: Int
@@ -425,35 +437,16 @@ data Player = Player
-- ^ The player's name -- ^ The player's name
, _pPosition :: String , _pPosition :: String
-- ^ The player's position -- ^ The player's position
, _pRookie :: Bool
-- ^ Indicates that the player is a rookie
, _pActive :: Bool
-- ^ Indicates that the player is active
, _pYtd :: PlayerStats , _pYtd :: PlayerStats
-- ^ The Player's year-to-date stats -- ^ The Player's year-to-date stats
, _pLifetime :: PlayerStats , _pLifetime :: PlayerStats
-- ^ The player's lifetime stats -- ^ The player's lifetime stats
} deriving (Eq, Show) } deriving (Eq, Show)
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
-- | Represents a (non-goalie) player's stats -- | Represents a (non-goalie) player's stats
data PlayerStats = PlayerStats data PlayerStats = PlayerStats
{ _psGoals :: Int { _psGoals :: Int
@@ -464,55 +457,22 @@ data PlayerStats = PlayerStats
-- ^ The number of penalty minutes -- ^ The number of penalty minutes
} deriving (Eq, Show) } deriving (Eq, Show)
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
-- | Represents a goalie -- | Represents a goalie
data Goalie = Goalie data Goalie = Goalie
{ _gNumber :: Int { _gNumber :: Int
-- ^ The goalie's number -- ^ The goalie's number
, _gName :: String , _gName :: String
-- ^ The goalie's name -- ^ The goalie's name
, _gRookie :: Bool
-- ^ Indicates that the goalie is a rookie
, _gActive :: Bool
-- ^ Indicates that the goalie is active
, _gYtd :: GoalieStats , _gYtd :: GoalieStats
-- ^ The goalie's year-to-date stats -- ^ The goalie's year-to-date stats
, _gLifetime :: GoalieStats , _gLifetime :: GoalieStats
-- ^ The goalie's lifetime stats -- ^ The goalie's lifetime stats
} deriving (Eq, Show) } 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 -- | Represents a goalie's stats
data GoalieStats = GoalieStats data GoalieStats = GoalieStats
{ _gsGames :: Int { _gsGames :: Int
@@ -531,6 +491,168 @@ data GoalieStats = GoalieStats
-- ^ The number of ties -- ^ The number of ties
} deriving (Eq, Show) } deriving (Eq, Show)
-- | Game statistics
data GameStats = GameStats
{ _gmsWins :: Int
-- ^ Games won
, _gmsLosses :: Int
-- ^ Games lost
, _gmsOvertime :: Int
-- ^ Games lost in overtime
, _gmsGoalsFor :: Int
-- ^ Goals for the team
, _gmsGoalsAgainst :: Int
-- ^ Goals against the team
} deriving (Eq, Show)
-- | Defines a user prompt
data Prompt = Prompt
{ promptDrawer :: ProgState -> C.Update ()
-- ^ Draws the prompt to the screen
, promptProcessChar :: Char -> String -> String
-- ^ Modifies the string based on the character entered
, promptAction :: String -> Action ()
-- ^ Action to perform when the value is entered
, promptSpecialKey :: C.Key -> Action ()
-- ^ Action to perform when a special key is pressed
}
-- | Parameters for a search prompt
data SelectParams a = SelectParams
{ spPrompt :: String
-- ^ The search prompt
, spSearchHeader :: String
-- ^ The header to display at the top of the search list
, spSearch :: String -> Database -> [(Int, a)]
-- ^ The search function
, spSearchExact :: String -> Database -> Maybe Int
-- ^ Search function looking for an exact match
, spElemDesc :: a -> String
-- ^ Provides a string description of an element
, spProcessChar :: Char -> String -> String
-- ^ Processes a character entered by the user
, spCallback :: Maybe Int -> Action ()
-- ^ The function when the selection is made
, spNotFound :: String -> Action ()
-- ^ The function to call when the selection doesn't exist
}
-- | Describes a table cell
data TableCell
= CellText String
-- ^ A cell with text
| CellFill Char
-- ^ A cell filled with the given character
deriving (Eq, Show)
makeLenses ''ProgState
makeLenses ''GameState
makeLenses ''CreatePlayerState
makeLenses ''CreateGoalieState
makeLenses ''EditPlayerState
makeLenses ''EditGoalieState
makeLenses ''Database
makeLenses ''Player
makeLenses ''PlayerStats
makeLenses ''Goalie
makeLenses ''GoalieStats
makeLenses ''GameStats
instance FromJSON Database where
parseJSON = withObject "Database" $ \v -> Database
<$> v .:? "players" .!= []
<*> v .:? "goalies" .!= []
<*> v .:? "games" .!= 0
<*> v .:? "home_game_stats" .!= newGameStats
<*> v .:? "away_game_stats" .!= newGameStats
instance ToJSON Database where
toJSON (Database players goalies games hgs ags) = object
[ "players" .= players
, "goalies" .= goalies
, "games" .= games
, "home_game_stats" .= hgs
, "away_game_stats" .= ags
]
toEncoding (Database players goalies games hgs ags) = pairs $
"players" .= players <>
"goalies" .= goalies <>
"games" .= games <>
"home_game_stats" .= hgs <>
"away_game_stats" .= ags
instance FromJSON Player where
parseJSON = withObject "Player" $ \v -> Player
<$> v .: "number"
<*> v .: "name"
<*> v .: "position"
<*> v .:? "rookie" .!= False
<*> v .:? "active" .!= True
<*> v .:? "ytd" .!= newPlayerStats
<*> v .:? "lifetime" .!= newPlayerStats
instance ToJSON Player where
toJSON (Player num name pos rk act ytd lt) = object
[ "number" .= num
, "name" .= name
, "position" .= pos
, "rookie" .= rk
, "active" .= act
, "ytd" .= ytd
, "lifetime" .= lt
]
toEncoding (Player num name pos rk act ytd lt) = pairs $
"number" .= num <>
"name" .= name <>
"position" .= pos <>
"rookie" .= rk <>
"active" .= act <>
"ytd" .= ytd <>
"lifetime" .= lt
instance FromJSON PlayerStats where
parseJSON = withObject "PlayerStats" $ \v -> PlayerStats
<$> v .:? "goals" .!= 0
<*> v .:? "assists" .!= 0
<*> v .:? "penalty_mins" .!= 0
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
instance FromJSON Goalie where
parseJSON = withObject "Goalie" $ \v -> Goalie
<$> v .: "number"
<*> v .: "name"
<*> v .:? "rookie" .!= False
<*> v .:? "active" .!= True
<*> v .:? "ytd" .!= newGoalieStats
<*> v .:? "lifetime" .!= newGoalieStats
instance ToJSON Goalie where
toJSON (Goalie num name rk act ytd lt) = object
[ "number" .= num
, "name" .= name
, "ytd" .= ytd
, "rookie" .= rk
, "active" .= act
, "lifetime" .= lt
]
toEncoding (Goalie num name rk act ytd lt) = pairs $
"number" .= num <>
"name" .= name <>
"rookie" .= rk <>
"active" .= act <>
"ytd" .= ytd <>
"lifetime" .= lt
instance FromJSON GoalieStats where instance FromJSON GoalieStats where
parseJSON = withObject "GoalieStats" $ \v -> GoalieStats parseJSON = withObject "GoalieStats" $ \v -> GoalieStats
<$> v .:? "games" .!= 0 <$> v .:? "games" .!= 0
@@ -560,20 +682,6 @@ instance ToJSON GoalieStats where
"losses" .= l <> "losses" .= l <>
"ties" .= t "ties" .= t
-- | Game statistics
data GameStats = GameStats
{ _gmsWins :: Int
-- ^ Games won
, _gmsLosses :: Int
-- ^ Games lost
, _gmsOvertime :: Int
-- ^ Games lost in overtime
, _gmsGoalsFor :: Int
-- ^ Goals for the team
, _gmsGoalsAgainst :: Int
-- ^ Goals against the team
} deriving (Eq, Show)
instance FromJSON GameStats where instance FromJSON GameStats where
parseJSON = withObject "GameStats" $ \v -> GameStats parseJSON = withObject "GameStats" $ \v -> GameStats
<$> v .: "wins" <$> v .: "wins"
@@ -597,57 +705,6 @@ instance ToJSON GameStats where
"goals_for" .= gf <> "goals_for" .= gf <>
"goals_against" .= ga "goals_against" .= ga
-- | Defines a user prompt
data Prompt = Prompt
{ promptDrawer :: ProgState -> C.Update ()
-- ^ Draws the prompt to the screen
, promptCharCheck :: Char -> Bool
-- ^ Determines whether or not the character is valid
, promptAction :: String -> Action ()
-- ^ Action to perform when the value is entered
, promptSpecialKey :: C.Key -> Action ()
-- ^ Action to perform when a special key is pressed
}
-- | Parameters for a search prompt
data SelectParams a = SelectParams
{ spPrompt :: String
-- ^ The search prompt
, spSearchHeader :: String
-- ^ The header to display at the top of the search list
, spSearch :: String -> Database -> [(Int, a)]
-- ^ The search function
, spSearchExact :: String -> Database -> Maybe Int
-- ^ Search function looking for an exact match
, spElemDesc :: a -> String
-- ^ Provides a string description of an element
, spCallback :: Maybe Int -> Action ()
-- ^ The function when the selection is made
, spNotFound :: String -> Action ()
-- ^ The function to call when the selection doesn't exist
}
-- | Describes a table cell
data TableCell
= CellText String
-- ^ A cell with text
| CellFill Char
-- ^ A cell filled with the given character
deriving (Eq, Show)
makeLenses ''ProgState
makeLenses ''GameState
makeLenses ''CreatePlayerState
makeLenses ''CreateGoalieState
makeLenses ''EditPlayerState
makeLenses ''EditGoalieState
makeLenses ''Database
makeLenses ''Player
makeLenses ''PlayerStats
makeLenses ''Goalie
makeLenses ''GoalieStats
makeLenses ''GameStats
gameStateL :: Lens' ProgMode GameState gameStateL :: Lens' ProgMode GameState
gameStateL = lens gameStateL = lens
(\case (\case
@@ -683,11 +740,29 @@ editGoalieStateL = lens
_ -> newEditGoalieState) _ -> newEditGoalieState)
(\_ egs -> EditGoalie egs) (\_ egs -> EditGoalie egs)
editStandingsModeL :: Lens' ProgMode EditStandingsMode
editStandingsModeL = lens
(\case
EditStandings esm -> esm
_ -> ESMMenu)
(\_ esm -> EditStandings esm)
esmSubModeL :: Lens' EditStandingsMode ESMSubMode
esmSubModeL = lens
(\case
ESMMenu -> ESMSubMenu
ESMHome m -> m
ESMAway m -> m)
(\mode subMode -> case mode of
ESMMenu -> ESMMenu
ESMHome _ -> ESMHome subMode
ESMAway _ -> ESMAway subMode)
-- | Constructor for a 'ProgState' -- | Constructor for a 'ProgState'
newProgState :: ProgState newProgState :: ProgState
newProgState = ProgState newProgState = ProgState
{ _database = newDatabase { _database = newDatabase
, _progMode = MainMenu , _progMode = TitleScreen
, _inputBuffer = "" , _inputBuffer = ""
, _scrollOffset = 0 , _scrollOffset = 0
} }
@@ -775,6 +850,8 @@ newPlayer num name pos = Player
{ _pNumber = num { _pNumber = num
, _pName = name , _pName = name
, _pPosition = pos , _pPosition = pos
, _pRookie = True
, _pActive = True
, _pYtd = newPlayerStats , _pYtd = newPlayerStats
, _pLifetime = newPlayerStats , _pLifetime = newPlayerStats
} }
@@ -797,6 +874,8 @@ newGoalie
newGoalie num name = Goalie newGoalie num name = Goalie
{ _gNumber = num { _gNumber = num
, _gName = name , _gName = name
, _gRookie = True
, _gActive = True
, _gYtd = newGoalieStats , _gYtd = newGoalieStats
, _gLifetime = newGoalieStats , _gLifetime = newGoalieStats
} }
@@ -904,7 +983,7 @@ playerSearch
-- ^ The matching players with their index numbers -- ^ The matching players with their index numbers
playerSearch sStr = playerSearch sStr =
filter match . zip [0..] filter match . zip [0..]
where match (_, p) = sStr `isInfixOf` (p^.pName) where match (_, p) = map toUpper sStr `isInfixOf` map toUpper (p^.pName)
-- | Searches for a player by exact match on name -- | Searches for a player by exact match on name
playerSearchExact playerSearchExact
@@ -967,8 +1046,9 @@ goalieSearch
-- ^ The list to search -- ^ The list to search
-> [(Int, Goalie)] -> [(Int, Goalie)]
-- ^ The search results with their corresponding index numbers -- ^ The search results with their corresponding index numbers
goalieSearch sStr = filter (\(_, goalie) -> sStr `isInfixOf` (goalie^.gName)) . goalieSearch sStr =
zip [0..] filter match . zip [0..]
where match (_, g) = map toUpper sStr `isInfixOf` map toUpper (g^.gName)
-- | Searches a list of goalies for an exact match -- | Searches a list of goalies for an exact match
goalieSearchExact goalieSearchExact
@@ -1008,4 +1088,10 @@ addGoalieStats g1 g2 = GoalieStats
-- | Determines a goalie's average goals allowed per game. -- | Determines a goalie's average goals allowed per game.
gsAverage :: GoalieStats -> Rational gsAverage :: GoalieStats -> Rational
gsAverage gs = fromIntegral (gs^.gsGoalsAllowed) / fromIntegral (gs^.gsGames) gsAverage gs = let
allowed = fromIntegral $ gs^.gsGoalsAllowed
mins = fromIntegral $ gs^.gsMinsPlayed
gLen = fromIntegral gameLength
in if mins == 0
then 0
else allowed / mins * gLen

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -39,6 +39,7 @@ module Mtlstats.Types.Menu (
import Lens.Micro ((^.)) import Lens.Micro ((^.))
import Lens.Micro.TH (makeLenses) import Lens.Micro.TH (makeLenses)
import Mtlstats.Format
import Mtlstats.Types import Mtlstats.Types
-- | Defines a menu -- | Defines a menu
@@ -65,8 +66,15 @@ makeLenses ''Menu
makeLenses ''MenuItem makeLenses ''MenuItem
instance Show (Menu a) where instance Show (Menu a) where
show m = m ^. menuTitle ++ "\n" ++ items show m = unlines
where items = unlines $ map show $ m ^. menuItems $ [ m^.menuTitle
, ""
]
++ body
where
body = map (left width) items
width = maximum $ map length items
items = map show $ m^.menuItems
instance Show (MenuItem a) where instance Show (MenuItem a) where
show i = [i ^. miKey] ++ ") " ++ i ^. miDescription show i = [i ^. miKey] ++ ": " ++ i ^. miDescription

View File

@@ -1,7 +1,7 @@
{- | {- |
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,8 +19,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-} -}
module Mtlstats.Util (nth, modifyNth, updateMap, slice) where module Mtlstats.Util
( nth
, modifyNth
, updateMap
, slice
, capitalizeName
) where
import Data.Char (isSpace, toUpper)
import qualified Data.Map as M import qualified Data.Map as M
-- | Attempt to select the element from a list at a given index -- | Attempt to select the element from a list at a given index
@@ -75,3 +82,25 @@ slice
-- ^ The list to take a subset of -- ^ The list to take a subset of
-> [a] -> [a]
slice offset len = take len . drop offset slice offset len = take len . drop offset
-- | Name capitalization function for a player
capitalizeName
:: Char
-- ^ The character being input
-> String
-- ^ The current string
-> String
-- ^ The resulting string
capitalizeName ch str = str ++ [ch']
where
ch' = if lockFlag str
then toUpper ch
else ch
lockFlag "" = True
lockFlag (c:cs)
| c == ',' = lockFlag' cs
| otherwise = lockFlag cs
lockFlag' "" = True
lockFlag' (c:cs)
| isSpace c = lockFlag' cs
| otherwise = False

View File

@@ -1,537 +0,0 @@
{-
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/>.
-}
module Actions.EditGoalieSpec (spec) where
import Data.Maybe (fromJust)
import Lens.Micro ((^.), (&), (.~))
import Test.Hspec (Spec, context, describe, it, shouldBe)
import Mtlstats.Actions.EditGoalie
import Mtlstats.Types
import Mtlstats.Util
spec :: Spec
spec = describe "EditGoalie" $ do
editGoalieNumberSpec
editGoalieNameSpec
editGoalieYtdGamesSpec
editGoalieYtdMinsSpec
editGoalieYtdGoalsSpec
editGoalieYtdWinsSpec
editGoalieYtdLossesSpec
editGoalieYtdTiesSpec
editGoalieLtGamesSpec
editGoalieLtMinsSpec
editGoalieLtGoalsSpec
editGoalieLtWinsSpec
editGoalieLtLossesSpec
editGoalieLtTiesSpec
editGoalieNumberSpec :: Spec
editGoalieNumberSpec = describe "editGoalieNumber" $ editTest
(editGoalieNumber 5)
EGNumber
(uncurry newGoalie)
[ ( "set Joe"
, Just 0
, (5, "Joe")
, (3, "Bob")
, EGMenu
)
, ( "set Bob"
, Just 1
, (2, "Joe")
, (5, "Bob")
, EGMenu
)
, ( "out of bounds"
, Just 2
, (2, "Joe")
, (3, "Bob")
, EGNumber
)
, ( "no goalie selected"
, Nothing
, (2, "Joe")
, (3, "Bob")
, EGNumber
)
]
editGoalieNameSpec :: Spec
editGoalieNameSpec = describe "editGoalieName" $ editTest
(editGoalieName "foo")
EGName
(uncurry newGoalie)
[ ( "set Joe"
, Just 0
, ( 2, "foo" )
, ( 3, "Bob" )
, EGMenu
)
, ( "set Bob"
, Just 1
, ( 2, "Joe" )
, ( 3, "foo" )
, EGMenu
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe" )
, ( 3, "Bob" )
, EGName
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe" )
, ( 3, "Bob" )
, EGName
)
]
editGoalieYtdGamesSpec :: Spec
editGoalieYtdGamesSpec = describe "editGoalieYtdGames" $ editTest
(editGoalieYtdGames 1)
EGYtdGames
(\(num, name, games) -> newGoalie num name & gYtd.gsGames .~ games)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdGames
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdGames
)
]
editGoalieYtdMinsSpec :: Spec
editGoalieYtdMinsSpec = describe "editGoalieYtdMins" $ editTest
(editGoalieYtdMins 1)
EGYtdMins
(\(num, name, mins) -> newGoalie num name & gYtd.gsMinsPlayed .~ mins)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, (2, "Joe", 0 )
, (3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdMins
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdMins
)
]
editGoalieYtdGoalsSpec :: Spec
editGoalieYtdGoalsSpec = describe "editGoalieYtdGoals" $ editTest
(editGoalieYtdGoals 1)
EGYtdGoals
(\(num, name, goals) -> newGoalie num name & gYtd.gsGoalsAllowed .~ goals)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdGoals
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdGoals
)
]
editGoalieYtdWinsSpec :: Spec
editGoalieYtdWinsSpec = describe "editGoalieYtdWins" $ editTest
(editGoalieYtdWins 1)
EGYtdWins
(\(num, name, wins) -> newGoalie num name & gYtd.gsWins .~ wins)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdWins
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdWins
)
]
editGoalieYtdLossesSpec :: Spec
editGoalieYtdLossesSpec = describe "editGoalieYtdLosses" $ editTest
(editGoalieYtdLosses 1)
EGYtdLosses
(\(num, name, losses) -> newGoalie num name & gYtd.gsLosses .~ losses)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdLosses
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdLosses
)
]
editGoalieYtdTiesSpec :: Spec
editGoalieYtdTiesSpec = describe "editGoalieYtdTies" $ editTest
(editGoalieYtdTies 1)
EGYtdTies
(\(num, name, ties) -> newGoalie num name & gYtd.gsTies .~ ties)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGYtd
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGYtd
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdTies
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGYtdTies
)
]
editGoalieLtGamesSpec :: Spec
editGoalieLtGamesSpec = describe "editGoalieLtGames" $ editTest
(editGoalieLtGames 1)
EGLtGames
(\(num, name, games) -> newGoalie num name & gLifetime.gsGames .~ games)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtGames
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtGames
)
]
editGoalieLtMinsSpec :: Spec
editGoalieLtMinsSpec = describe "editGoalieLtMins" $ editTest
(editGoalieLtMins 1)
EGLtMins
(\(num, name, mins) -> newGoalie num name & gLifetime.gsMinsPlayed .~ mins)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtMins
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtMins
)
]
editGoalieLtGoalsSpec :: Spec
editGoalieLtGoalsSpec = describe "editGoalieLtGoals" $ editTest
(editGoalieLtGoals 1)
EGLtGoals
(\(num, name, goals) -> newGoalie num name & gLifetime.gsGoalsAllowed .~ goals)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtGoals
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtGoals
)
]
editGoalieLtWinsSpec :: Spec
editGoalieLtWinsSpec = describe "editGoalieLtWins" $ editTest
(editGoalieLtWins 1)
EGLtWins
(\(num, name, wins) -> newGoalie num name & gLifetime.gsWins .~ wins)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtWins
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtWins
)
]
editGoalieLtLossesSpec :: Spec
editGoalieLtLossesSpec = describe "editGoalieLtLosses" $ editTest
(editGoalieLtLosses 1)
EGLtLosses
(\(num, name, losses) -> newGoalie num name & gLifetime.gsLosses .~ losses)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtLosses
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtLosses
)
]
editGoalieLtTiesSpec :: Spec
editGoalieLtTiesSpec = describe "editGoalieLtTies" $ editTest
(editGoalieLtTies 1)
EGLtTies
(\(num, name, ties) -> newGoalie num name & gLifetime.gsTies .~ ties)
[ ( "set Joe"
, Just 0
, ( 2, "Joe", 1 )
, ( 3, "Bob", 0 )
, EGLifetime
)
, ( "set Bob"
, Just 1
, ( 2, "Joe", 0 )
, ( 3, "Bob", 1 )
, EGLifetime
)
, ( "out of bounds"
, Just 2
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtTies
)
, ( "no goalie selected"
, Nothing
, ( 2, "Joe", 0 )
, ( 3, "Bob", 0 )
, EGLtTies
)
]
editTest
:: (ProgState -> ProgState)
-> EditGoalieMode
-> (a -> Goalie)
-> [(String, Maybe Int, a, a, EditGoalieMode)]
-> Spec
editTest func setMode mkGoalie params = do
mapM_
(\(setLabel, setGid, joeData, bobData, expectMode) -> context setLabel $ do
let
egs = newEditGoalieState
& egsSelectedGoalie .~ setGid
& egsMode .~ setMode
ps = func $ progState $ EditGoalie egs
mapM_
(\(chkLabel, chkGid, goalieData) -> context chkLabel $ let
actual = fromJust $ nth chkGid $ ps^.database.dbGoalies
expected = mkGoalie goalieData
in it ("should be " ++ show expected) $
actual `shouldBe` expected)
-- label, goalie ID, goalie data
[ ( "check Joe", 0, joeData )
, ( "check Bob", 1, bobData )
]
context "check mode" $
it ("should be " ++ show expectMode) $
ps^.progMode.editGoalieStateL.egsMode `shouldBe` expectMode)
params
context "wrong progMode" $ do
let ps = func $ progState MainMenu
it "should not change the database" $
ps^.database `shouldBe` db
it "should not change the progMode" $
show (ps^.progMode) `shouldBe` "MainMenu"
joe :: Goalie
joe = newGoalie 2 "Joe"
bob :: Goalie
bob = newGoalie 3 "Bob"
db :: Database
db = newDatabase & dbGoalies .~ [joe, bob]
progState :: ProgMode -> ProgState
progState mode = newProgState
& progMode .~ mode
& database .~ db

View File

@@ -0,0 +1,83 @@
{-
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 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/>.
-}
{-# LANGUAGE LambdaCase #-}
module Actions.EditStandingsSpec (spec) where
import Lens.Micro ((^.), (&), (.~))
import Test.Hspec
( Spec
, context
, describe
, it
, shouldBe
, shouldSatisfy
)
import Mtlstats.Actions.EditStandings
import Mtlstats.Types
spec :: Spec
spec = describe "EditStandings" $ do
mapM_
(\(label, f, expected) -> describe label $ do
let
ps = newProgState
ps' = f ps
it "should set progMode to EditStandings" $
ps'^.progMode `shouldSatisfy` \case
(EditStandings _) -> True
_ -> False
it ("should set editStandingsMode to " ++ show expected) $
ps'^.progMode.editStandingsModeL `shouldBe` expected)
-- label, function, expected mode
[ ( "editStandings", editStandings, ESMMenu )
, ( "editHomeStandings", editHomeStandings, ESMHome ESMSubMenu )
, ( "editAwayStandings", editAwayStandings, ESMAway ESMSubMenu )
]
mapM_
(\(label, f, expected) -> describe label $ do
mapM_
(\prefix -> context ("mode: " ++ show (prefix ESMSubMenu)) $ let
ps = newProgState & progMode.editStandingsModeL .~ prefix ESMSubMenu
ps' = f ps
in it ("should set the mode to " ++ show expected) $
ps'^.progMode.editStandingsModeL `shouldBe` prefix expected)
[ESMHome, ESMAway]
context "mode: ESMMenu" $ let
ps = newProgState & progMode.editStandingsModeL .~ ESMMenu
ps' = f ps
in it "should not change the mode" $
ps'^.progMode.editStandingsModeL `shouldBe` ESMMenu)
-- label, function, expected
[ ( "editWins", editWins, ESMEditWins )
, ( "editLosses", editLosses, ESMEditLosses )
, ( "editOvertime", editOvertime, ESMEditOvertime )
, ( "editGoalsFor", editGoalsFor, ESMEditGoalsFor )
, ( "editGoalsAgainst", editGoalsAgainst, ESMEditGoalsAgainst )
]

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -24,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module ActionsSpec (spec) where module ActionsSpec (spec) where
import Control.Monad (replicateM) import Control.Monad (replicateM)
import Lens.Micro ((^.), (&), (.~), (?~)) import Lens.Micro ((^.), (&), (.~), (?~), (%~))
import Test.Hspec import Test.Hspec
( Spec ( Spec
, context , context
@@ -38,8 +38,8 @@ import Test.Hspec
import Mtlstats.Actions import Mtlstats.Actions
import Mtlstats.Types import Mtlstats.Types
import qualified Actions.EditGoalieSpec as EditGoalie
import qualified Actions.NewGameSpec as NewGame import qualified Actions.NewGameSpec as NewGame
import qualified Actions.EditStandingsSpec as EditStandings
import qualified TypesSpec as TS import qualified TypesSpec as TS
spec :: Spec spec :: Spec
@@ -47,13 +47,17 @@ spec = describe "Mtlstats.Actions" $ do
startNewSeasonSpec startNewSeasonSpec
startNewGameSpec startNewGameSpec
resetYtdSpec resetYtdSpec
clearRookiesSpec
resetStandingsSpec resetStandingsSpec
addCharSpec addCharSpec
removeCharSpec removeCharSpec
createPlayerSpec createPlayerSpec
createGoalieSpec createGoalieSpec
editSpec
editPlayerSpec editPlayerSpec
editSelectedPlayerSpec
editGoalieSpec editGoalieSpec
editSelectedGoalieSpec
addPlayerSpec addPlayerSpec
addGoalieSpec addGoalieSpec
resetCreatePlayerStateSpec resetCreatePlayerStateSpec
@@ -62,7 +66,7 @@ spec = describe "Mtlstats.Actions" $ do
scrollUpSpec scrollUpSpec
scrollDownSpec scrollDownSpec
NewGame.spec NewGame.spec
EditGoalie.spec EditStandings.spec
startNewSeasonSpec :: Spec startNewSeasonSpec :: Spec
startNewSeasonSpec = describe "startNewSeason" $ do startNewSeasonSpec = describe "startNewSeason" $ do
@@ -128,6 +132,45 @@ resetYtdSpec = describe "resetYtd" $
lt ^. gsTies `shouldNotBe` 0) $ lt ^. gsTies `shouldNotBe` 0) $
s ^. database . dbGoalies s ^. database . dbGoalies
clearRookiesSpec :: Spec
clearRookiesSpec = describe "clearRookies" $ do
let
players =
[ newPlayer 1 "Joe" "centre" & pRookie .~ True
, newPlayer 2 "Bob" "centre" & pRookie .~ False
]
goalies =
[ newGoalie 3 "Bill" & gRookie .~ True
, newGoalie 4 "Doug" & gRookie .~ False
]
ps = newProgState
& database
%~ (dbPlayers .~ players)
. (dbGoalies .~ goalies)
ps' = clearRookies ps
context "Players" $ mapM_
(\p -> let
name = p^.pName
rFlag = p^.pRookie
in context name $
it "should not be a rookie" $
rFlag `shouldBe` False)
(ps'^.database.dbPlayers)
context "Goalies" $ mapM_
(\g -> let
name = g^.gName
rFlag = g^.gRookie
in context name $
it "should not be a rookie" $
rFlag `shouldBe` False)
(ps'^.database.dbGoalies)
resetStandingsSpec :: Spec resetStandingsSpec :: Spec
resetStandingsSpec = describe "resetStandings" $ do resetStandingsSpec = describe "resetStandings" $ do
let let
@@ -198,18 +241,76 @@ createGoalieSpec = describe "createGoalie" $
s = createGoalie newProgState s = createGoalie newProgState
in show (s^.progMode) `shouldBe` "CreateGoalie" in show (s^.progMode) `shouldBe` "CreateGoalie"
editSpec :: Spec
editSpec = describe "edit" $
it "should change the mode to EditMenu" $ let
ps = edit newProgState
in show (ps^.progMode) `shouldBe` "EditMenu"
editPlayerSpec :: Spec editPlayerSpec :: Spec
editPlayerSpec = describe "editPlayer" $ editPlayerSpec = describe "editPlayer" $
it "should change the mode appropriately" $ let it "should change the mode appropriately" $ let
s = editPlayer newProgState s = editPlayer newProgState
in show (s^.progMode) `shouldBe` "EditPlayer" in show (s^.progMode) `shouldBe` "EditPlayer"
editSelectedPlayerSpec :: Spec
editSelectedPlayerSpec = describe "editSelectedPlayer" $ mapM_
(\(label, pState, expected) -> context label $
it "should edit the players appropriately" $ let
pState' = editSelectedPlayer (pName .~ "foo") pState
players' = pState'^.database.dbPlayers
in players' `shouldBe` expected)
-- label, initial state, expected
[ ( "wrong mode", baseState, players )
, ( "not selected", changePlayer Nothing, players )
, ( "player 0", changePlayer $ Just 0, changed0 )
, ( "player 1", changePlayer $ Just 1, changed1 )
, ( "out of bounds", changePlayer $ Just 2, players )
]
where
baseState = newProgState & database.dbPlayers .~ players
changePlayer n = baseState
& (progMode.editPlayerStateL.epsSelectedPlayer .~ n)
players = [ player 0, player 1 ]
changed0 = [ player' 0, player 1 ]
changed1 = [ player 0, player' 1 ]
player n = newPlayer n ("Player " ++ show n) "pos"
player' n = newPlayer n "foo" "pos"
editGoalieSpec :: Spec editGoalieSpec :: Spec
editGoalieSpec = describe "editGoalie" $ editGoalieSpec = describe "editGoalie" $
it "should change the mode appropriately" $ let it "should change the mode appropriately" $ let
s = editGoalie newProgState s = editGoalie newProgState
in show (s^.progMode) `shouldBe` "EditGoalie" in show (s^.progMode) `shouldBe` "EditGoalie"
editSelectedGoalieSpec :: Spec
editSelectedGoalieSpec = describe "editSelectedGoalie" $ mapM_
(\(label, pState, expected) -> context label $
it "should edit the goalies appropriately" $ let
pState' = editSelectedGoalie (gName .~ "foo") pState
goalies' = pState'^.database.dbGoalies
in goalies' `shouldBe` expected)
-- label, initial state, expected
[ ( "wrong mode", baseState, goalies )
, ( "not selected", changeGoalie Nothing, goalies )
, ( "goalie 0", changeGoalie $ Just 0, changed0 )
, ( "goalie 1", changeGoalie $ Just 1, changed1 )
, ( "out of bounds", changeGoalie $ Just 2, goalies )
]
where
baseState = newProgState & database.dbGoalies .~ goalies
changeGoalie n = baseState
& (progMode.editGoalieStateL.egsSelectedGoalie .~ n)
goalies = [ goalie 0, goalie 1 ]
changed0 = [ goalie' 0, goalie 1 ]
changed1 = [ goalie 0, goalie' 1 ]
goalie n = newGoalie n ("Player " ++ show n)
goalie' n = newGoalie n "foo"
addPlayerSpec :: Spec addPlayerSpec :: Spec
addPlayerSpec = describe "addPlayer" $ do addPlayerSpec = describe "addPlayer" $ do
let let

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -33,6 +33,7 @@ spec = describe "Mtlstats.Format" $ do
leftSpec leftSpec
rightSpec rightSpec
centreSpec centreSpec
padRightSpec
overlaySpec overlaySpec
monthSpec monthSpec
labelTableSpec labelTableSpec
@@ -98,6 +99,16 @@ centreSpec = describe "centre" $ do
it "should truncate the text" $ it "should truncate the text" $
centre 2 "foo" `shouldBe` "fo" centre 2 "foo" `shouldBe` "fo"
padRightSpec :: Spec
padRightSpec = describe "padRight" $ mapM_
(\(label, width, str, expected) -> context label $
it ("should be " ++ show expected) $
padRight width str `shouldBe` expected)
-- label, width, input string, expected
[ ( "text shorter", 5, "foo", "foo " )
, ( "text longer", 3, "foobar", "foobar" )
]
overlaySpec :: Spec overlaySpec :: Spec
overlaySpec = describe "overlay" $ do overlaySpec = describe "overlay" $ do

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -22,45 +22,70 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module Helpers.GoalieSpec (spec) where module Helpers.GoalieSpec (spec) where
import Lens.Micro ((&), (.~), (%~)) import Lens.Micro ((&), (.~), (%~))
import Test.Hspec (Spec, describe, it, shouldBe) import Test.Hspec (Spec, context, describe, it, shouldBe)
import Mtlstats.Helpers.Goalie import Mtlstats.Helpers.Goalie
import Mtlstats.Types import Mtlstats.Types
spec :: Spec spec :: Spec
spec = describe "Goalie" spec = describe "Goalie" $ do
goalieDetailsSpec goalieDetailsSpec
goalieNameSpec
goalieDetailsSpec :: Spec goalieDetailsSpec :: Spec
goalieDetailsSpec = describe "goalieDetails" $ let goalieDetailsSpec = describe "goalieDetails" $ let
input = newGoalie 1 "Joe" input = newGoalie 1 "Joe"
& gRookie .~ True
& gYtd & gYtd
%~ ( gsGames .~ 2 ) %~ ( gsGames .~ 2 )
. ( gsMinsPlayed .~ 3 ) . ( gsMinsPlayed .~ 3 )
. ( gsGoalsAllowed .~ 4 ) . ( gsGoalsAllowed .~ 4 )
. ( gsWins .~ 5 ) . ( gsShutouts .~ 5 )
. ( gsLosses .~ 6 ) . ( gsWins .~ 6 )
. ( gsTies .~ 7 ) . ( gsLosses .~ 7 )
. ( gsTies .~ 8 )
& gLifetime & gLifetime
%~ ( gsGames .~ 8 ) %~ ( gsGames .~ 9 )
. ( gsMinsPlayed .~ 9 ) . ( gsMinsPlayed .~ 10 )
. ( gsGoalsAllowed .~ 10 ) . ( gsGoalsAllowed .~ 11 )
. ( gsWins .~ 11 ) . ( gsShutouts .~ 12 )
. ( gsLosses .~ 12 ) . ( gsWins .~ 13 )
. ( gsTies .~ 13 ) . ( gsLosses .~ 14 )
. ( gsTies .~ 15 )
expected = unlines expected = unlines
[ "Number: 1" [ "Number: 1"
, " Name: Joe" , " Name: Joe*"
, "" , ""
, " YTD Lifetime" , " YTD Lifetime"
, " Games played 2 8" , " Games played 2 9"
, " Mins played 3 9" , " Mins played 3 10"
, "Goals allowed 4 10" , "Goals allowed 4 11"
, " Wins 5 11" , " Shutouts 5 12"
, " Losses 6 12" , " Wins 6 13"
, " Ties 7 13" , " Losses 7 14"
, " Ties 8 15"
] ]
in it "should format the output correctly" $ in it "should format the output correctly" $
goalieDetails input `shouldBe` expected goalieDetails input `shouldBe` expected
goalieNameSpec :: Spec
goalieNameSpec = describe "goalieName" $ mapM_
(\(label, g, expected) -> context label $
it ("should be " ++ expected) $
goalieName g `shouldBe` expected)
-- label, goalie, expected
[ ( "rookie", rookie, "foo*" )
, ( "non-rookie", active, "foo" )
, ( "retired", retired, "*foo" )
]
where
rookie = goalie True True
active = goalie False True
retired = goalie False False
goalie r a = newGoalie 1 "foo"
& gRookie .~ r
& gActive .~ a

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -22,20 +22,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module Helpers.PlayerSpec (spec) where module Helpers.PlayerSpec (spec) where
import Lens.Micro ((&), (.~)) import Lens.Micro ((&), (.~))
import Test.Hspec (Spec, describe, it, shouldBe) import Test.Hspec (Spec, context, describe, it, shouldBe)
import Mtlstats.Helpers.Player import Mtlstats.Helpers.Player
import Mtlstats.Types import Mtlstats.Types
spec :: Spec spec :: Spec
spec = describe "Player" spec = describe "Player" $ do
playerDetailsSpec playerDetailsSpec
playerNameSpec
playerDetailsSpec :: Spec playerDetailsSpec :: Spec
playerDetailsSpec = describe "playerDetails" $ playerDetailsSpec = describe "playerDetails" $
it "should give a detailed description" $ let it "should give a detailed description" $ let
p = newPlayer 1 "Joe" "centre" p = newPlayer 1 "Joe" "centre"
& pRookie .~ True
& pYtd .~ PlayerStats & pYtd .~ PlayerStats
{ _psGoals = 2 { _psGoals = 2
, _psAssists = 3 , _psAssists = 3
@@ -49,7 +51,7 @@ playerDetailsSpec = describe "playerDetails" $
expected = unlines expected = unlines
[ " Number: 1" [ " Number: 1"
, " Name: Joe" , " Name: Joe*"
, "Position: centre" , "Position: centre"
, "" , ""
, " YTD Lifetime" , " YTD Lifetime"
@@ -59,3 +61,23 @@ playerDetailsSpec = describe "playerDetails" $
] ]
in playerDetails p `shouldBe` expected in playerDetails p `shouldBe` expected
playerNameSpec :: Spec
playerNameSpec = describe "playerName" $ mapM_
(\(label, p, expected) -> context label $
it ("should be " ++ expected) $
playerName p `shouldBe` expected)
-- label, player, expected
[ ( "rookie", rookie, "foo*" )
, ( "non-rookie", nonRookie, "foo" )
, ( "retired", retired, "*foo" )
]
where
rookie = player True True
nonRookie = player False True
retired = player False False
player r a = newPlayer 1 "foo" "centre"
& pRookie .~ r
& pActive .~ a

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -37,11 +37,11 @@ showSpec :: Spec
showSpec = describe "show" $ showSpec = describe "show" $
it "should display correctly" $ let it "should display correctly" $ let
menu = Menu "Foo" () menu = Menu "Foo" ()
[ MenuItem '1' "Item 1" $ return () [ MenuItem '1' "foo" $ return ()
, MenuItem '2' "Item 2" $ return () , MenuItem '2' "bar baz" $ return ()
] ]
expected = expected =
"Foo\n\ "Foo\n\n\
\1) Item 1\n\ \1: foo \n\
\2) Item 2\n" \2: bar baz\n"
in show menu `shouldBe` expected in show menu `shouldBe` expected

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -36,7 +36,7 @@ import Data.Aeson.Types (Value (Object))
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.Ratio ((%)) import Data.Ratio ((%))
import Lens.Micro (Lens', (&), (^.), (.~), (?~)) import Lens.Micro (Lens', (&), (^.), (.~), (?~))
import System.Random (randomRIO) import System.Random (randomIO, randomRIO)
import Test.Hspec (Spec, context, describe, it, shouldBe) import Test.Hspec (Spec, context, describe, it, shouldBe)
import Mtlstats.Config import Mtlstats.Config
@@ -58,6 +58,8 @@ spec = describe "Mtlstats.Types" $ do
createGoalieStateLSpec createGoalieStateLSpec
editPlayerStateLSpec editPlayerStateLSpec
editGoalieStateLSpec editGoalieStateLSpec
editStandingsModeLSpec
esmSubModeLSpec
teamScoreSpec teamScoreSpec
otherScoreSpec otherScoreSpec
homeTeamSpec homeTeamSpec
@@ -191,6 +193,47 @@ editGoalieStateLSpec = describe "editGoalieStateL" $
egs2 = newEditGoalieState egs2 = newEditGoalieState
& egsSelectedGoalie ?~ 2 & egsSelectedGoalie ?~ 2
editStandingsModeLSpec :: Spec
editStandingsModeLSpec = describe "editStandingsModeL" $
lensSpec editStandingsModeL
-- getters
[ ( "missing mode", MainMenu, menu )
, ( "with mode", EditStandings home, home )
]
-- setters
[ ( "set mode", MainMenu, home )
, ( "change mode", EditStandings home, away )
]
where
menu = ESMMenu
home = ESMHome ESMSubMenu
away = ESMAway ESMSubMenu
esmSubModeLSpec :: Spec
esmSubModeLSpec = describe "esmSubModeL" $ do
context "getters" $ mapM_
(\(label, mode, expected) -> context label $
it ("should be " ++ show expected) $
mode^.esmSubModeL `shouldBe` expected)
-- label, mode, expected
[ ( "no state", ESMMenu, ESMSubMenu )
, ( "with state", ESMHome ESMEditWins, ESMEditWins )
]
context "setters" $ mapM_
(\(label, mode, expected) -> context label $
it ("should be " ++ show expected) $ let
mode' = mode & esmSubModeL .~ ESMEditWins
in mode' `shouldBe` expected)
-- label, mode, expected
[ ( "no state", ESMMenu, ESMMenu )
, ( "home mode", ESMHome ESMSubMenu, ESMHome ESMEditWins )
, ( "away mode", ESMAway ESMSubMenu, ESMAway ESMEditWins )
]
teamScoreSpec :: Spec teamScoreSpec :: Spec
teamScoreSpec = describe "teamScore" $ do teamScoreSpec = describe "teamScore" $ do
let let
@@ -271,6 +314,7 @@ lensSpec lens getters setters = do
player :: Player player :: Player
player = newPlayer 1 "Joe" "centre" player = newPlayer 1 "Joe" "centre"
& pRookie .~ False
& pYtd .~ playerStats 1 & pYtd .~ playerStats 1
& pLifetime .~ playerStats 2 & pLifetime .~ playerStats 2
@@ -279,6 +323,8 @@ playerJSON = Object $ HM.fromList
[ ( "number", toJSON (1 :: Int) ) [ ( "number", toJSON (1 :: Int) )
, ( "name", toJSON ("Joe" :: String) ) , ( "name", toJSON ("Joe" :: String) )
, ( "position", toJSON ("centre" :: String) ) , ( "position", toJSON ("centre" :: String) )
, ( "rookie", toJSON False )
, ( "active", toJSON True )
, ( "ytd", playerStatsJSON 1 ) , ( "ytd", playerStatsJSON 1 )
, ( "lifetime", playerStatsJSON 2 ) , ( "lifetime", playerStatsJSON 2 )
] ]
@@ -298,6 +344,7 @@ playerStatsJSON n = Object $ HM.fromList
goalie :: Goalie goalie :: Goalie
goalie = newGoalie 1 "Joe" goalie = newGoalie 1 "Joe"
& gRookie .~ False
& gYtd .~ goalieStats 1 & gYtd .~ goalieStats 1
& gLifetime .~ goalieStats 2 & gLifetime .~ goalieStats 2
@@ -305,6 +352,8 @@ goalieJSON :: Value
goalieJSON = Object $ HM.fromList goalieJSON = Object $ HM.fromList
[ ( "number", toJSON (1 :: Int) ) [ ( "number", toJSON (1 :: Int) )
, ( "name", toJSON ("Joe" :: String ) ) , ( "name", toJSON ("Joe" :: String ) )
, ( "rookie", toJSON False )
, ( "active", toJSON True )
, ( "ytd", goalieStatsJSON 1 ) , ( "ytd", goalieStatsJSON 1 )
, ( "lifetime", goalieStatsJSON 2 ) , ( "lifetime", goalieStatsJSON 2 )
] ]
@@ -591,7 +640,7 @@ playerSearchSpec = describe "playerSearch" $ mapM_
ps = [joe, bob, steve] ps = [joe, bob, steve]
in playerSearch sStr ps `shouldBe` expected) in playerSearch sStr ps `shouldBe` expected)
-- search, result -- search, result
[ ( "Joe", [(0, joe)] ) [ ( "joe", [(0, joe)] )
, ( "o", [(0, joe), (1, bob)] ) , ( "o", [(0, joe), (1, bob)] )
, ( "e", [(0, joe), (2, steve)] ) , ( "e", [(0, joe), (2, steve)] )
, ( "x", [] ) , ( "x", [] )
@@ -725,8 +774,8 @@ goalieSearchSpec = describe "goalieSearch" $ do
goalieSearch "x" goalies `shouldBe` [] goalieSearch "x" goalies `shouldBe` []
context "exact match" $ context "exact match" $
it "should return Steve" $ it "should return Bob" $
goalieSearch "Bob" goalies `shouldBe` [result 1] goalieSearch "bob" goalies `shouldBe` [result 1]
goalieSearchExactSpec :: Spec goalieSearchExactSpec :: Spec
goalieSearchExactSpec = describe "goalieSearchExact" $ do goalieSearchExactSpec = describe "goalieSearchExact" $ do
@@ -813,16 +862,21 @@ addGoalieStatsSpec = describe "addGoalieStats" $ let
actual `shouldBe` expected actual `shouldBe` expected
gsAverageSpec :: Spec gsAverageSpec :: Spec
gsAverageSpec = describe "gsAverage" $ let gsAverageSpec = describe "gsAverage" $ mapM_
(\(label, stats, expected) -> context label $
it ("should be " ++ show expected) $
gsAverage stats `shouldBe` expected)
-- label, stats, expected
[ ( "with minutes", gs, 3 % 2 )
, ( "no minutes", newGoalieStats , 0 )
]
where
gs = newGoalieStats gs = newGoalieStats
& gsGames .~ 2 & gsMinsPlayed .~ 2 * gameLength
& gsGoalsAllowed .~ 3 & gsGoalsAllowed .~ 3
expected = 3 % 2
in it ("should be " ++ show expected) $
gsAverage gs `shouldBe` expected
joe :: Player joe :: Player
joe = newPlayer 2 "Joe" "center" joe = newPlayer 2 "Joe" "center"
@@ -838,6 +892,8 @@ makePlayer = Player
<$> makeNum <$> makeNum
<*> makeName <*> makeName
<*> makeName <*> makeName
<*> makeBool
<*> makeBool
<*> makePlayerStats <*> makePlayerStats
<*> makePlayerStats <*> makePlayerStats
@@ -846,6 +902,8 @@ makeGoalie :: IO Goalie
makeGoalie = Goalie makeGoalie = Goalie
<$> makeNum <$> makeNum
<*> makeName <*> makeName
<*> makeBool
<*> makeBool
<*> makeGoalieStats <*> makeGoalieStats
<*> makeGoalieStats <*> makeGoalieStats
@@ -870,6 +928,9 @@ makeGoalieStats = GoalieStats
makeNum :: IO Int makeNum :: IO Int
makeNum = randomRIO (1, 10) makeNum = randomRIO (1, 10)
makeBool :: IO Bool
makeBool = randomIO
makeName :: IO String makeName :: IO String
makeName = replicateM 10 $ randomRIO ('A', 'Z') makeName = replicateM 10 $ randomRIO ('A', 'Z')
@@ -939,3 +1000,8 @@ instance Comparable CreateGoalieState where
describe "cgsName" $ describe "cgsName" $
it ("should be " ++ expected^.cgsName) $ it ("should be " ++ expected^.cgsName) $
actual^.cgsName `shouldBe` expected^.cgsName actual^.cgsName `shouldBe` expected^.cgsName
instance Comparable EditStandingsMode where
compareTest actual expected =
it ("should be " ++ show expected) $
actual `shouldBe` expected

View File

@@ -1,7 +1,7 @@
{- {-
mtlstats mtlstats
Copyright (C) 2019 Rhéal Lamothe Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com> <rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -32,6 +32,7 @@ spec = describe "Mtlstats.Util" $ do
modifyNthSpec modifyNthSpec
updateMapSpec updateMapSpec
sliceSpec sliceSpec
capitalizeNameSpec
nthSpec :: Spec nthSpec :: Spec
nthSpec = describe "nth" $ mapM_ nthSpec = describe "nth" $ mapM_
@@ -93,3 +94,23 @@ sliceSpec = describe "slice" $ do
context "negative offset" $ context "negative offset" $
it "should return the correct number of elements from the beginning" $ it "should return the correct number of elements from the beginning" $
slice (-10) 2 list `shouldBe` [2, 4] slice (-10) 2 list `shouldBe` [2, 4]
capitalizeNameSpec :: Spec
capitalizeNameSpec = describe "capitalizeName" $ mapM_
(\(label, ch, str, expected) -> context label $
it ("should be " ++ expected) $
capitalizeName ch str `shouldBe` expected)
-- label, character, string, expected
[ ( "initial lower", 'a', "", "A" )
, ( "initial upper", 'A', "", "A" )
, ( "initial non-alpha", '0', "", "0" )
, ( "pre-comma lower", 'a', "A", "AA" )
, ( "pre-comma upper", 'A', "A", "AA" )
, ( "pre-comma non-alpha", '0', "A", "A0" )
, ( "post-comma first lower", 'a', "FOO, ", "FOO, A" )
, ( "post-comma first upper", 'A', "FOO, ", "FOO, A" )
, ( "post-comma first non-alpha", '0', "FOO, ", "FOO, 0" )
, ( "unrestricted upper", 'A', "FOO, A", "FOO, AA" )
, ( "unrestricted lower", 'a', "FOO, A", "FOO, Aa" )
, ( "unrestricted non-alpha", '0', "FOO, A", "FOO, A0" )
]