werewolf 0.5.1.0 → 0.5.2.0
raw patch · 43 files changed
+1449/−835 lines, 43 files
Files
- CHANGELOG.md +12/−0
- README.md +2/−1
- app/Werewolf/Command/Choose.hs +5/−2
- app/Werewolf/Command/Help.hs +14/−6
- src/Game/Werewolf/Command/DevotedServant.hs +4/−3
- src/Game/Werewolf/Command/Hunter.hs +41/−0
- src/Game/Werewolf/Command/Orphan.hs +35/−0
- src/Game/Werewolf/Command/Status.hs +30/−54
- src/Game/Werewolf/Command/WildChild.hs +0/−35
- src/Game/Werewolf/Command/Witch.hs +1/−2
- src/Game/Werewolf/Command/WolfHound.hs +4/−1
- src/Game/Werewolf/Engine.hs +17/−18
- src/Game/Werewolf/Game.hs +30/−20
- src/Game/Werewolf/Messages.hs +60/−31
- src/Game/Werewolf/Player.hs +36/−20
- src/Game/Werewolf/Role.hs +56/−36
- src/Game/Werewolf/Util.hs +26/−20
- test/src/Game/Werewolf/Test/Arbitrary.hs +69/−28
- test/src/Game/Werewolf/Test/Command.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Choose.hs +162/−81
- test/src/Game/Werewolf/Test/Command/Heal.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Pass.hs +8/−10
- test/src/Game/Werewolf/Test/Command/Poison.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Protect.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Quit.hs +6/−8
- test/src/Game/Werewolf/Test/Command/Reveal.hs +6/−8
- test/src/Game/Werewolf/Test/Command/See.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Vote.hs +0/−2
- test/src/Game/Werewolf/Test/Engine.hs +37/−419
- test/src/Game/Werewolf/Test/Engine/Angel.hs +39/−0
- test/src/Game/Werewolf/Test/Engine/DevotedServant.hs +57/−0
- test/src/Game/Werewolf/Test/Engine/Hunter.hs +21/−0
- test/src/Game/Werewolf/Test/Engine/Lynching.hs +88/−0
- test/src/Game/Werewolf/Test/Engine/Orphan.hs +72/−0
- test/src/Game/Werewolf/Test/Engine/Protector.hs +52/−0
- test/src/Game/Werewolf/Test/Engine/Scapegoat.hs +51/−0
- test/src/Game/Werewolf/Test/Engine/Seer.hs +59/−0
- test/src/Game/Werewolf/Test/Engine/Village.hs +55/−0
- test/src/Game/Werewolf/Test/Engine/Werewolf.hs +89/−0
- test/src/Game/Werewolf/Test/Engine/Witch.hs +103/−0
- test/src/Game/Werewolf/Test/Engine/WolfHound.hs +56/−0
- test/src/Game/Werewolf/Test/Game.hs +31/−18
- werewolf.cabal +15/−2
CHANGELOG.md view
@@ -2,6 +2,18 @@ ### Upcoming +### v0.5.2.0++*Minor*++* Renamed the Wild-child to Orphan. ([#128](https://github.com/hjwylde/werewolf/issues/128))+* Added the Hunter role. ([#3](https://github.com/hjwylde/werewolf/issues/3))++*Revisions*++* Updated the Orphan's description. ([#128](https://github.com/hjwylde/werewolf/issues/128))+* Added role taken message for the Devoted Servant. ([#157](https://github.com/hjwylde/werewolf/issues/157))+ ### v0.5.1.0 *Minor*
README.md view
@@ -45,7 +45,7 @@ The Ambiguous are able to change allegiance throughout the game. * Devoted Servant-* Wild-child+* Orphan * Wolf-hound **The Loners:**@@ -66,6 +66,7 @@ The Villagers must lynch all of the Werewolves. * Druid+* Hunter * Jester * Protector * Scapegoat
app/Werewolf/Command/Choose.hs view
@@ -28,8 +28,9 @@ import Data.Text (Text) import Game.Werewolf+import Game.Werewolf.Command.Hunter as Hunter+import Game.Werewolf.Command.Orphan as Orphan import Game.Werewolf.Command.Scapegoat as Scapegoat-import Game.Werewolf.Command.WildChild as WildChild import Game.Werewolf.Command.WolfHound as WolfHound import Werewolf.Game@@ -48,8 +49,10 @@ game <- readGame tag command <- case game ^. stage of+ HuntersTurn1 -> return $ Hunter.chooseCommand callerName (head args)+ HuntersTurn2 -> return $ Hunter.chooseCommand callerName (head args)+ OrphansTurn -> return $ Orphan.chooseCommand callerName (head args) ScapegoatsTurn -> return $ Scapegoat.chooseCommand callerName args- WildChildsTurn -> return $ WildChild.chooseCommand callerName (head args) WolfHoundsTurn -> return $ WolfHound.chooseCommand callerName (head args) _ -> exitWith failure { messages = [playerCannotDoThatRightNowMessage callerName]
app/Werewolf/Command/Help.hs view
@@ -92,6 +92,14 @@ , "- `reveal`" , "- `pass`" ]+ , whenPlayerHasRole callerName mGame hunterRole+ [ "Hunter commands:"+ , "- `choose PLAYER`"+ ]+ , whenPlayerHasRole callerName mGame orphanRole+ [ "Orphan commands:"+ , "- `choose PLAYER`"+ ] , whenPlayerHasRole callerName mGame protectorRole [ "Protector commands:" , "- `protect PLAYER`"@@ -104,10 +112,6 @@ [ "Seer commands:" , "- `see PLAYER`" ]- , whenPlayerHasRole callerName mGame wildChildRole- [ "Wild-child commands:"- , "- `choose PLAYER`"- ] , whenPlayerHasRole callerName mGame witchRole [ "Witch commands:" , "- `heal`"@@ -153,8 +157,8 @@ , whenRoleInPlay mGame angelRole "- (When the Angel is in play) the village votes to lynch a suspect." , "- The village falls asleep."- , whenRoleInPlay mGame wildChildRole- "- (First round only) the Wild-child wakes up and chooses a role model."+ , whenRoleInPlay mGame orphanRole+ "- (First round only) the Orphan wakes up and chooses a role model." , whenRoleInPlay mGame protectorRole "- The Protector wakes up and protects someone." , whenRoleInPlay mGame seerRole@@ -165,11 +169,15 @@ , whenRoleInPlay mGame witchRole "- The Witch wakes up and may heal the victim and/or poison someone." , "- The village wakes up and find the victim."+ , whenRoleInPlay mGame hunterRole+ "- (When the Hunter is killed) the Hunter chooses someone to shoot." , whenRoleInPlay mGame druidRole "- Ferina grunts if the Druid is next to a Werewolf." , "- The village votes to lynch a suspect." , whenRoleInPlay mGame devotedServantRole "- (When someone is lynched) the Devoted Servant may choose whether to reveal themselves and take on the role of their master."+ , whenRoleInPlay mGame hunterRole+ "- (When the Hunter is killed) the Hunter chooses someone to shoot." , whenRoleInPlay mGame scapegoatRole "- (When the Scapegoat is blamed) the Scapegoat chooses whom may vote on the next day." , T.concat
src/Game/Werewolf/Command/DevotedServant.hs view
@@ -34,7 +34,7 @@ passCommand callerName = Command $ do validateCommand callerName - passes %= nub . cons callerName+ passed .= True revealCommand :: Text -> Command revealCommand callerName = Command $ do@@ -49,6 +49,7 @@ setPlayerRole targetName devotedServantRole tell [devotedServantRevealedMessage callerName]+ tell [roleTakenMessage callerName targetRole] resetRole callerName targetRole @@ -61,11 +62,11 @@ resetRole :: (MonadState Game m, MonadWriter [Message] m) => Text -> Role -> m () resetRole callerName role | role == jesterRole = jesterRevealed .= False+ | role == orphanRole = roleModel .= Nothing | role == simpleWerewolfRole = do aliveWerewolfNames <- toListOf (players . werewolves . alive . name) <$> get tell $ devotedServantJoinedPackMessages callerName (aliveWerewolfNames \\ [callerName])- | role == wildChildRole = roleModel .= Nothing | role == witchRole = healUsed .= False >> poisonUsed .= False- | role == wolfHoundRole = allegianceChosen .= Nothing+ | role == wolfHoundRole = allegianceChosen .= False | otherwise = return ()
+ src/Game/Werewolf/Command/Hunter.hs view
@@ -0,0 +1,41 @@+{-|+Module : Game.Werewolf.Command.Hunter+Description : Hunter commands.++Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com++Hunter commands.+-}++module Game.Werewolf.Command.Hunter (+ -- * Commands+ chooseCommand,+) where++import Control.Lens+import Control.Monad.Except+import Control.Monad.Extra+import Control.Monad.Writer++import Data.Text (Text)++import Game.Werewolf hiding (doesPlayerExist, killPlayer)+import Game.Werewolf.Messages+import Game.Werewolf.Util++chooseCommand :: Text -> Text -> Command+chooseCommand callerName targetName = Command $ do+ whenM isGameOver $ throwError [gameIsOverMessage callerName]+ unlessM (doesPlayerExist callerName) $ throwError [playerDoesNotExistMessage callerName callerName]+ unlessM (isPlayerHunter callerName) $ throwError [playerCannotDoThatMessage callerName]+ unlessM isHuntersTurn $ throwError [playerCannotDoThatRightNowMessage callerName]+ validatePlayer callerName targetName++ target <- findPlayerBy_ name targetName++ tell [playerShotMessage target]+ killPlayer targetName++ hunterRetaliated .= True
+ src/Game/Werewolf/Command/Orphan.hs view
@@ -0,0 +1,35 @@+{-|+Module : Game.Werewolf.Command.Orphan+Description : Orphan commands.++Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com++Orphan commands.+-}++module Game.Werewolf.Command.Orphan (+ -- * Commands+ chooseCommand,+) where++import Control.Lens+import Control.Monad.Except+import Control.Monad.Extra++import Data.Text (Text)++import Game.Werewolf+import Game.Werewolf.Messages+import Game.Werewolf.Util++chooseCommand :: Text -> Text -> Command+chooseCommand callerName targetName = Command $ do+ validatePlayer callerName callerName+ unlessM (isPlayerOrphan callerName) $ throwError [playerCannotDoThatMessage callerName]+ unlessM isOrphansTurn $ throwError [playerCannotDoThatRightNowMessage callerName]+ when (callerName == targetName) $ throwError [playerCannotChooseSelfMessage callerName]+ validatePlayer callerName targetName++ roleModel .= Just targetName
src/Game/Werewolf/Command/Status.hs view
@@ -9,7 +9,9 @@ Status commands. -} -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-} module Game.Werewolf.Command.Status ( -- * Commands@@ -37,70 +39,44 @@ pingCommand :: Text -> Command pingCommand callerName = Command $ use stage >>= \stage' -> case stage' of- DevotedServantsTurn -> do- devotedServant <- findPlayerBy_ role devotedServantRole-- tell [pingRoleMessage $ devotedServantRole ^. Role.name]- tell [pingPlayerMessage $ devotedServant ^. name]-+ DevotedServantsTurn -> pingRole devotedServantRole FerinasGrunt -> return ()- GameOver -> tell [gameIsOverMessage callerName]-+ HuntersTurn1 -> pingRole hunterRole+ HuntersTurn2 -> pingRole hunterRole Lynching -> return ()-- ProtectorsTurn -> do- protector <- findPlayerBy_ role protectorRole-- tell [pingRoleMessage $ protectorRole ^. Role.name]- tell [pingPlayerMessage $ protector ^. name]-- ScapegoatsTurn -> do- scapegoat <- findPlayerBy_ role scapegoatRole-- tell [pingRoleMessage $ scapegoatRole ^. Role.name]- tell [pingPlayerMessage $ scapegoat ^. name]-- SeersTurn -> do- seer <- findPlayerBy_ role seerRole-- tell [pingRoleMessage $ seerRole ^. Role.name]- tell [pingPlayerMessage $ seer ^. name]-+ OrphansTurn -> pingRole orphanRole+ ProtectorsTurn -> pingRole protectorRole+ ScapegoatsTurn -> pingRole scapegoatRole+ SeersTurn -> pingRole seerRole Sunrise -> return ()- Sunset -> return ()-- VillagesTurn -> do- allowedVoterNames <- use allowedVoters- pendingVoterNames <- toListOf names <$> getPendingVoters-- tell [waitingOnMessage Nothing $ allowedVoterNames `intersect` pendingVoterNames]- tell $ map pingPlayerMessage (allowedVoterNames `intersect` pendingVoterNames)-- WerewolvesTurn -> do- pendingVoters <- getPendingVoters-- tell [pingRoleMessage "Werewolves"]- tell $ map pingPlayerMessage (pendingVoters ^.. werewolves . name)+ VillagesTurn -> pingVillagers+ WerewolvesTurn -> pingWerewolves+ WitchsTurn -> pingRole witchRole+ WolfHoundsTurn -> pingRole wolfHoundRole - WildChildsTurn -> do- wildChild <- findPlayerBy_ role wildChildRole+pingRole :: (MonadState Game m, MonadWriter [Message] m) => Role -> m ()+pingRole role' = do+ player <- findPlayerBy_ role role' - tell [pingRoleMessage $ wildChildRole ^. Role.name]- tell [pingPlayerMessage $ wildChild ^. name]+ tell [pingRoleMessage $ role' ^. Role.name]+ tell [pingPlayerMessage $ player ^. name] - WitchsTurn -> do- witch <- findPlayerBy_ role witchRole+pingVillagers :: (MonadState Game m, MonadWriter [Message] m) => m ()+pingVillagers = do+ allowedVoterNames <- use allowedVoters+ pendingVoterNames <- toListOf names <$> getPendingVoters - tell [pingRoleMessage $ witchRole ^. Role.name]- tell [pingPlayerMessage $ witch ^. name]+ tell [waitingOnMessage Nothing $ allowedVoterNames `intersect` pendingVoterNames]+ tell $ map pingPlayerMessage (allowedVoterNames `intersect` pendingVoterNames) - WolfHoundsTurn -> do- wolfHound <- findPlayerBy_ role wolfHoundRole+pingWerewolves :: (MonadState Game m, MonadWriter [Message] m) => m ()+pingWerewolves = do+ pendingVoters <- getPendingVoters - tell [pingRoleMessage $ wolfHoundRole ^. Role.name]- tell [pingPlayerMessage $ wolfHound ^. name]+ tell [pingRoleMessage "Werewolves"]+ tell $ map pingPlayerMessage (pendingVoters ^.. werewolves . name) statusCommand :: Text -> Command statusCommand callerName = Command $ use stage >>= \stage' -> case stage' of
− src/Game/Werewolf/Command/WildChild.hs
@@ -1,35 +0,0 @@-{-|-Module : Game.Werewolf.Command.WildChild-Description : Wild-child commands.--Copyright : (c) Henry J. Wylde, 2016-License : BSD3-Maintainer : public@hjwylde.com--Wild-child commands.--}--module Game.Werewolf.Command.WildChild (- -- * Commands- chooseCommand,-) where--import Control.Lens-import Control.Monad.Except-import Control.Monad.Extra--import Data.Text (Text)--import Game.Werewolf-import Game.Werewolf.Messages-import Game.Werewolf.Util--chooseCommand :: Text -> Text -> Command-chooseCommand callerName targetName = Command $ do- validatePlayer callerName callerName- unlessM (isPlayerWildChild callerName) $ throwError [playerCannotDoThatMessage callerName]- unlessM isWildChildsTurn $ throwError [playerCannotDoThatRightNowMessage callerName]- when (callerName == targetName) $ throwError [playerCannotChooseSelfMessage callerName]- validatePlayer callerName targetName-- roleModel .= Just targetName
src/Game/Werewolf/Command/Witch.hs view
@@ -22,7 +22,6 @@ import Control.Monad.Extra import Control.Monad.State hiding (state) -import Data.List import Data.Text (Text) import Game.Werewolf@@ -42,7 +41,7 @@ passCommand callerName = Command $ do validateCommand callerName - passes %= nub . cons callerName+ passed .= True poisonCommand :: Text -> Text -> Command poisonCommand callerName targetName = Command $ do
src/Game/Werewolf/Command/WolfHound.hs view
@@ -35,8 +35,11 @@ unlessM isWolfHoundsTurn $ throwError [playerCannotDoThatRightNowMessage callerName] when (isNothing mAllegiance) $ throwError [allegianceDoesNotExistMessage callerName allegianceName] - allegianceChosen .= mAllegiance+ setPlayerAllegiance callerName allegiance++ allegianceChosen .= True where+ allegiance = fromJust mAllegiance mAllegiance = case T.toLower allegianceName of "villagers" -> Just Villagers "werewolves" -> Just Werewolves
src/Game/Werewolf/Engine.hs view
@@ -71,7 +71,7 @@ whenM (has (players . devotedServants . dead) <$> get) advanceStage whenM (has devotedServants <$> getVoteResult) advanceStage- whenM (has devotedServants <$> getPassers) advanceStage+ whenM (use passed) advanceStage FerinasGrunt -> do druid <- findPlayerBy_ role druidRole@@ -83,6 +83,10 @@ GameOver -> return () + HuntersTurn1 -> whenM (use hunterRetaliated) advanceStage++ HuntersTurn2 -> whenM (use hunterRetaliated) advanceStage+ Lynching -> do getVoteResult >>= lynchVotees @@ -95,6 +99,11 @@ advanceStage + OrphansTurn -> do+ whenM (has (players . orphans . dead) <$> get) advanceStage++ whenM (isJust <$> use roleModel) advanceStage+ ProtectorsTurn -> do whenM (has (players . protectors . dead) <$> get) advanceStage @@ -130,14 +139,14 @@ Sunset -> do whenJustM (use roleModel) $ \roleModelsName -> do- wildChild <- findPlayerBy_ role wildChildRole+ orphan <- findPlayerBy_ role orphanRole - whenM (isPlayerDead roleModelsName &&^ return (is alive wildChild) &&^ return (is villager wildChild)) $ do+ whenM (isPlayerDead roleModelsName &&^ return (is alive orphan) &&^ return (is villager orphan)) $ do aliveWerewolfNames <- toListOf (players . werewolves . alive . name) <$> get - setPlayerAllegiance (wildChild ^. name) Werewolves+ setPlayerAllegiance (orphan ^. name) Werewolves - tell $ wildChildJoinedPackMessages (wildChild ^. name) aliveWerewolfNames+ tell $ orphanJoinedPackMessages (orphan ^. name) aliveWerewolfNames advanceStage @@ -154,11 +163,6 @@ advanceStage - WildChildsTurn -> do- whenM (has (players . wildChildren . dead) <$> get) advanceStage-- whenM (isJust <$> use roleModel) advanceStage- WitchsTurn -> do whenM (has (players . witches . dead) <$> get) advanceStage @@ -173,17 +177,12 @@ heal .= False whenM (use healUsed &&^ use poisonUsed) advanceStage- whenM (has witches <$> getPassers) advanceStage+ whenM (use passed) advanceStage WolfHoundsTurn -> do whenM (has (players . wolfHounds . dead) <$> get) advanceStage - whenJustM (use allegianceChosen) $ \allegiance -> do- wolfHound <- findPlayerBy_ role wolfHoundRole-- setPlayerAllegiance (wolfHound ^. name) allegiance-- advanceStage+ whenM (use allegianceChosen) advanceStage lynchVotees :: (MonadState Game m, MonadWriter [Message] m) => [Player] -> m () lynchVotees [votee]@@ -217,7 +216,7 @@ stage .= nextStage boots .= Map.empty- passes .= []+ passed .= False see .= Nothing tell . stageMessages =<< get
src/Game/Werewolf/Game.hs view
@@ -17,14 +17,14 @@ module Game.Werewolf.Game ( -- * Game Game,- stage, round, players, events, boots, passes, allegianceChosen, allowedVoters, heal, healUsed,- jesterRevealed, poison, poisonUsed, priorProtect, protect, roleModel, scapegoatBlamed, see,- votes,+ stage, round, players, events, boots, allegianceChosen, allowedVoters, heal, healUsed,+ hunterRetaliated, jesterRevealed, passed, poison, poisonUsed, priorProtect, protect, roleModel,+ scapegoatBlamed, see, votes, Stage(..),- _DevotedServantsTurn, _FerinasGrunt, _GameOver, _Lynching, _ProtectorsTurn, _ScapegoatsTurn,- _SeersTurn, _Sunrise, _Sunset, _VillagesTurn, _WerewolvesTurn, _WildChildsTurn, _WitchsTurn,- _WolfHoundsTurn,+ _DevotedServantsTurn, _FerinasGrunt, _GameOver, _HuntersTurn1, _HuntersTurn2, _Lynching,+ _OrphansTurn, _ProtectorsTurn, _ScapegoatsTurn, _SeersTurn, _Sunrise, _Sunset, _VillagesTurn,+ _WerewolvesTurn, _WitchsTurn, _WolfHoundsTurn, allStages, stageCycle, stageAvailable,@@ -55,7 +55,6 @@ import Data.Text (Text) import Game.Werewolf.Player-import Game.Werewolf.Role hiding (name) import Prelude hiding (round) @@ -68,7 +67,7 @@ -- -- Any further fields on the game are specific to one or more roles (and their respective turns!). -- Some of the additional fields are reset each round (e.g., the Seer's 'see') while others are--- kept around for the whole game (e.g., the Wild-child's 'roleModel').+-- kept around for the whole game (e.g., the Orphan's 'roleModel'). -- -- In order to advance a game's 'state', a 'Game.Werewolf.Command.Command' from a user needs to be -- received. Afterwards the following steps should be performed:@@ -87,17 +86,18 @@ , _players :: [Player] , _events :: [Event] , _boots :: Map Text [Text]- , _allegianceChosen :: Maybe Allegiance -- ^ Wolf-hound+ , _allegianceChosen :: Bool -- ^ Wolf-hound , _allowedVoters :: [Text] -- ^ Scapegoat , _heal :: Bool -- ^ Witch , _healUsed :: Bool -- ^ Witch+ , _hunterRetaliated :: Bool -- ^ Hunter , _jesterRevealed :: Bool -- ^ Jester- , _passes :: [Text] -- ^ Witch+ , _passed :: Bool -- ^ Devoted Servant, Witch , _poison :: Maybe Text -- ^ Witch , _poisonUsed :: Bool -- ^ Witch , _priorProtect :: Maybe Text -- ^ Protector , _protect :: Maybe Text -- ^ Protector- , _roleModel :: Maybe Text -- ^ Wild-child+ , _roleModel :: Maybe Text -- ^ Orphan , _scapegoatBlamed :: Bool -- ^ Scapegoat , _see :: Maybe Text -- ^ Seer , _votes :: Map Text Text -- ^ Villagers and Werewolves@@ -109,11 +109,12 @@ -- -- Once the game reaches a turn stage, it requires a 'Game.Werewolf.Command.Command' to help push -- it past. Often only certain roles and commands may be performed at any given stage.-data Stage = DevotedServantsTurn | FerinasGrunt | GameOver | Lynching | ProtectorsTurn- | ScapegoatsTurn | SeersTurn | Sunrise | Sunset | VillagesTurn | WerewolvesTurn- | WildChildsTurn | WitchsTurn | WolfHoundsTurn+data Stage = DevotedServantsTurn | FerinasGrunt | GameOver | HuntersTurn1 | HuntersTurn2 | Lynching+ | OrphansTurn | ProtectorsTurn | ScapegoatsTurn | SeersTurn | Sunrise | Sunset+ | VillagesTurn | WerewolvesTurn | WitchsTurn | WolfHoundsTurn deriving (Eq, Read, Show) +-- TODO (hjw): remove events -- | Events occur /after/ a 'Stage' is advanced. This is automatically handled in -- 'Game.Werewolf.Engine.checkStage', while an event's specific behaviour is defined by -- 'Game.Werewolf.Engine.eventAvailable' and 'Game.Werewolf.Engine.applyEvent'.@@ -138,15 +139,17 @@ [ VillagesTurn , DevotedServantsTurn , Lynching+ , HuntersTurn1 , ScapegoatsTurn , Sunset , WolfHoundsTurn , SeersTurn- , WildChildsTurn+ , OrphansTurn , ProtectorsTurn , WerewolvesTurn , WitchsTurn , Sunrise+ , HuntersTurn2 , FerinasGrunt , GameOver ]@@ -167,6 +170,12 @@ && isn't devotedServant (head $ getVoteResult game) stageAvailable game FerinasGrunt = has (players . druids . alive) game stageAvailable _ GameOver = False+stageAvailable game HuntersTurn1 =+ has (players . hunters . dead) game+ && not (game ^. hunterRetaliated)+stageAvailable game HuntersTurn2 =+ has (players . hunters . dead) game+ && not (game ^. hunterRetaliated) stageAvailable game Lynching = Map.size (game ^. votes) > 0 stageAvailable game ProtectorsTurn = has (players . protectors . alive) game stageAvailable game ScapegoatsTurn = game ^. scapegoatBlamed@@ -177,15 +186,15 @@ (has (players . angels . alive) game || not (isFirstRound game)) && any (is alive) (getAllowedVoters game) stageAvailable game WerewolvesTurn = has (players . werewolves . alive) game-stageAvailable game WildChildsTurn =- has (players . wildChildren . alive) game+stageAvailable game OrphansTurn =+ has (players . orphans . alive) game && isNothing (game ^. roleModel) stageAvailable game WitchsTurn = has (players . witches . alive) game && (not (game ^. healUsed) || not (game ^. poisonUsed)) stageAvailable game WolfHoundsTurn = has (players . wolfHounds . alive) game- && isNothing (game ^. allegianceChosen)+ && not (game ^. allegianceChosen) -- | Creates a new 'Game' with the given players. No validations are performed here, those are left -- to 'Game.Werewolf.Engine.startGame'.@@ -198,11 +207,12 @@ , _players = players , _events = [] , _boots = Map.empty- , _passes = []- , _allegianceChosen = Nothing+ , _passed = False+ , _allegianceChosen = False , _allowedVoters = players ^.. names , _heal = False , _healUsed = False+ , _hunterRetaliated = False , _jesterRevealed = False , _poison = Nothing , _poisonUsed = False
src/Game/Werewolf/Messages.hs view
@@ -44,11 +44,17 @@ angelJoinedVillagersMessage, -- * Devoted Servant's turn messages- devotedServantRevealedMessage, devotedServantJoinedPackMessages,+ devotedServantRevealedMessage, roleTakenMessage, devotedServantJoinedPackMessages, -- * Druid's turn messages ferinaGruntsMessage, + -- * Hunter's turn messages+ playerShotMessage,++ -- * Orphan's turn messages+ orphanJoinedPackMessages,+ -- * Protector's turn messages -- ** Error messages@@ -76,9 +82,6 @@ -- ** Error messages playerCannotDevourAnotherWerewolfMessage, - -- * Wild-child's turn messages- wildChildJoinedPackMessages,- -- ** Error messages playerCannotChooseSelfMessage, @@ -149,7 +152,10 @@ DevotedServantsTurn -> devotedServantsTurnMessages devotedServantsName victimsName FerinasGrunt -> [] GameOver -> []+ HuntersTurn1 -> huntersTurnMessages huntersName+ HuntersTurn2 -> huntersTurnMessages huntersName Lynching -> []+ OrphansTurn -> orphansTurnMessages orphansName ProtectorsTurn -> protectorsTurnMessages protectorsName ScapegoatsTurn -> scapegoatsTurnMessages scapegoatsName SeersTurn -> seersTurnMessages seersName@@ -161,18 +167,18 @@ WerewolvesTurn -> if isFirstRound game then firstWerewolvesTurnMessages aliveWerewolfNames else werewolvesTurnMessages aliveWerewolfNames- WildChildsTurn -> wildChildsTurnMessages wildChildsName WitchsTurn -> witchsTurnMessages game WolfHoundsTurn -> wolfHoundsTurnMessages wolfHoundsName where players' = game ^. players- protectorsName = players' ^?! protectors . name devotedServantsName = players' ^?! devotedServants . name victimsName = head (getVoteResult game) ^. name+ huntersName = players' ^?! hunters . name+ orphansName = players' ^?! orphans . name+ protectorsName = players' ^?! protectors . name scapegoatsName = players' ^?! scapegoats . name seersName = players' ^?! seers . name aliveWerewolfNames = players' ^.. werewolves . alive . name- wildChildsName = players' ^?! wildChildren . name wolfHoundsName = players' ^?! wolfHounds . name devotedServantsTurnMessages :: Text -> Text -> [Message]@@ -184,6 +190,18 @@ ] ] +huntersTurnMessages :: Text -> [Message]+huntersTurnMessages huntersName =+ [ publicMessage $ T.unwords ["Just before", huntersName, "was struck down he let off a shot."]+ , privateMessage huntersName "Whom do you `choose` to kill with your last shot?"+ ]++orphansTurnMessages :: Text -> [Message]+orphansTurnMessages to =+ [ publicMessage "The Orphan wakes up."+ , privateMessage to "Whom do you `choose` to be your role model?"+ ]+ protectorsTurnMessages :: Text -> [Message] protectorsTurnMessages to = [ publicMessage "The Protector wakes up."@@ -242,12 +260,6 @@ publicMessage "The Werewolves wake up, transform and choose a new victim." : groupMessages tos "Whom would you like to `vote` to devour?" -wildChildsTurnMessages :: Text -> [Message]-wildChildsTurnMessages to =- [ publicMessage "The Wild-child wakes up."- , privateMessage to "Whom do you `choose` to be your role model?"- ]- witchsTurnMessages :: Game -> [Message] witchsTurnMessages game = concat [ [wakeUpMessage]@@ -405,7 +417,10 @@ showTurn DevotedServantsTurn = "Devoted Servant's" showTurn FerinasGrunt = undefined showTurn GameOver = undefined+ showTurn HuntersTurn1 = "Hunter's"+ showTurn HuntersTurn2 = "Hunter's" showTurn Lynching = undefined+ showTurn OrphansTurn = "Orphan's" showTurn ProtectorsTurn = "Protector's" showTurn ScapegoatsTurn = "Scapegoat's" showTurn SeersTurn = "Seer's"@@ -413,7 +428,6 @@ showTurn Sunset = undefined showTurn VillagesTurn = "village's" showTurn WerewolvesTurn = "Werewolves'"- showTurn WildChildsTurn = "Wild-child's" showTurn WitchsTurn = "Witch's" showTurn WolfHoundsTurn = "Wolf-hound's" @@ -460,11 +474,17 @@ devotedServantRevealedMessage :: Text -> Message devotedServantRevealedMessage devotedServantsName = publicMessage $ T.unwords- [ devotedServantsName, "stands up in horror."- , "Determined to not let their master's abilities be lost forever,"- , "she selflessly takes on their role."+ [ "Determined to not let their master's abilities be lost forever,"+ , devotedServantsName, "the Devoted Servant selflessly takes on their role." ] +roleTakenMessage :: Text -> Role -> Message+roleTakenMessage to role = privateMessage to $ T.intercalate "\n"+ [ T.concat ["You've taken on the role of ", article role, " ", role ^. Role.name, "."]+ , role ^. description+ , role ^. rules+ ]+ devotedServantJoinedPackMessages :: Text -> [Text] -> [Message] devotedServantJoinedPackMessages devotedServantsName werewolfNames = privateMessage devotedServantsName (T.unwords $ masterWasWerewolfMessage:packMessages)@@ -489,6 +509,29 @@ , "She loudly grunts as she smells danger." ] +playerShotMessage :: Player -> Message+playerShotMessage target = publicMessage $ T.unwords+ [ targetName, "the", targetRole, "slumps down to the ground, hands clutching at their chest"+ , "while blood slips between their fingers and pools around them."+ ]+ where+ targetName = target ^. name+ targetRole = target ^. role . Role.name++orphanJoinedPackMessages :: Text -> [Text] -> [Message]+orphanJoinedPackMessages orphansName werewolfNames =+ privateMessage orphansName (T.unwords+ [ "The death of your role model is distressing."+ , "Without second thought you abandon the Villagers and run off into the woods,"+ , "towards your old home."+ , "As you arrive you see the familiar", tryPlural (length werewolfNames) "face", "of"+ , concatList werewolfNames, "waiting and happy to have you back."+ ])+ : groupMessages werewolfNames (T.unwords+ [ orphansName, "the Orphan scampers off into the woods."+ , "Without their role model nothing is holding back their true, wolfish, nature."+ ])+ playerCannotProtectSamePlayerTwiceInARowMessage :: Text -> Message playerCannotProtectSamePlayerTwiceInARowMessage to = privateMessage to "You cannot protect the same player twice in a row!"@@ -585,20 +628,6 @@ playerCannotDevourAnotherWerewolfMessage :: Text -> Message playerCannotDevourAnotherWerewolfMessage to = privateMessage to "You cannot devour another Werewolf!"--wildChildJoinedPackMessages :: Text -> [Text] -> [Message]-wildChildJoinedPackMessages wildChildsName werewolfNames =- privateMessage wildChildsName (T.unwords- [ "The death of your role model is distressing."- , "Without second thought you abandon the Villagers and run off into the woods,"- , "towards your old home."- , "As you arrive you see the familiar", tryPlural (length werewolfNames) "face", "of"- , concatList werewolfNames, "waiting and happy to have you back."- ])- : groupMessages werewolfNames (T.unwords- [ wildChildsName, "the Wild-child scampers off into the woods."- , "Without his role model nothing is holding back his true, wolfish, nature."- ]) playerCannotChooseSelfMessage :: Text -> Message playerCannotChooseSelfMessage to = privateMessage to "You cannot choose yourself!"
src/Game/Werewolf/Player.hs view
@@ -26,16 +26,16 @@ newPlayer, -- ** Traversals- angel, devotedServant, druid, jester, protector, scapegoat, seer, simpleVillager,- simpleWerewolf, villagerVillager, wildChild, witch, wolfHound,+ angel, devotedServant, druid, hunter, jester, orphan, protector, scapegoat, seer,+ simpleVillager, simpleWerewolf, villagerVillager, witch, wolfHound, villager, werewolf, -- | These are provided just as a bit of sugar to avoid continually writing @'traverse' .@. names, roles, states, -- | N.B., these are not legal traversals for the same reason 'filtered' isn't!- angels, devotedServants, druids, jesters, protectors, scapegoats, seers, simpleVillagers,- simpleWerewolves, villagerVillagers, wildChildren, witches, wolfHounds,+ angels, devotedServants, druids, hunters, jesters, orphans, protectors, scapegoats, seers,+ simpleVillagers, simpleWerewolves, villagerVillagers, witches, wolfHounds, villagers, werewolves, alive, dead, @@ -99,6 +99,14 @@ druid :: Traversal' Player () druid = role . only druidRole +-- | The traversal of 'Player's with a 'hunterRole'.+--+-- @+-- 'hunter' = 'role' . 'only' 'hunterRole'+-- @+hunter :: Traversal' Player ()+hunter = role . only hunterRole+ -- | The traversal of 'Player's with a 'jesterRole'. -- -- @@@ -107,6 +115,14 @@ jester :: Traversal' Player () jester = role . only jesterRole +-- | The traversal of 'Player's with a 'orphanRole'.+--+-- @+-- 'orphan' = 'role' . 'only' 'orphanRole'+-- @+orphan :: Traversal' Player ()+orphan = role . only orphanRole+ -- | The traversal of 'Player's with a 'protectorRole'. -- -- @@@ -155,14 +171,6 @@ villagerVillager :: Traversal' Player () villagerVillager = role . only villagerVillagerRole --- | The traversal of 'Player's with a 'wildChildRole'.------ @--- 'wildChild' = 'role' . 'only' 'wildChildRole'--- @-wildChild :: Traversal' Player ()-wildChild = role . only wildChildRole- -- | The traversal of 'Player's with a 'witchRole'. -- -- @@@ -243,6 +251,14 @@ druids :: Traversable t => Traversal' (t Player) Player druids = traverse . filtered (is druid) +-- | This 'Traversal' provides the traversal of 'hunter' 'Player's.+--+-- @+-- 'hunters' = 'traverse' . 'filtered' ('is' 'hunter')+-- @+hunters :: Traversable t => Traversal' (t Player) Player+hunters = traverse . filtered (is hunter)+ -- | This 'Traversal' provides the traversal of 'jester' 'Player's. -- -- @@@ -251,6 +267,14 @@ jesters :: Traversable t => Traversal' (t Player) Player jesters = traverse . filtered (is jester) +-- | This 'Traversal' provides the traversal of 'orphan' 'Player's.+--+-- @+-- 'orphans' = 'traverse' . 'filtered' ('is' 'orphan')+-- @+orphans :: Traversable t => Traversal' (t Player) Player+orphans = traverse . filtered (is orphan)+ -- | This 'Traversal' provides the traversal of 'protector' 'Player's. -- -- @@@ -298,14 +322,6 @@ -- @ villagerVillagers :: Traversable t => Traversal' (t Player) Player villagerVillagers = traverse . filtered (is villagerVillager)---- | This 'Traversal' provides the traversal of 'wildChild' 'Player's.------ @--- 'wildChildren' = 'traverse' . 'filtered' ('is' 'wildChild')--- @-wildChildren :: Traversable t => Traversal' (t Player) Player-wildChildren = traverse . filtered (is wildChild) -- | This 'Traversal' provides the traversal of 'witch' 'Player's. --
src/Game/Werewolf/Role.hs view
@@ -33,7 +33,7 @@ -- | No-one knows the true nature of the Ambiguous, sometimes not even the Ambiguous themselves! -- -- The Ambiguous are able to change allegiance throughout the game.- devotedServantRole, wildChildRole, wolfHoundRole,+ devotedServantRole, orphanRole, wolfHoundRole, -- *** The Loners -- | The Loners look out for themselves and themselves alone.@@ -47,7 +47,7 @@ -- certain few have learnt some tricks over the years that may turn out rather useful. -- The Villagers must lynch all of the Werewolves.- druidRole, jesterRole, protectorRole, scapegoatRole, seerRole, simpleVillagerRole,+ druidRole, hunterRole, jesterRole, protectorRole, scapegoatRole, seerRole, simpleVillagerRole, villagerVillagerRole, witchRole, -- *** The Werewolves@@ -103,14 +103,15 @@ [ angelRole , devotedServantRole , druidRole+ , hunterRole , jesterRole+ , orphanRole , protectorRole , scapegoatRole , seerRole , simpleVillagerRole , simpleWerewolfRole , villagerVillagerRole- , wildChildRole , witchRole , wolfHoundRole ]@@ -149,41 +150,37 @@ ] } --- | /Abandoned in the woods by his parents at a young age, he was raised by wolves. As soon as he/--- /learned how to walk on all fours, the Wild-child began to wander around Miller's Hollow. One/--- /day, fascinated by an inhabitant of the village who was walking upright with grace and/--- /presence, he made them his secret role model. He then decided to integrate himself into the/--- /community of Miller's Hollow and entered, worried, in the village. The community was moved by/--- /his frailty, adopted him, and welcomed him in their fold. What will become of him: honest/--- /Villager or terrible Werewolf? For all of his life, the heart of the Wild-child will swing/--- /between these two alternatives. May his model confirm him in his newfound humanity./+-- | /Abandoned by their parents as a child, with no-one wanting to look after another mouth to/+-- /feed, the Orphan was left to fend for themself. No-one looks twice at the Orphan and even/+-- /fewer offer kindness towards the lonely child. One day however, one townsperson changes all/+-- /this. He offers the Orphan food, water and a roof over his head. Grateful for his chairty and/+-- /affection, the Orphan makes him their role model. Pray that no ill should befall their role/+-- /model, for who knows in such an event whom, or what, the Orphan may turn to.../ ----- On the first night, the Wild-child may choose a player to become his role model. If during the--- game the chosen player is eliminated, the Wild-child becomes a Werewolf. He will then wake up--- the next night with his peers and will devour with them each night until the end of the game.--- However for as long as the Wild-child's role model is alive, he remains a Villager.-wildChildRole :: Role-wildChildRole = Role- { _name = "Wild-child"+-- On the first night, the Orphan may choose a player to become his role model. If during the game+-- the role model is eliminated, the Orphan becomes a Werewolf. He will then wake up the next+-- night with his peers and will devour with them each night until the end of the game. However+-- for as long as the Orphan's role model is alive, he remains a Villager.+orphanRole :: Role+orphanRole = Role+ { _name = "Orphan" , _allegiance = Villagers , _balance = -1 , _description = T.unwords- [ "Abandoned in the woods by his parents at a young age, he was raised by wolves. As soon"- , "as he learned how to walk on all fours, the Wild-child began to wander around Miller's"- , "Hollow. One day, fascinated by an inhabitant of the village who was walking upright"- , "with grace and presence, he made them his secret role model. He then decided to"- , "integrate himself into the community of Miller's Hollow and entered, worried, in the"- , "village. The community was moved by his frailty, adopted him, and welcomed him in their"- , "fold. What will become of him: honest Villager or terrible Werewolf? For all of his"- , "life, the heart of the Wild-child will swing between these two alternatives. May his"- , "model confirm him in his newfound humanity."+ [ "Abandoned by their parents as a child, with no-one wanting to look after another mouth"+ , "to feed, the Orphan was left to fend for themself. No-one looks twice at the Orphan and"+ , "even fewer offer kindness towards the lonely child. One day however, one townsperson"+ , "changes all this. He offers the Orphan food, water and a roof over his head. Grateful"+ , "for his chairty and affection, the Orphan makes him their role model. Pray that no ill"+ , "should befall their role model, for who knows in such an event whom, or what, the Orphan"+ , "may turn to..." ] , _rules = T.unwords- [ "On the first night, the Wild-child may choose a player to become his role model. If"- , "during the game the chosen player is eliminated, the Wild-child becomes a Werewolf. He"- , "will then wake up the next night with his peers and will devour with them each night"- , "until the end of the game. However for as long as the Wild-child's role model is alive,"- , "he remains a Villager."+ [ "On the first night, the Orphan may choose a player to become his role model. If during"+ , "the game the role model is eliminated, the Orphan becomes a Werewolf. He will then wake"+ , "up the next night with his peers and will devour with them each night until the end of"+ , "the game. However for as long as the Orphan's role model is alive, he remains a"+ , "Villager." ] } @@ -268,6 +265,28 @@ ] } +-- | /A skilled marksman with quick reflexes. In the unfortunate situation that they are jumped and/+-- /killed unjustly, they are able to let off a shot at their attacker, killing them instantly./+-- /The Hunter never misses./+--+-- If the Hunter gets killed they get to choose one player, believed to be an attacker, to kill+-- immediately.+hunterRole :: Role+hunterRole = Role+ { _name = "Hunter"+ , _allegiance = Villagers+ , _balance = 2+ , _description = T.unwords+ [ "A skilled marksman with quick reflexes. In the unfortunate situation that they are"+ , "jumped and killed unjustly, they are able to let off a shot at their attacker, killing"+ , "them instantly. The Hunter never misses."+ ]+ , _rules = T.unwords+ [ "If the Hunter gets killed they get to choose one player, believed to be an attacker, to"+ , "kill immediately."+ ]+ }+ -- | /The Protector is one of the few pure of heart and altruistic Villagers. They are forever/ -- /putting others needs above their own, standing guard at night against this terrifying foe./ -- /Each night they fight against the Werewolves with naught but a sword and shield, potentially/@@ -298,8 +317,8 @@ } -- | /Werewolves don't just spring up out of the ground! That's where dwarves come from. Clearly/--- /someone is to blame for this affliction to Fougères. Ah! Unluckily, since no-one actually/--- /knows who brought them here, the blame is always laid upon the Scapegoat./+-- /someone is to blame for this affliction to Fougères. Unluckily for the Scapegoat, since/+-- /no-one actually knows who brought them here, the blame is always laid upon them!/ -- -- If the village's vote ends in a tie, it's the Scapegoat who is eliminated instead of no-one. --@@ -312,8 +331,9 @@ , _balance = 0 , _description = T.unwords [ "Werewolves don't just spring up out of the ground! That's where dwarves come from."- , "Clearly someone is to blame for this affliction to Fougères. Ah! Unluckily, since no-one"- , "actually knows who brought them here, the blame is always laid upon the Scapegoat."+ , "Clearly someone is to blame for this affliction to Fougères. Unluckily for the"+ , "Scapegoat, since no-one actually knows who brought them here, the blame is always laid"+ , "upon them!" ] , _rules = T.intercalate "\n" [ T.unwords
src/Game/Werewolf/Util.hs view
@@ -20,20 +20,21 @@ killPlayer, removePlayer, setPlayerAllegiance, setPlayerRole, -- ** Searches- findPlayerBy_, getAdjacentAlivePlayers, getPassers, getPlayerVote,- getAllowedVoters, getPendingVoters, getVoteResult,+ findPlayerBy_, getAdjacentAlivePlayers, getPlayerVote, getAllowedVoters, getPendingVoters,+ getVoteResult, -- ** Queries- isDevotedServantsTurn, isGameOver, isProtectorsTurn, isScapegoatsTurn, isSeersTurn, isSunrise,- isVillagesTurn, isWerewolvesTurn, isWildChildsTurn, isWitchsTurn, isWolfHoundsTurn,+ isDevotedServantsTurn, isGameOver, isHuntersTurn, isOrphansTurn, isProtectorsTurn,+ isScapegoatsTurn, isSeersTurn, isSunrise, isVillagesTurn, isWerewolvesTurn, isWitchsTurn,+ isWolfHoundsTurn, hasAnyoneWon, hasAngelWon, hasVillagersWon, hasWerewolvesWon, -- * Player -- ** Queries doesPlayerExist,- isPlayerDevotedServant, isPlayerJester, isPlayerProtector, isPlayerScapegoat, isPlayerSeer,- isPlayerWildChild, isPlayerWitch, isPlayerWolfHound,+ isPlayerDevotedServant, isPlayerHunter, isPlayerJester, isPlayerOrphan, isPlayerProtector,+ isPlayerScapegoat, isPlayerSeer, isPlayerWitch, isPlayerWolfHound, isPlayerWerewolf, isPlayerAlive, isPlayerDead, ) where@@ -63,25 +64,24 @@ removePlayer name' = do killPlayer name' - passes %= delete name'- votes %= Map.delete name'+ votes %= Map.delete name' player <- findPlayerBy_ name name' when (is angel player) $ setPlayerAllegiance name' Villagers+ when (is orphan player) $ roleModel .= Nothing when (is protector player) $ do protect .= Nothing priorProtect .= Nothing when (is seer player) $ see .= Nothing- when (is wildChild player) $ roleModel .= Nothing when (is witch player) $ do heal .= False healUsed .= False poison .= Nothing poisonUsed .= False- when (is wolfHound player) $ allegianceChosen .= Nothing+ when (is wolfHound player) $ allegianceChosen .= True --- | Fudges the player's allegiance. This function is useful for roles such as the Wild-child where+-- | Fudges the player's allegiance. This function is useful for roles such as the Orphan where -- they align themselves differently given some trigger. setPlayerAllegiance :: MonadState Game m => Text -> Allegiance -> m () setPlayerAllegiance name' allegiance' = modify $ players . traverse . filteredBy name name' . role . allegiance .~ allegiance'@@ -104,9 +104,6 @@ adjacentElements 0 list = last list : take 2 list adjacentElements index list = take 3 $ drop (index - 1) (cycle list) -getPassers :: MonadState Game m => m [Player]-getPassers = mapM (findPlayerBy_ name) =<< use passes- getPlayerVote :: MonadState Game m => Text -> m (Maybe Text) getPlayerVote playerName = use $ votes . at playerName @@ -125,6 +122,15 @@ isGameOver :: MonadState Game m => m Bool isGameOver = has (stage . _GameOver) <$> get +isHuntersTurn :: MonadState Game m => m Bool+isHuntersTurn = orM+ [ has (stage . _HuntersTurn1) <$> get+ , has (stage . _HuntersTurn2) <$> get+ ]++isOrphansTurn :: MonadState Game m => m Bool+isOrphansTurn = has (stage . _OrphansTurn) <$> get+ isProtectorsTurn :: MonadState Game m => m Bool isProtectorsTurn = has (stage . _ProtectorsTurn) <$> get @@ -143,9 +149,6 @@ isWerewolvesTurn :: MonadState Game m => m Bool isWerewolvesTurn = has (stage . _WerewolvesTurn) <$> get -isWildChildsTurn :: MonadState Game m => m Bool-isWildChildsTurn = has (stage . _WildChildsTurn) <$> get- isWitchsTurn :: MonadState Game m => m Bool isWitchsTurn = has (stage . _WitchsTurn) <$> get @@ -170,9 +173,15 @@ isPlayerDevotedServant :: MonadState Game m => Text -> m Bool isPlayerDevotedServant name' = is devotedServant <$> findPlayerBy_ name name' +isPlayerHunter :: MonadState Game m => Text -> m Bool+isPlayerHunter name' = is hunter <$> findPlayerBy_ name name'+ isPlayerJester :: MonadState Game m => Text -> m Bool isPlayerJester name' = is jester <$> findPlayerBy_ name name' +isPlayerOrphan :: MonadState Game m => Text -> m Bool+isPlayerOrphan name' = is orphan <$> findPlayerBy_ name name'+ isPlayerProtector :: MonadState Game m => Text -> m Bool isPlayerProtector name' = is protector <$> findPlayerBy_ name name' @@ -181,9 +190,6 @@ isPlayerSeer :: MonadState Game m => Text -> m Bool isPlayerSeer name' = is seer <$> findPlayerBy_ name name'--isPlayerWildChild :: MonadState Game m => Text -> m Bool-isPlayerWildChild name' = is wildChild <$> findPlayerBy_ name name' isPlayerWitch :: MonadState Game m => Text -> m Bool isPlayerWitch name' = is witch <$> findPlayerBy_ name name'
test/src/Game/Werewolf/Test/Arbitrary.hs view
@@ -12,14 +12,15 @@ -- ** Game NewGame(..),- GameAtDevotedServantsTurn(..), GameAtGameOver(..), GameAtProtectorsTurn(..),- GameAtScapegoatsTurn(..), GameAtSeersTurn(..), GameAtSunrise(..), GameAtVillagesTurn(..),- GameAtWerewolvesTurn(..), GameAtWildChildsTurn(..), GameAtWitchsTurn(..),+ GameAtDevotedServantsTurn(..), GameAtGameOver(..), GameAtHuntersTurn(..), GameAtOrphansTurn(..),+ GameAtProtectorsTurn(..), GameAtScapegoatsTurn(..), GameAtSeersTurn(..), GameAtSunrise(..),+ GameAtVillagesTurn(..), GameAtWerewolvesTurn(..), GameAtWitchsTurn(..), GameAtWolfHoundsTurn(..), GameOnSecondRound(..), GameWithAllegianceChosen(..), GameWithAllowedVoters(..), GameWithConflictingVote(..), GameWithDeadPlayers(..), GameWithDevourEvent(..), GameWithDevourVotes(..), GameWithHeal(..), GameWithJesterRevealedAtVillagesTurn(..), GameWithLynchVotes(..), GameWithMajorityVote(..),+ GameWithNoAllowedVotersAtVillagesTurn(..), GameWithNoWerewolvesAtProtectorsTurn(..), GameWithOneAllegianceAlive(..), GameWithPassAtDevotedServantsTurn(..), GameWithPoison(..), GameWithProtect(..), GameWithProtectAndDevourVotes(..), GameWithRoleModel(..), GameWithRoleModelAtVillagesTurn(..), GameWithSee(..),@@ -30,11 +31,11 @@ -- * Contextual arbitraries -- ** Command- arbitraryCommand, arbitraryWolfHoundChooseCommand, arbitraryWildChildChooseCommand,- arbitraryScapegoatChooseCommand, arbitraryHealCommand, arbitraryDevotedServantPassCommand,- arbitraryWitchPassCommand, arbitraryPoisonCommand, arbitraryProtectCommand,- arbitraryQuitCommand, arbitraryRevealCommand, arbitrarySeeCommand, arbitraryWerewolfVoteCommand,- arbitraryVillagerVoteCommand,+ arbitraryCommand, arbitraryHunterChooseCommand, arbitraryOrphanChooseCommand,+ arbitraryWolfHoundChooseCommand, arbitraryScapegoatChooseCommand, arbitraryHealCommand,+ arbitraryDevotedServantPassCommand, arbitraryWitchPassCommand, arbitraryPoisonCommand,+ arbitraryProtectCommand, arbitraryQuitCommand, arbitraryRevealCommand, arbitrarySeeCommand,+ arbitraryWerewolfVoteCommand, arbitraryVillagerVoteCommand, runArbitraryCommands, -- ** Player@@ -51,12 +52,13 @@ import Game.Werewolf import Game.Werewolf.Command.DevotedServant as DevotedServant import Game.Werewolf.Command.Global+import Game.Werewolf.Command.Hunter as Hunter+import Game.Werewolf.Command.Orphan as Orphan import Game.Werewolf.Command.Protector import Game.Werewolf.Command.Scapegoat as Scapegoat import Game.Werewolf.Command.Seer import Game.Werewolf.Command.Villager as Villager import Game.Werewolf.Command.Werewolf as Werewolf-import Game.Werewolf.Command.WildChild as WildChild import Game.Werewolf.Command.Witch as Witch import Game.Werewolf.Command.WolfHound as WolfHound import Game.Werewolf.Test.Util@@ -115,6 +117,25 @@ return $ GameAtGameOver (game & stage .~ GameOver) +newtype GameAtHuntersTurn = GameAtHuntersTurn Game+ deriving (Eq, Show)++instance Arbitrary GameAtHuntersTurn where+ arbitrary = do+ game <- arbitrary+ turn <- elements [HuntersTurn1, HuntersTurn2]++ return $ GameAtHuntersTurn (game & stage .~ turn)++newtype GameAtOrphansTurn = GameAtOrphansTurn Game+ deriving (Eq, Show)++instance Arbitrary GameAtOrphansTurn where+ arbitrary = do+ game <- arbitrary++ return $ GameAtOrphansTurn (game & stage .~ OrphansTurn)+ newtype GameAtProtectorsTurn = GameAtProtectorsTurn Game deriving (Eq, Show) @@ -169,15 +190,6 @@ return $ GameAtWerewolvesTurn (game & stage .~ WerewolvesTurn) -newtype GameAtWildChildsTurn = GameAtWildChildsTurn Game- deriving (Eq, Show)--instance Arbitrary GameAtWildChildsTurn where- arbitrary = do- game <- arbitrary-- return $ GameAtWildChildsTurn (game & stage .~ WildChildsTurn)- newtype GameAtWitchsTurn = GameAtWitchsTurn Game deriving (Eq, Show) @@ -323,6 +335,26 @@ return . GameWithMajorityVoteAtDevotedServantsTurn $ run_ checkStage game +newtype GameWithNoAllowedVotersAtVillagesTurn = GameWithNoAllowedVotersAtVillagesTurn Game+ deriving (Eq, Show)++instance Arbitrary GameWithNoAllowedVotersAtVillagesTurn where+ arbitrary = do+ (GameAtVillagesTurn game) <- arbitrary++ return $ GameWithNoAllowedVotersAtVillagesTurn (game & allowedVoters .~ [])++newtype GameWithNoWerewolvesAtProtectorsTurn = GameWithNoWerewolvesAtProtectorsTurn Game+ deriving (Eq, Show)++instance Arbitrary GameWithNoWerewolvesAtProtectorsTurn where+ arbitrary = do+ (GameAtProtectorsTurn game) <- arbitrary+ let werewolfNames = game ^.. players . werewolves . name+ let game' = foldr killPlayer game werewolfNames++ return $ GameWithNoWerewolvesAtProtectorsTurn game'+ newtype GameWithOneAllegianceAlive = GameWithOneAllegianceAlive Game deriving (Eq, Show) @@ -393,8 +425,8 @@ instance Arbitrary GameWithRoleModel where arbitrary = do- (GameAtWildChildsTurn game) <- arbitrary- (Blind command) <- arbitraryWildChildChooseCommand game+ (GameAtOrphansTurn game) <- arbitrary+ (Blind command) <- arbitraryOrphanChooseCommand game let game' = run_ (apply command) game return $ GameWithRoleModel game'@@ -439,7 +471,10 @@ ] FerinasGrunt -> return $ Blind noopCommand GameOver -> return $ Blind noopCommand+ HuntersTurn1 -> arbitraryHunterChooseCommand game+ HuntersTurn2 -> arbitraryHunterChooseCommand game Lynching -> return $ Blind noopCommand+ OrphansTurn -> arbitraryOrphanChooseCommand game ProtectorsTurn -> arbitraryProtectCommand game ScapegoatsTurn -> arbitraryScapegoatChooseCommand game SeersTurn -> arbitrarySeeCommand game@@ -447,7 +482,6 @@ Sunset -> return $ Blind noopCommand VillagesTurn -> arbitraryVillagerVoteCommand game WerewolvesTurn -> arbitraryWerewolfVoteCommand game- WildChildsTurn -> arbitraryWildChildChooseCommand game WitchsTurn -> oneof [ arbitraryHealCommand game , arbitraryWitchPassCommand game@@ -455,19 +489,26 @@ ] WolfHoundsTurn -> arbitraryWolfHoundChooseCommand game +arbitraryHunterChooseCommand :: Game -> Gen (Blind Command)+arbitraryHunterChooseCommand game = do+ let hunter = game ^?! players . hunters+ target <- arbitraryPlayer game++ return . Blind $ Hunter.chooseCommand (hunter ^. name) (target ^. name)++arbitraryOrphanChooseCommand :: Game -> Gen (Blind Command)+arbitraryOrphanChooseCommand game = do+ let orphan = game ^?! players . orphans+ target <- suchThat (arbitraryPlayer game) (orphan /=)++ return . Blind $ Orphan.chooseCommand (orphan ^. name) (target ^. name)+ arbitraryWolfHoundChooseCommand :: Game -> Gen (Blind Command) arbitraryWolfHoundChooseCommand game = do let wolfHoundsName = game ^?! players . wolfHounds . name allegianceName <- elements $ map (T.pack . show) [Villagers, Werewolves] return . Blind $ WolfHound.chooseCommand wolfHoundsName allegianceName--arbitraryWildChildChooseCommand :: Game -> Gen (Blind Command)-arbitraryWildChildChooseCommand game = do- let wildChild = game ^?! players . wildChildren- target <- suchThat (arbitraryPlayer game) (wildChild /=)-- return . Blind $ WildChild.chooseCommand (wildChild ^. name) (target ^. name) arbitraryScapegoatChooseCommand :: Game -> Gen (Blind Command) arbitraryScapegoatChooseCommand game = do
test/src/Game/Werewolf/Test/Command.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command ( -- * Tests allCommandTests,
test/src/Game/Werewolf/Test/Command/Choose.hs view
@@ -19,8 +19,9 @@ import qualified Data.Text as T import Game.Werewolf+import Game.Werewolf.Command.Hunter as Hunter+import Game.Werewolf.Command.Orphan as Orphan import Game.Werewolf.Command.Scapegoat as Scapegoat-import Game.Werewolf.Command.WildChild as WildChild import Game.Werewolf.Command.WolfHound as WolfHound import Game.Werewolf.Test.Arbitrary import Game.Werewolf.Test.Util@@ -30,23 +31,33 @@ allChooseCommandTests :: [TestTree] allChooseCommandTests =- [ testProperty "wolf-hound choose command errors when game is over" prop_wolfHoundChooseCommandErrorsWhenGameIsOver+ [ testProperty "hunter choose command errors when game is over" prop_hunterChooseCommandErrorsWhenGameIsOver+ , testProperty "hunter choose command errors when caller does not exist" prop_hunterChooseCommandErrorsWhenCallerDoesNotExist+ , testProperty "hunter choose command errors when any target does not exist" prop_hunterChooseCommandErrorsWhenTargetDoesNotExist+ , testProperty "hunter choose command errors when any target is dead" prop_hunterChooseCommandErrorsWhenTargetIsDead+ , testProperty "hunter choose command errors when not hunter's turn" prop_hunterChooseCommandErrorsWhenNotHuntersTurn+ , testProperty "hunter choose command errors when caller not hunter" prop_hunterChooseCommandErrorsWhenCallerNotHunter+ , testProperty "hunter choose command kills target" prop_hunterChooseCommandKillsTarget+ , testProperty "hunter choose command sets hunter retaliated" prop_hunterChooseCommandSetsHunterRetaliated++ , testProperty "orphan choose command errors when game is over" prop_orphanChooseCommandErrorsWhenGameIsOver+ , testProperty "orphan choose command errors when caller does not exist" prop_orphanChooseCommandErrorsWhenCallerDoesNotExist+ , testProperty "orphan choose command errors when target does not exist" prop_orphanChooseCommandErrorsWhenTargetDoesNotExist+ , testProperty "orphan choose command errors when caller is dead" prop_orphanChooseCommandErrorsWhenCallerIsDead+ , testProperty "orphan choose command errors when target is dead" prop_orphanChooseCommandErrorsWhenTargetIsDead+ , testProperty "orphan choose command errors when target is caller" prop_orphanChooseCommandErrorsWhenTargetIsCaller+ , testProperty "orphan choose command errors when not orphan's turn" prop_orphanChooseCommandErrorsWhenNotOrphansTurn+ , testProperty "orphan choose command errors when caller not orphan" prop_orphanChooseCommandErrorsWhenCallerNotOrphan+ , testProperty "orphan choose command sets role model" prop_orphanChooseCommandSetsRoleModel++ , testProperty "wolf-hound choose command errors when game is over" prop_wolfHoundChooseCommandErrorsWhenGameIsOver , testProperty "wolf-hound choose command errors when caller does not exist" prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist , testProperty "wolf-hound choose command errors when caller is dead" prop_wolfHoundChooseCommandErrorsWhenCallerIsDead , testProperty "wolf-hound choose command errors when not wolf-hound's turn" prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn , testProperty "wolf-hound choose command errors when caller not wolf-hound" prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound , testProperty "wolf-hound choose command errors when allegiance does not exist" prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist , testProperty "wolf-hound choose command sets allegiance chosen" prop_wolfHoundChooseCommandSetsAllegianceChosen-- , testProperty "wild-child choose command errors when game is over" prop_wildChildChooseCommandErrorsWhenGameIsOver- , testProperty "wild-child choose command errors when caller does not exist" prop_wildChildChooseCommandErrorsWhenCallerDoesNotExist- , testProperty "wild-child choose command errors when target does not exist" prop_wildChildChooseCommandErrorsWhenTargetDoesNotExist- , testProperty "wild-child choose command errors when caller is dead" prop_wildChildChooseCommandErrorsWhenCallerIsDead- , testProperty "wild-child choose command errors when target is dead" prop_wildChildChooseCommandErrorsWhenTargetIsDead- , testProperty "wild-child choose command errors when target is caller" prop_wildChildChooseCommandErrorsWhenTargetIsCaller- , testProperty "wild-child choose command errors when not wild-child's turn" prop_wildChildChooseCommandErrorsWhenNotWildChildsTurn- , testProperty "wild-child choose command errors when caller not wild-child" prop_wildChildChooseCommandErrorsWhenCallerNotWildChild- , testProperty "wild-child choose command sets role model" prop_wildChildChooseCommandSetsRoleModel+ , testProperty "wolf-hound choose command sets allegiance" prop_wolfHoundChooseCommandSetsAllegiance , testProperty "scapegoat choose command errors when game is over" prop_scapegoatChooseCommandErrorsWhenGameIsOver , testProperty "scapegoat choose command errors when caller does not exist" prop_scapegoatChooseCommandErrorsWhenCallerDoesNotExist@@ -58,124 +69,194 @@ , testProperty "scapegoat choose command resets scapegoat blamed" prop_scapegoatChooseCommandResetsScapegoatBlamed ] -prop_wolfHoundChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property-prop_wolfHoundChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =- forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind+prop_hunterChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property+prop_hunterChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =+ forAll (arbitraryHunterChooseCommand game) $ verbose_runCommandErrors game . getBlind -prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist :: GameAtWolfHoundsTurn -> Player -> Allegiance -> Property-prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist (GameAtWolfHoundsTurn game) caller allegiance = do- let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance)+prop_hunterChooseCommandErrorsWhenCallerDoesNotExist :: GameAtHuntersTurn -> Player -> Property+prop_hunterChooseCommandErrorsWhenCallerDoesNotExist (GameAtHuntersTurn game) caller =+ forAll (arbitraryPlayer game) $ \target -> do+ let command = Hunter.chooseCommand (caller ^. name) (target ^. name) - not (doesPlayerExist (caller ^. name) game)+ not (doesPlayerExist (caller ^. name) game)+ ==> verbose_runCommandErrors game command++prop_hunterChooseCommandErrorsWhenTargetDoesNotExist :: GameAtHuntersTurn -> Player -> Property+prop_hunterChooseCommandErrorsWhenTargetDoesNotExist (GameAtHuntersTurn game) target = do+ let hunter = game ^?! players . hunters+ let command = Hunter.chooseCommand (hunter ^. name) (target ^. name)++ not (doesPlayerExist (target ^. name) game) ==> verbose_runCommandErrors game command -prop_wolfHoundChooseCommandErrorsWhenCallerIsDead :: GameAtWolfHoundsTurn -> Allegiance -> Property-prop_wolfHoundChooseCommandErrorsWhenCallerIsDead (GameAtWolfHoundsTurn game) allegiance = do- let wolfHound = game ^?! players . wolfHounds- let game' = killPlayer (wolfHound ^. name) game- let command = WolfHound.chooseCommand (wolfHound ^. name) (T.pack $ show allegiance)+prop_hunterChooseCommandErrorsWhenTargetIsDead :: GameAtHuntersTurn -> Property+prop_hunterChooseCommandErrorsWhenTargetIsDead (GameAtHuntersTurn game) = do+ let hunter = game ^?! players . hunters - verbose_runCommandErrors game' command+ forAll (arbitraryPlayer game) $ \target -> do+ let game' = killPlayer (target ^. name) game+ let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) -prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn :: Game -> Property-prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn game =- hasn't (stage . _WolfHoundsTurn) game- ==> forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind+ verbose_runCommandErrors game' command -prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound :: GameAtWolfHoundsTurn -> Allegiance -> Property-prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound (GameAtWolfHoundsTurn game) allegiance =- forAll (suchThat (arbitraryPlayer game) (isn't wolfHound)) $ \caller -> do- let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance)+prop_hunterChooseCommandErrorsWhenNotHuntersTurn :: Game -> Property+prop_hunterChooseCommandErrorsWhenNotHuntersTurn game =+ hasn't (stage . _HuntersTurn1) game && hasn't (stage . _HuntersTurn2) game+ ==> forAll (arbitraryHunterChooseCommand game) $ verbose_runCommandErrors game . getBlind +prop_hunterChooseCommandErrorsWhenCallerNotHunter :: GameAtHuntersTurn -> Property+prop_hunterChooseCommandErrorsWhenCallerNotHunter (GameAtHuntersTurn game) =+ forAll (suchThat (arbitraryPlayer game) (isn't hunter)) $ \caller ->+ forAll (arbitraryPlayer game) $ \target -> do+ let command = Hunter.chooseCommand (caller ^. name) (target ^. name)+ verbose_runCommandErrors game command -prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist :: GameAtWolfHoundsTurn -> Text -> Property-prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist (GameAtWolfHoundsTurn game) allegiance = do- let wolfHound = game ^?! players . wolfHounds- let command = WolfHound.chooseCommand (wolfHound ^. name) allegiance+prop_hunterChooseCommandKillsTarget :: GameAtHuntersTurn -> Property+prop_hunterChooseCommandKillsTarget (GameAtHuntersTurn game) = do+ let hunter = game ^?! players . hunters - allegiance `notElem` ["Villagers", "Werewolves"]- ==> verbose_runCommandErrors game command+ forAll (arbitraryPlayer game) $ \target -> do+ let command = Hunter.chooseCommand (hunter ^. name) (target ^. name)+ let game' = run_ (apply command) game -prop_wolfHoundChooseCommandSetsAllegianceChosen :: GameAtWolfHoundsTurn -> Property-prop_wolfHoundChooseCommandSetsAllegianceChosen (GameAtWolfHoundsTurn game) = do- let wolfHoundsName = game ^?! players . wolfHounds . name+ is dead $ game' ^?! players . traverse . filteredBy name (target ^. name) - forAll (elements [Villagers, Werewolves]) $ \allegiance' -> do- let command = WolfHound.chooseCommand wolfHoundsName (T.pack $ show allegiance')+prop_hunterChooseCommandSetsHunterRetaliated :: GameAtHuntersTurn -> Property+prop_hunterChooseCommandSetsHunterRetaliated (GameAtHuntersTurn game) = do+ let hunter = game ^?! players . hunters++ forAll (arbitraryPlayer game) $ \target -> do+ let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) let game' = run_ (apply command) game - fromJust (game' ^. allegianceChosen) === allegiance'+ game' ^. hunterRetaliated -prop_wildChildChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property-prop_wildChildChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =- forAll (arbitraryWildChildChooseCommand game) $ verbose_runCommandErrors game . getBlind+prop_orphanChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property+prop_orphanChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =+ forAll (arbitraryOrphanChooseCommand game) $ verbose_runCommandErrors game . getBlind -prop_wildChildChooseCommandErrorsWhenCallerDoesNotExist :: GameAtWildChildsTurn -> Player -> Property-prop_wildChildChooseCommandErrorsWhenCallerDoesNotExist (GameAtWildChildsTurn game) caller =+prop_orphanChooseCommandErrorsWhenCallerDoesNotExist :: GameAtOrphansTurn -> Player -> Property+prop_orphanChooseCommandErrorsWhenCallerDoesNotExist (GameAtOrphansTurn game) caller = forAll (arbitraryPlayer game) $ \target -> do- let command = WildChild.chooseCommand (caller ^. name) (target ^. name)+ let command = Orphan.chooseCommand (caller ^. name) (target ^. name) not (doesPlayerExist (caller ^. name) game) ==> verbose_runCommandErrors game command -prop_wildChildChooseCommandErrorsWhenTargetDoesNotExist :: GameAtWildChildsTurn -> Player -> Property-prop_wildChildChooseCommandErrorsWhenTargetDoesNotExist (GameAtWildChildsTurn game) target = do- let wildChild = game ^?! players . wildChildren- let command = WildChild.chooseCommand (wildChild ^. name) (target ^. name)+prop_orphanChooseCommandErrorsWhenTargetDoesNotExist :: GameAtOrphansTurn -> Player -> Property+prop_orphanChooseCommandErrorsWhenTargetDoesNotExist (GameAtOrphansTurn game) target = do+ let orphan = game ^?! players . orphans+ let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) not (doesPlayerExist (target ^. name) game) ==> verbose_runCommandErrors game command -prop_wildChildChooseCommandErrorsWhenCallerIsDead :: GameAtWildChildsTurn -> Property-prop_wildChildChooseCommandErrorsWhenCallerIsDead (GameAtWildChildsTurn game) = do- let wildChild = game ^?! players . wildChildren- let game' = killPlayer (wildChild ^. name) game+prop_orphanChooseCommandErrorsWhenCallerIsDead :: GameAtOrphansTurn -> Property+prop_orphanChooseCommandErrorsWhenCallerIsDead (GameAtOrphansTurn game) = do+ let orphan = game ^?! players . orphans+ let game' = killPlayer (orphan ^. name) game forAll (arbitraryPlayer game') $ \target -> do- let command = WildChild.chooseCommand (wildChild ^. name) (target ^. name)+ let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) verbose_runCommandErrors game' command -prop_wildChildChooseCommandErrorsWhenTargetIsDead :: GameAtWildChildsTurn -> Property-prop_wildChildChooseCommandErrorsWhenTargetIsDead (GameAtWildChildsTurn game) = do- let wildChild = game ^?! players . wildChildren+prop_orphanChooseCommandErrorsWhenTargetIsDead :: GameAtOrphansTurn -> Property+prop_orphanChooseCommandErrorsWhenTargetIsDead (GameAtOrphansTurn game) = do+ let orphan = game ^?! players . orphans forAll (arbitraryPlayer game) $ \target -> do let game' = killPlayer (target ^. name) game- let command = WildChild.chooseCommand (wildChild ^. name) (target ^. name)+ let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) verbose_runCommandErrors game' command -prop_wildChildChooseCommandErrorsWhenTargetIsCaller :: GameAtWildChildsTurn -> Property-prop_wildChildChooseCommandErrorsWhenTargetIsCaller (GameAtWildChildsTurn game) = do- let wildChild = game ^?! players . wildChildren- let command = WildChild.chooseCommand (wildChild ^. name) (wildChild ^. name)+prop_orphanChooseCommandErrorsWhenTargetIsCaller :: GameAtOrphansTurn -> Property+prop_orphanChooseCommandErrorsWhenTargetIsCaller (GameAtOrphansTurn game) = do+ let orphan = game ^?! players . orphans+ let command = Orphan.chooseCommand (orphan ^. name) (orphan ^. name) verbose_runCommandErrors game command -prop_wildChildChooseCommandErrorsWhenNotWildChildsTurn :: Game -> Property-prop_wildChildChooseCommandErrorsWhenNotWildChildsTurn game =- hasn't (stage . _WildChildsTurn) game- ==> forAll (arbitraryWildChildChooseCommand game) $ verbose_runCommandErrors game . getBlind+prop_orphanChooseCommandErrorsWhenNotOrphansTurn :: Game -> Property+prop_orphanChooseCommandErrorsWhenNotOrphansTurn game =+ hasn't (stage . _OrphansTurn) game+ ==> forAll (arbitraryOrphanChooseCommand game) $ verbose_runCommandErrors game . getBlind -prop_wildChildChooseCommandErrorsWhenCallerNotWildChild :: GameAtWildChildsTurn -> Property-prop_wildChildChooseCommandErrorsWhenCallerNotWildChild (GameAtWildChildsTurn game) =- forAll (suchThat (arbitraryPlayer game) (isn't wildChild)) $ \caller ->+prop_orphanChooseCommandErrorsWhenCallerNotOrphan :: GameAtOrphansTurn -> Property+prop_orphanChooseCommandErrorsWhenCallerNotOrphan (GameAtOrphansTurn game) =+ forAll (suchThat (arbitraryPlayer game) (isn't orphan)) $ \caller -> forAll (arbitraryPlayer game) $ \target -> do- let command = WildChild.chooseCommand (caller ^. name) (target ^. name)+ let command = Orphan.chooseCommand (caller ^. name) (target ^. name) verbose_runCommandErrors game command -prop_wildChildChooseCommandSetsRoleModel :: GameAtWildChildsTurn -> Property-prop_wildChildChooseCommandSetsRoleModel (GameAtWildChildsTurn game) = do- let wildChild = game ^?! players . wildChildren+prop_orphanChooseCommandSetsRoleModel :: GameAtOrphansTurn -> Property+prop_orphanChooseCommandSetsRoleModel (GameAtOrphansTurn game) = do+ let orphan = game ^?! players . orphans - forAll (suchThat (arbitraryPlayer game) (wildChild /=)) $ \target -> do- let command = WildChild.chooseCommand (wildChild ^. name) (target ^. name)+ forAll (suchThat (arbitraryPlayer game) (orphan /=)) $ \target -> do+ let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) let game' = run_ (apply command) game fromJust (game' ^. roleModel) === target ^. name++prop_wolfHoundChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property+prop_wolfHoundChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =+ forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind++prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist :: GameAtWolfHoundsTurn -> Player -> Allegiance -> Property+prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist (GameAtWolfHoundsTurn game) caller allegiance = do+ let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance)++ not (doesPlayerExist (caller ^. name) game)+ ==> verbose_runCommandErrors game command++prop_wolfHoundChooseCommandErrorsWhenCallerIsDead :: GameAtWolfHoundsTurn -> Allegiance -> Property+prop_wolfHoundChooseCommandErrorsWhenCallerIsDead (GameAtWolfHoundsTurn game) allegiance = do+ let wolfHound = game ^?! players . wolfHounds+ let game' = killPlayer (wolfHound ^. name) game+ let command = WolfHound.chooseCommand (wolfHound ^. name) (T.pack $ show allegiance)++ verbose_runCommandErrors game' command++prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn :: Game -> Property+prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn game =+ hasn't (stage . _WolfHoundsTurn) game+ ==> forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind++prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound :: GameAtWolfHoundsTurn -> Allegiance -> Property+prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound (GameAtWolfHoundsTurn game) allegiance =+ forAll (suchThat (arbitraryPlayer game) (isn't wolfHound)) $ \caller -> do+ let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance)++ verbose_runCommandErrors game command++prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist :: GameAtWolfHoundsTurn -> Text -> Property+prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist (GameAtWolfHoundsTurn game) allegiance = do+ let wolfHound = game ^?! players . wolfHounds+ let command = WolfHound.chooseCommand (wolfHound ^. name) allegiance++ allegiance `notElem` ["Villagers", "Werewolves"]+ ==> verbose_runCommandErrors game command++prop_wolfHoundChooseCommandSetsAllegianceChosen :: GameAtWolfHoundsTurn -> Property+prop_wolfHoundChooseCommandSetsAllegianceChosen (GameAtWolfHoundsTurn game) =+ forAll (arbitraryWolfHoundChooseCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command) game++ game' ^. allegianceChosen++prop_wolfHoundChooseCommandSetsAllegiance :: GameAtWolfHoundsTurn -> Property+prop_wolfHoundChooseCommandSetsAllegiance (GameAtWolfHoundsTurn game) = do+ let wolfHoundsName = game ^?! players . wolfHounds . name++ forAll (elements [Villagers, Werewolves]) $ \allegiance' -> do+ let command = WolfHound.chooseCommand wolfHoundsName (T.pack $ show allegiance')+ let game' = run_ (apply command) game++ game' ^?! players . wolfHounds . role . allegiance === allegiance' prop_scapegoatChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_scapegoatChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) =
test/src/Game/Werewolf/Test/Command/Heal.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Heal ( -- * Tests allHealCommandTests,
test/src/Game/Werewolf/Test/Command/Pass.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Pass ( -- * Tests allPassCommandTests,@@ -29,13 +27,13 @@ , testProperty "devoted servant pass command errors when caller does not exist" prop_devotedServantPassCommandErrorsWhenCallerDoesNotExist , testProperty "devoted servant pass command errors when caller is dead" prop_devotedServantPassCommandErrorsWhenCallerIsDead , testProperty "devoted servant pass command errors when not devoted servant's turn" prop_devotedServantPassCommandErrorsWhenNotDevotedServantsTurn- , testProperty "devoted servant pass command updates passes" prop_devotedServantPassCommandUpdatesPasses+ , testProperty "devoted servant pass command sets passed" prop_devotedServantPassCommandSetsPassed , testProperty "witch pass command errors when game is over" prop_witchPassCommandErrorsWhenGameIsOver , testProperty "witch pass command errors when caller does not exist" prop_witchPassCommandErrorsWhenCallerDoesNotExist , testProperty "witch pass command errors when caller is dead" prop_witchPassCommandErrorsWhenCallerIsDead , testProperty "witch pass command errors when not witch's turn" prop_witchPassCommandErrorsWhenNotWitchsTurn- , testProperty "witch pass command updates passes" prop_witchPassCommandUpdatesPasses+ , testProperty "witch pass command sets passed" prop_witchPassCommandSetsPassed ] prop_devotedServantPassCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property@@ -60,12 +58,12 @@ hasn't (stage . _DevotedServantsTurn) game ==> forAll (arbitraryDevotedServantPassCommand game) $ verbose_runCommandErrors game . getBlind -prop_devotedServantPassCommandUpdatesPasses :: GameAtDevotedServantsTurn -> Property-prop_devotedServantPassCommandUpdatesPasses (GameAtDevotedServantsTurn game) =+prop_devotedServantPassCommandSetsPassed :: GameAtDevotedServantsTurn -> Property+prop_devotedServantPassCommandSetsPassed (GameAtDevotedServantsTurn game) = forAll (arbitraryDevotedServantPassCommand game) $ \(Blind command) -> do let game' = run_ (apply command) game - length (game' ^. passes) == 1+ game' ^. passed prop_witchPassCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_witchPassCommandErrorsWhenGameIsOver (GameAtGameOver game) =@@ -89,9 +87,9 @@ hasn't (stage . _WitchsTurn) game ==> forAll (arbitraryWitchPassCommand game) $ verbose_runCommandErrors game . getBlind -prop_witchPassCommandUpdatesPasses :: GameAtWitchsTurn -> Property-prop_witchPassCommandUpdatesPasses (GameAtWitchsTurn game) =+prop_witchPassCommandSetsPassed :: GameAtWitchsTurn -> Property+prop_witchPassCommandSetsPassed (GameAtWitchsTurn game) = forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do let game' = run_ (apply command) game - length (game' ^. passes) == 1+ game' ^. passed
test/src/Game/Werewolf/Test/Command/Poison.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Poison ( -- * Tests allPoisonCommandTests,
test/src/Game/Werewolf/Test/Command/Protect.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Protect ( -- * Tests allProtectCommandTests,
test/src/Game/Werewolf/Test/Command/Quit.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Quit ( -- * Tests allQuitCommandTests,@@ -39,7 +37,7 @@ , testProperty "quit command clears protect when caller is protector" prop_quitCommandClearsProtectWhenCallerIsProtector , testProperty "quit command clears player's devour vote" prop_quitCommandClearsPlayersDevourVote , testProperty "quit command clears player's lynch vote" prop_quitCommandClearsPlayersLynchVote- , testProperty "quit command clears role model when caller is wild-child" prop_quitCommandClearsRoleModelWhenCallerIsWildChild+ , testProperty "quit command clears role model when caller is orphan" prop_quitCommandClearsRoleModelWhenCallerIsOrphan , testProperty "quit command sets angel's allegiance when caller is angel" prop_quitCommandSetsAngelsAllegianceWhenCallerIsAngel ] @@ -73,7 +71,7 @@ let wolfHoundsName = game ^?! players . wolfHounds . name let command = quitCommand wolfHoundsName - isNothing $ run_ (apply command) game ^. allegianceChosen+ run_ (apply command) game ^. allegianceChosen prop_quitCommandClearsHealWhenCallerIsWitch :: GameWithHeal -> Bool prop_quitCommandClearsHealWhenCallerIsWitch (GameWithHeal game) = do@@ -131,10 +129,10 @@ isNothing $ run_ (apply command) game ^. votes . at (caller ^. name) -prop_quitCommandClearsRoleModelWhenCallerIsWildChild :: GameWithRoleModel -> Bool-prop_quitCommandClearsRoleModelWhenCallerIsWildChild (GameWithRoleModel game) = do- let wildChild = game ^?! players . wildChildren- let command = quitCommand (wildChild ^. name)+prop_quitCommandClearsRoleModelWhenCallerIsOrphan :: GameWithRoleModel -> Bool+prop_quitCommandClearsRoleModelWhenCallerIsOrphan (GameWithRoleModel game) = do+ let orphan = game ^?! players . orphans+ let command = quitCommand (orphan ^. name) isNothing $ run_ (apply command) game ^. roleModel
test/src/Game/Werewolf/Test/Command/Reveal.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Reveal ( -- * Tests allRevealCommandTests,@@ -34,7 +32,7 @@ , testProperty "reveal command sets caller's role" prop_revealCommandSetsCallersRole , testProperty "reveal command sets target's role" prop_revealCommandSetsTargetsRole , testProperty "reveal command resets role when jester" prop_revealCommandResetsRoleWhenJester- , testProperty "reveal command resets role when wild-child" prop_revealCommandResetsRoleWhenWildChild+ , testProperty "reveal command resets role when orphan" prop_revealCommandResetsRoleWhenOrphan , testProperty "reveal command resets role when witch" prop_revealCommandResetsRoleWhenWitch , testProperty "reveal command resets role when wolf-hound" prop_revealCommandResetsRoleWhenWolfHound ]@@ -101,8 +99,8 @@ targetsName = head (getVoteResult game) ^. name game' = game & players . traverse . filteredBy name targetsName . role .~ jesterRole & jesterRevealed .~ True -prop_revealCommandResetsRoleWhenWildChild :: GameAtDevotedServantsTurn -> Bool-prop_revealCommandResetsRoleWhenWildChild (GameAtDevotedServantsTurn game) = do+prop_revealCommandResetsRoleWhenOrphan :: GameAtDevotedServantsTurn -> Bool+prop_revealCommandResetsRoleWhenOrphan (GameAtDevotedServantsTurn game) = do let devotedServantsName = game ^?! players . devotedServants . name let command = revealCommand devotedServantsName let game'' = run_ (apply command) game'@@ -110,7 +108,7 @@ isNothing $ game'' ^. roleModel where targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ wildChildRole & roleModel .~ Just targetsName+ game' = game & players . traverse . filteredBy name targetsName . role .~ orphanRole & roleModel .~ Just targetsName prop_revealCommandResetsRoleWhenWitch :: GameAtDevotedServantsTurn -> Bool prop_revealCommandResetsRoleWhenWitch (GameAtDevotedServantsTurn game) = do@@ -129,7 +127,7 @@ let command = revealCommand devotedServantsName let game'' = run_ (apply command) game' - isNothing $ game'' ^. allegianceChosen+ not $ game'' ^. allegianceChosen where targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ wolfHoundRole & allegianceChosen .~ Just Villagers+ game' = game & players . traverse . filteredBy name targetsName . role .~ wolfHoundRole & allegianceChosen .~ True
test/src/Game/Werewolf/Test/Command/See.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.See ( -- * Tests allSeeCommandTests,
test/src/Game/Werewolf/Test/Command/Vote.hs view
@@ -5,8 +5,6 @@ Maintainer : public@hjwylde.com -} -{-# LANGUAGE OverloadedStrings #-}- module Game.Werewolf.Test.Command.Vote ( -- * Tests allVoteCommandTests,
test/src/Game/Werewolf/Test/Engine.hs view
@@ -16,16 +16,23 @@ import Control.Monad.Except import Control.Monad.Writer -import Data.Either.Extra-import Data.List.Extra-import qualified Data.Map as Map-import Data.Maybe+import Data.Either.Extra+import Data.List.Extra import Game.Werewolf-import Game.Werewolf.Command.DevotedServant-import Game.Werewolf.Command.Global-import Game.Werewolf.Command.Villager import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Engine.Angel+import Game.Werewolf.Test.Engine.DevotedServant+import Game.Werewolf.Test.Engine.Hunter+import Game.Werewolf.Test.Engine.Lynching+import Game.Werewolf.Test.Engine.Orphan+import Game.Werewolf.Test.Engine.Protector+import Game.Werewolf.Test.Engine.Scapegoat+import Game.Werewolf.Test.Engine.Seer+import Game.Werewolf.Test.Engine.Village+import Game.Werewolf.Test.Engine.Werewolf+import Game.Werewolf.Test.Engine.Witch+import Game.Werewolf.Test.Engine.WolfHound import Game.Werewolf.Test.Util import Prelude hiding (round)@@ -35,428 +42,39 @@ import Test.Tasty.QuickCheck allEngineTests :: [TestTree]-allEngineTests =- [ testProperty "check stage skips devoted servant's turn when no devoted servant" prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant- , testProperty "check stage skips protector's turn when no protector" prop_checkStageSkipsProtectorsTurnWhenNoProtector- , testProperty "check stage skips scapegoat's turn when no scapegoat" prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat- , testProperty "check stage skips seer's turn when no seer" prop_checkStageSkipsSeersTurnWhenNoSeer- , testProperty "check stage skips village's turn when allowed voters empty" prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty- , testProperty "check stage skips wild-child's turn when no wild-child" prop_checkStageSkipsWildChildsTurnWhenNoWildChild- , testProperty "check stage skips witch's turn when no witch" prop_checkStageSkipsWitchsTurnWhenNoWitch- , testProperty "check stage skips wolf-hound's turn when no wolf-hound" prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound-- , testProperty "check devoted servant's turn advances to wolf-hound's turn" prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn- , testProperty "check devoted servant's turn advances when no devoted servant" prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant- , testProperty "check devoted servant's turn does nothing unless revealed or passed" prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed+allEngineTests = concat+ [ allAngelEngineTests+ , allDevotedServantEngineTests+ , allHunterEngineTests+ , allLynchingEngineTests+ , allOrphanEngineTests+ , allProtectorEngineTests+ , allScapegoatEngineTests+ , allSeerEngineTests+ , allVillageEngineTests+ , allWerewolfEngineTests+ , allWitchEngineTests+ , allWolfHoundEngineTests - , testProperty "check lynching lynches one player when consensus" prop_checkLynchingLynchesOnePlayerWhenConsensus- , testProperty "check lynching lynches no one when target is jester" prop_checkLynchingLynchesNoOneWhenTargetIsJester- , testProperty "check lynching lynches scapegoat when conflicted" prop_checkLynchingLynchesScapegoatWhenConflicted- , testProperty "check lynching lynches no one when conflicted and no scapegoats" prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats- , testProperty "check lynching resets votes" prop_checkLynchingResetsVotes- , testProperty "check lynching sets allowed voters" prop_checkLynchingSetsAllowedVoters+ , allGameOverTests+ , allStartGameTests+ ] - , testProperty "check game over advances stage when one allegiance alive" prop_checkGameOverAdvancesStageWhenOneAllegianceAlive- -- TODO (hjw): pending- --, testProperty "check game over does nothing when at least two allegiances alive" prop_checkGameOverDoesNothingWhenAtLeastTwoAllegiancesAlive+allGameOverTests :: [TestTree]+allGameOverTests =+ [ testProperty "check game over advances stage when one allegiance alive" prop_checkGameOverAdvancesStageWhenOneAllegianceAlive , testProperty "check game over advances stage when after first round and angel dead" prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndAngelDead , testProperty "check game over does nothing when angel dead but aligned with villagers" prop_checkGameOverDoesNothingWhenAngelDeadButAlignedWithVillagers , testProperty "check game over does nothing when game over" prop_checkGameOverDoesNothingWhenGameOver-- , testProperty "check protector's turn advances to werewolves' turn" prop_checkProtectorsTurnAdvancesToWerewolvesTurn- , testProperty "check protector's turn advances when no protector" prop_checkProtectorsTurnAdvancesWhenNoProtector- , testProperty "check protector's turn does nothing unless protected" prop_checkProtectorsTurnDoesNothingUnlessProtected-- , testProperty "check scapegoat's turn advances to wolf-hound's turn" prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn- , testProperty "check scapegoat's turn skips wolf-hound's turn when allegiance chosen" prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen- , testProperty "check scapegoat's turn does nothing while scapegoat blamed" prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed-- , testProperty "check seer's turn advances to wild-child's turn" prop_checkSeersTurnAdvancesToWildChildsTurn- , testProperty "check seer's turn advances when no seer" prop_checkSeersTurnAdvancesWhenNoSeer- , testProperty "check seer's turn resets sees" prop_checkSeersTurnResetsSee- , testProperty "check seer's turn does nothing unless seen" prop_checkSeersTurnDoesNothingUnlessSeen-- , testProperty "check sunrise increments round" prop_checkSunriseIncrementsRound- , testProperty "check sunrise sets angel's allegiance" prop_checkSunriseSetsAngelsAllegiance-- , testProperty "check sunset sets wild-child's allegiance when role model dead" prop_checkSunsetSetsWildChildsAllegianceWhenRoleModelDead-- , testProperty "check villages' turn advances to devoted servant's turn" prop_checkVillagesTurnAdvancesToDevotedServantsTurn- , testProperty "check villages' turn skips devoted servant's turn when conflicted" prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted- , testProperty "check villages' turn does nothing unless all voted" prop_checkVillagesTurnDoesNothingUnlessAllVoted-- , testProperty "check werewolves' turn advances to witch's turn" prop_checkWerewolvesTurnAdvancesToWitchsTurn- , testProperty "check werewolves' turn skips witch's turn when healed and poisoned" prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned- , testProperty "check werewolves' turn kills one player when consensus" prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus- , testProperty "check werewolves' turn kills no one when conflicted" prop_checkWerewolvesTurnKillsNoOneWhenConflicted- , testProperty "check werewolves' turn kills no one when target defended" prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended- , testProperty "check werewolves' turn resets protect" prop_checkWerewolvesTurnResetsProtect- , testProperty "check werewolves' turn resets votes" prop_checkWerewolvesTurnResetsVotes- , testProperty "check werewolves' turn does nothing unless all voted" prop_checkWerewolvesTurnDoesNothingUnlessAllVoted-- , testProperty "check wild-child's turn advances to protector's turn" prop_checkWildChildsTurnAdvancesToProtectorsTurn- , testProperty "check wild-child's turn advances when no wild-child" prop_checkWildChildsTurnAdvancesWhenNoWildChild- , testProperty "check wild-child's turn does nothing unless chosen" prop_checkWildChildsTurnDoesNothingUnlessRoleModelChosen-- , testProperty "check witch's turn advances to villages' turn" prop_checkWitchsTurnAdvancesToVillagesTurn- , testProperty "check witch's turn advances when no witch" prop_checkWitchsTurnAdvancesWhenNoWitch- , testProperty "check witch's turn heals devouree when healed" prop_checkWitchsTurnHealsDevoureeWhenHealed- , testProperty "check witch's turn kills one player when poisoned" prop_checkWitchsTurnKillsOnePlayerWhenPoisoned- , testProperty "check witch's turn does nothing when passed" prop_checkWitchsTurnDoesNothingWhenPassed- , testProperty "check witch's turn does nothing unless actioned or passed" prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed- , testProperty "check witch's turn resets heal" prop_checkWitchsTurnResetsHeal- , testProperty "check witch's turn resets poison" prop_checkWitchsTurnResetsPoison- , testProperty "check witch's turn clears passes" prop_checkWitchsTurnClearsPasses-- , testProperty "check wolf-hound's turn advances to seer's turn" prop_checkWolfHoundsTurnAdvancesToSeersTurn- , testProperty "check wolf-hound's turn advances when no wolf-hound" prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound- , testProperty "check wolf-hound's turn sets wolf-hound's allegiance" prop_checkWolfHoundsTurnSetsWolfHoundsAllegiance- , testProperty "check wolf-hound's turn does nothing unless allegiance chosen" prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen+ ] - , testProperty "start game uses given players" prop_startGameUsesGivenPlayers+allStartGameTests :: [TestTree]+allStartGameTests =+ [ testProperty "start game uses given players" prop_startGameUsesGivenPlayers , testProperty "start game errors unless unique player names" prop_startGameErrorsUnlessUniquePlayerNames , testProperty "start game errors when less than 7 players" prop_startGameErrorsWhenLessThan7Players , testProperty "start game errors when more than 1 of a restricted role" prop_startGameErrorsWhenMoreThan1OfARestrictedRole ]--prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant :: GameWithMajorityVote -> Bool-prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant (GameWithMajorityVote game) =- hasn't (stage . _DevotedServantsTurn) game'- where- devotedServantsName = game ^?! players . devotedServants . name- game' = run_ (apply (quitCommand devotedServantsName) >> checkStage) game--prop_checkStageSkipsProtectorsTurnWhenNoProtector :: GameWithRoleModel -> Bool-prop_checkStageSkipsProtectorsTurnWhenNoProtector (GameWithRoleModel game) =- hasn't (stage . _ProtectorsTurn) game'- where- protectorsName = game ^?! players . protectors . name- game' = run_ (apply (quitCommand protectorsName) >> checkStage) game--prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat :: GameWithConflictingVote -> Bool-prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat (GameWithConflictingVote game) =- hasn't (stage . _ScapegoatsTurn) game'- where- scapegoatsName = game ^?! players . scapegoats . name- game' = run_ (apply (quitCommand scapegoatsName) >> checkStage) game--prop_checkStageSkipsSeersTurnWhenNoSeer :: GameWithPassAtDevotedServantsTurn -> Bool-prop_checkStageSkipsSeersTurnWhenNoSeer (GameWithPassAtDevotedServantsTurn game) =- hasn't (stage . _SeersTurn) game'- where- seersName = game ^?! players . seers . name- game' = run_ (apply (quitCommand seersName) >> checkStage) game--prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty :: GameAtWitchsTurn -> Property-prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game') $ \(Blind passWitchsTurnCommand) -> do- hasn't (stage . _VillagesTurn) (run_ (apply passWitchsTurnCommand >> checkStage) game')- where- game' = game & allowedVoters .~ []--prop_checkStageSkipsWildChildsTurnWhenNoWildChild :: GameWithSee -> Bool-prop_checkStageSkipsWildChildsTurnWhenNoWildChild (GameWithSee game) =- hasn't (stage . _WildChildsTurn) game'- where- wildChildsName = game ^?! players . wildChildren . name- game' = run_ (apply (quitCommand wildChildsName) >> checkStage) game--prop_checkStageSkipsWitchsTurnWhenNoWitch :: GameWithDevourVotes -> Property-prop_checkStageSkipsWitchsTurnWhenNoWitch (GameWithDevourVotes game) =- null (run_ checkStage game' ^.. players . angels . dead)- ==> hasn't (stage . _WitchsTurn) game'- where- witchsName = game ^?! players . witches . name- game' = run_ (apply (quitCommand witchsName) >> checkStage) game--prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound :: GameWithProtect -> Bool-prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound (GameWithProtect game) =- hasn't (stage . _WolfHoundsTurn) game'- where- wolfHoundsName = game ^?! players . wolfHounds . name- game' = run_ (apply (quitCommand wolfHoundsName) >> checkStage) game--prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn :: GameAtDevotedServantsTurn -> Property-prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn (GameAtDevotedServantsTurn game) = do- forAll (arbitraryCommand game) $ \(Blind command) ->- isn't angel target && isn't wolfHound target- ==> has (stage . _WolfHoundsTurn) (run_ (apply command >> checkStage) game)- where- target = head $ getVoteResult game--prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant :: GameAtDevotedServantsTurn -> Bool-prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = quitCommand devotedServantsName-- hasn't (stage . _DevotedServantsTurn) (run_ (apply command >> checkStage) game)--prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed :: GameAtDevotedServantsTurn -> Bool-prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed (GameAtDevotedServantsTurn game) =- has (stage . _DevotedServantsTurn) (run_ checkStage game)--prop_checkLynchingLynchesOnePlayerWhenConsensus :: GameWithPassAtDevotedServantsTurn -> Property-prop_checkLynchingLynchesOnePlayerWhenConsensus (GameWithPassAtDevotedServantsTurn game) =- isn't jester target- ==> length (run_ checkStage game ^.. players . traverse . dead) == 1- where- target = head $ getVoteResult game--prop_checkLynchingLynchesNoOneWhenTargetIsJester :: GameAtVillagesTurn -> Bool-prop_checkLynchingLynchesNoOneWhenTargetIsJester (GameAtVillagesTurn game) = do- let game' = foldr (\player -> run_ (apply $ voteCommand (player ^. name) (jester ^. name))) game (game ^. players)-- none (is dead) (run_ checkStage game' ^. players)- where- jester = game ^?! players . jesters--prop_checkLynchingLynchesScapegoatWhenConflicted :: GameAtScapegoatsTurn -> Bool-prop_checkLynchingLynchesScapegoatWhenConflicted (GameAtScapegoatsTurn game) =- is dead $ run_ checkStage game ^?! players . scapegoats--prop_checkLynchingResetsVotes :: GameWithPassAtDevotedServantsTurn -> Property-prop_checkLynchingResetsVotes (GameWithPassAtDevotedServantsTurn game) =- isn't devotedServant target- ==> Map.null $ run_ checkStage game ^. votes- where- target = head $ getVoteResult game--prop_checkLynchingSetsAllowedVoters :: GameWithLynchVotes -> Property-prop_checkLynchingSetsAllowedVoters (GameWithLynchVotes game) =- game' ^. allowedVoters === expectedAllowedVoters ^.. names- where- game' = run_ checkStage game- expectedAllowedVoters- | game' ^. jesterRevealed = filter (isn't jester) $ game' ^. players- | otherwise = game' ^.. players . traverse . alive--prop_checkProtectorsTurnAdvancesToWerewolvesTurn :: GameWithProtect -> Bool-prop_checkProtectorsTurnAdvancesToWerewolvesTurn (GameWithProtect game) =- has (stage . _WerewolvesTurn) (run_ checkStage game)--prop_checkProtectorsTurnAdvancesWhenNoProtector :: GameAtProtectorsTurn -> Bool-prop_checkProtectorsTurnAdvancesWhenNoProtector (GameAtProtectorsTurn game) = do- let protector = game ^?! players . protectors- let command = quitCommand $ protector ^. name-- hasn't (stage . _ProtectorsTurn) (run_ (apply command >> checkStage) game)--prop_checkProtectorsTurnDoesNothingUnlessProtected :: GameAtProtectorsTurn -> Bool-prop_checkProtectorsTurnDoesNothingUnlessProtected (GameAtProtectorsTurn game) =- has (stage . _ProtectorsTurn) (run_ checkStage game)--prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn :: GameWithAllowedVoters -> Bool-prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn (GameWithAllowedVoters game) =- has (stage . _WolfHoundsTurn) (run_ checkStage game)--prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen :: GameWithAllowedVoters -> Property-prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen (GameWithAllowedVoters game) =- forAll (elements [Villagers, Werewolves]) $ \allegiance -> do- let game' = game & allegianceChosen .~ Just allegiance-- hasn't (stage . _WolfHoundsTurn) (run_ checkStage game')--prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed :: GameAtScapegoatsTurn -> Bool-prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed (GameAtScapegoatsTurn game) =- has (stage . _ScapegoatsTurn) (run_ checkStage game)--prop_checkSeersTurnAdvancesToWildChildsTurn :: GameWithSee -> Bool-prop_checkSeersTurnAdvancesToWildChildsTurn (GameWithSee game) =- has (stage . _WildChildsTurn) (run_ checkStage game)--prop_checkSeersTurnAdvancesWhenNoSeer :: GameAtSeersTurn -> Bool-prop_checkSeersTurnAdvancesWhenNoSeer (GameAtSeersTurn game) = do- let seer = game ^?! players . seers- let command = quitCommand $ seer ^. name-- hasn't (stage . _SeersTurn) (run_ (apply command >> checkStage) game)--prop_checkSeersTurnResetsSee :: GameWithSee -> Bool-prop_checkSeersTurnResetsSee (GameWithSee game) =- isNothing $ run_ checkStage game ^. see--prop_checkSeersTurnDoesNothingUnlessSeen :: GameAtSeersTurn -> Bool-prop_checkSeersTurnDoesNothingUnlessSeen (GameAtSeersTurn game) =- has (stage . _SeersTurn) (run_ checkStage game)--prop_checkSunriseIncrementsRound :: GameAtSunrise -> Property-prop_checkSunriseIncrementsRound (GameAtSunrise game) =- run_ checkStage game ^. round === game ^. round + 1--prop_checkSunriseSetsAngelsAllegiance :: GameAtSunrise -> Bool-prop_checkSunriseSetsAngelsAllegiance (GameAtSunrise game) = do- let game' = run_ checkStage game-- is villager $ game' ^?! players . angels--prop_checkSunsetSetsWildChildsAllegianceWhenRoleModelDead :: GameWithRoleModelAtVillagesTurn -> Property-prop_checkSunsetSetsWildChildsAllegianceWhenRoleModelDead (GameWithRoleModelAtVillagesTurn game) = do- let game' = foldr (\player -> run_ (apply $ voteCommand (player ^. name) (roleModel' ^. name))) game (game ^. players)-- let devotedServantsName = game ^?! players . devotedServants . name- let command = passCommand devotedServantsName-- isn't angel roleModel' && isn't devotedServant roleModel' && isn't jester roleModel'- ==> is werewolf $ run_ (checkStage >> apply command >> checkStage) game' ^?! players . wildChildren- where- roleModel' = game ^?! players . traverse . filteredBy name (fromJust $ game ^. roleModel)--prop_checkVillagesTurnAdvancesToDevotedServantsTurn :: GameWithMajorityVote -> Property-prop_checkVillagesTurnAdvancesToDevotedServantsTurn (GameWithMajorityVote game) =- isn't angel target && isn't devotedServant target- ==> has (stage . _DevotedServantsTurn) (run_ checkStage game)- where- target = head $ getVoteResult game--prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted :: GameWithConflictingVote -> Bool-prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted (GameWithConflictingVote game) =- hasn't (stage . _DevotedServantsTurn) (run_ checkStage game)---- TODO (hjw): tidy this test-prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats :: Game -> Property-prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats game =- forAll (runArbitraryCommands n game') $ \game'' ->- length (getVoteResult game'') > 1- ==> run_ checkStage game'' ^. players == game' ^. players- where- scapegoatsName = game ^?! players . scapegoats . name- game' = killPlayer scapegoatsName game & stage .~ VillagesTurn- n = length $ game' ^. players--prop_checkVillagesTurnDoesNothingUnlessAllVoted :: GameAtVillagesTurn -> Property-prop_checkVillagesTurnDoesNothingUnlessAllVoted (GameAtVillagesTurn game) =- forAll (runArbitraryCommands n game) $ \game' ->- has (stage . _VillagesTurn) (run_ checkStage game')- where- n = length (game ^. players) - 1--prop_checkWerewolvesTurnAdvancesToWitchsTurn :: GameWithDevourVotes -> Property-prop_checkWerewolvesTurnAdvancesToWitchsTurn (GameWithDevourVotes game) =- length (getVoteResult game) == 1- ==> has (stage . _WitchsTurn) (run_ checkStage game)--prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned :: GameWithDevourVotes -> Bool-prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned (GameWithDevourVotes game) =- hasn't (stage . _WitchsTurn) (run_ checkStage game')- where- game' = game & healUsed .~ True & poisonUsed .~ True--prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus :: GameWithDevourVotes -> Property-prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus (GameWithDevourVotes game) =- length (getVoteResult game) == 1- ==> has (events . traverse . _DevourEvent) (run_ checkStage game)--prop_checkWerewolvesTurnKillsNoOneWhenConflicted :: GameWithDevourVotes -> Property-prop_checkWerewolvesTurnKillsNoOneWhenConflicted (GameWithDevourVotes game) =- length (getVoteResult game) > 1- ==> hasn't (events . traverse . _DevourEvent) (run_ checkStage game)--prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended :: GameWithProtectAndDevourVotes -> Property-prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended (GameWithProtectAndDevourVotes game) =- length (getVoteResult game) == 1- ==> hasn't (events . traverse . _DevourEvent) (run_ checkStage game')- where- target = head $ getVoteResult game- game' = game & protect .~ Just (target ^. name)--prop_checkWerewolvesTurnResetsProtect :: GameWithProtectAndDevourVotes -> Bool-prop_checkWerewolvesTurnResetsProtect (GameWithProtectAndDevourVotes game) =- isNothing $ run_ checkStage game ^. protect--prop_checkWerewolvesTurnResetsVotes :: GameWithDevourVotes -> Bool-prop_checkWerewolvesTurnResetsVotes (GameWithDevourVotes game) =- Map.null $ run_ checkStage game ^. votes--prop_checkWerewolvesTurnDoesNothingUnlessAllVoted :: GameAtWerewolvesTurn -> Property-prop_checkWerewolvesTurnDoesNothingUnlessAllVoted (GameAtWerewolvesTurn game) =- forAll (runArbitraryCommands n game) $ \game' ->- has (stage . _WerewolvesTurn) (run_ checkStage game')- where- n = length (game ^.. players . werewolves) - 1--prop_checkWildChildsTurnAdvancesToProtectorsTurn :: GameAtWildChildsTurn -> Property-prop_checkWildChildsTurnAdvancesToProtectorsTurn (GameAtWildChildsTurn game) =- forAll (arbitraryWildChildChooseCommand game) $ \(Blind command) ->- has (stage . _ProtectorsTurn) (run_ (apply command >> checkStage) game)--prop_checkWildChildsTurnAdvancesWhenNoWildChild :: GameAtWildChildsTurn -> Bool-prop_checkWildChildsTurnAdvancesWhenNoWildChild (GameAtWildChildsTurn game) = do- let wildChild = game ^?! players . wildChildren- let command = quitCommand $ wildChild ^. name-- hasn't (stage . _WildChildsTurn) (run_ (apply command >> checkStage) game)--prop_checkWildChildsTurnDoesNothingUnlessRoleModelChosen :: GameAtWildChildsTurn -> Bool-prop_checkWildChildsTurnDoesNothingUnlessRoleModelChosen (GameAtWildChildsTurn game) =- has (stage . _WildChildsTurn) (run_ checkStage game)--prop_checkWitchsTurnAdvancesToVillagesTurn :: GameAtWitchsTurn -> Property-prop_checkWitchsTurnAdvancesToVillagesTurn (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- has (stage . _VillagesTurn) (run_ (apply command >> checkStage) game)--prop_checkWitchsTurnAdvancesWhenNoWitch :: GameAtWitchsTurn -> Bool-prop_checkWitchsTurnAdvancesWhenNoWitch (GameAtWitchsTurn game) = do- let witch = game ^?! players . witches- let command = quitCommand $ witch ^. name-- hasn't (stage . _WitchsTurn) (run_ (apply command >> checkStage) game)--prop_checkWitchsTurnHealsDevoureeWhenHealed :: GameWithHeal -> Property-prop_checkWitchsTurnHealsDevoureeWhenHealed (GameWithHeal game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- none (is dead) (run_ (apply command >> checkStage) game ^. players)--prop_checkWitchsTurnKillsOnePlayerWhenPoisoned :: GameWithPoison -> Property-prop_checkWitchsTurnKillsOnePlayerWhenPoisoned (GameWithPoison game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- length (run_ (apply command >> checkStage) game ^.. players . traverse . dead) == 1--prop_checkWitchsTurnDoesNothingWhenPassed :: GameAtWitchsTurn -> Property-prop_checkWitchsTurnDoesNothingWhenPassed (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- none (is dead) $ run_ (apply command >> checkStage) game ^. players--prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed :: GameAtWitchsTurn -> Bool-prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed (GameAtWitchsTurn game) =- has (stage . _WitchsTurn) (run_ checkStage game)--prop_checkWitchsTurnResetsHeal :: GameWithHeal -> Property-prop_checkWitchsTurnResetsHeal (GameWithHeal game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- not $ run_ (apply command >> checkStage) game ^. heal--prop_checkWitchsTurnResetsPoison :: GameWithPoison -> Property-prop_checkWitchsTurnResetsPoison (GameWithPoison game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- isNothing $ run_ (apply command >> checkStage) game ^. poison--prop_checkWitchsTurnClearsPasses :: GameAtWitchsTurn -> Property-prop_checkWitchsTurnClearsPasses (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->- null $ run_ (apply command >> checkStage) game ^. passes--prop_checkWolfHoundsTurnAdvancesToSeersTurn :: GameAtWolfHoundsTurn -> Property-prop_checkWolfHoundsTurnAdvancesToSeersTurn (GameAtWolfHoundsTurn game) =- forAll (arbitraryWolfHoundChooseCommand game) $ \(Blind command) ->- has (stage . _SeersTurn) (run_ (apply command >> checkStage) game)--prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound :: GameAtWolfHoundsTurn -> Bool-prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound (GameAtWolfHoundsTurn game) = do- let wolfHound = game ^?! players . wolfHounds- let command = quitCommand $ wolfHound ^. name-- hasn't (stage . _WolfHoundsTurn) (run_ (apply command >> checkStage) game)--prop_checkWolfHoundsTurnSetsWolfHoundsAllegiance :: GameWithAllegianceChosen -> Property-prop_checkWolfHoundsTurnSetsWolfHoundsAllegiance (GameWithAllegianceChosen game) =- game' ^?! players . wolfHounds . role . allegiance === fromJust (game' ^. allegianceChosen)- where- game' = run_ checkStage game--prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen :: GameAtWolfHoundsTurn -> Bool-prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen (GameAtWolfHoundsTurn game) =- has (stage . _WolfHoundsTurn) (run_ checkStage game) prop_checkGameOverAdvancesStageWhenOneAllegianceAlive :: GameWithOneAllegianceAlive -> Property prop_checkGameOverAdvancesStageWhenOneAllegianceAlive (GameWithOneAllegianceAlive game) =
+ test/src/Game/Werewolf/Test/Engine/Angel.hs view
@@ -0,0 +1,39 @@+{-|+Module : Game.Werewolf.Test.Engine.Angel+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Angel (+ -- * Tests+ allAngelEngineTests,+) where++import Control.Lens++import Game.Werewolf+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Prelude hiding (round)++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allAngelEngineTests :: [TestTree]+allAngelEngineTests =+ [ testProperty "check sunrise increments round" prop_checkSunriseIncrementsRound+ , testProperty "check sunrise sets angel's allegiance" prop_checkSunriseSetsAngelsAllegiance+ ]++prop_checkSunriseIncrementsRound :: GameAtSunrise -> Property+prop_checkSunriseIncrementsRound (GameAtSunrise game) =+ run_ checkStage game ^. round === game ^. round + 1++prop_checkSunriseSetsAngelsAllegiance :: GameAtSunrise -> Bool+prop_checkSunriseSetsAngelsAllegiance (GameAtSunrise game) = do+ let game' = run_ checkStage game++ is villager $ game' ^?! players . angels
+ test/src/Game/Werewolf/Test/Engine/DevotedServant.hs view
@@ -0,0 +1,57 @@+{-|+Module : Game.Werewolf.Test.Engine.DevotedServant+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.DevotedServant (+ -- * Tests+ allDevotedServantEngineTests,+) where++import Control.Lens hiding (isn't)++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allDevotedServantEngineTests :: [TestTree]+allDevotedServantEngineTests =+ [ testProperty "check stage skips devoted servant's turn when no devoted servant" prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant++ , testProperty "check devoted servant's turn advances to wolf-hound's turn" prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn+ , testProperty "check devoted servant's turn advances when no devoted servant" prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant+ , testProperty "check devoted servant's turn does nothing unless revealed or passed" prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed+ ]++prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant :: GameWithMajorityVote -> Bool+prop_checkStageSkipsDevotedServantsTurnWhenNoDevotedServant (GameWithMajorityVote game) =+ hasn't (stage . _DevotedServantsTurn) game'+ where+ devotedServantsName = game ^?! players . devotedServants . name+ game' = run_ (apply (quitCommand devotedServantsName) >> checkStage) game++prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn :: GameAtDevotedServantsTurn -> Property+prop_checkDevotedServantsTurnAdvancesToWolfHoundsTurn (GameAtDevotedServantsTurn game) = do+ forAll (arbitraryCommand game) $ \(Blind command) ->+ isn't angel target && isn't hunter target && isn't wolfHound target+ ==> has (stage . _WolfHoundsTurn) (run_ (apply command >> checkStage) game)+ where+ target = head $ getVoteResult game++prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant :: GameAtDevotedServantsTurn -> Bool+prop_checkDevotedServantsTurnAdvancesWhenNoDevotedServant (GameAtDevotedServantsTurn game) = do+ let devotedServantsName = game ^?! players . devotedServants . name+ let command = quitCommand devotedServantsName++ hasn't (stage . _DevotedServantsTurn) (run_ (apply command >> checkStage) game)++prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed :: GameAtDevotedServantsTurn -> Bool+prop_checkDevotedServantsTurnDoesNothingUnlessRevealedOrPassed (GameAtDevotedServantsTurn game) =+ has (stage . _DevotedServantsTurn) (run_ checkStage game)
+ test/src/Game/Werewolf/Test/Engine/Hunter.hs view
@@ -0,0 +1,21 @@+{-|+Module : Game.Werewolf.Test.Engine.Hunter+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Hunter (+ -- * Tests+ allHunterEngineTests,+) where++import Test.Tasty++allHunterEngineTests :: [TestTree]+allHunterEngineTests =+ -- TODO (hjw): pending+ [ --testProperty "check hunter's turn advances to wolf-hound's turn when hunter lynched"+ --, testProperty "check hunter's turn advances to village's turn when hunter devoured"+ --, testProperty "check hunter's turn does nothing until hunter retaliated"+ ]
+ test/src/Game/Werewolf/Test/Engine/Lynching.hs view
@@ -0,0 +1,88 @@+{-|+Module : Game.Werewolf.Test.Engine.Lynching+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Lynching (+ -- * Tests+ allLynchingEngineTests,+) where++import Control.Lens hiding (isn't)++import qualified Data.Map as Map++import Game.Werewolf+import Game.Werewolf.Command.Villager+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allLynchingEngineTests :: [TestTree]+allLynchingEngineTests =+ [ testProperty "check stage skips lynching when no votes" prop_checkStageSkipsLynchingWhenNoVotes++ , testProperty "check lynching lynches one player when consensus" prop_checkLynchingLynchesOnePlayerWhenConsensus+ , testProperty "check lynching lynches no one when target is jester" prop_checkLynchingLynchesNoOneWhenTargetIsJester+ , testProperty "check lynching lynches scapegoat when conflicted" prop_checkLynchingLynchesScapegoatWhenConflicted+ , testProperty "check lynching lynches no one when conflicted and no scapegoats" prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats+ , testProperty "check lynching resets votes" prop_checkLynchingResetsVotes+ , testProperty "check lynching sets allowed voters" prop_checkLynchingSetsAllowedVoters+ ]++prop_checkStageSkipsLynchingWhenNoVotes :: GameWithNoAllowedVotersAtVillagesTurn -> Bool+prop_checkStageSkipsLynchingWhenNoVotes (GameWithNoAllowedVotersAtVillagesTurn game) = do+ let game' = run_ checkStage game++ hasn't (stage . _Lynching) game'++prop_checkLynchingLynchesOnePlayerWhenConsensus :: GameWithPassAtDevotedServantsTurn -> Property+prop_checkLynchingLynchesOnePlayerWhenConsensus (GameWithPassAtDevotedServantsTurn game) =+ isn't jester target+ ==> length (run_ checkStage game ^.. players . traverse . dead) == 1+ where+ target = head $ getVoteResult game++prop_checkLynchingLynchesNoOneWhenTargetIsJester :: GameAtVillagesTurn -> Bool+prop_checkLynchingLynchesNoOneWhenTargetIsJester (GameAtVillagesTurn game) = do+ let game' = foldr (\player -> run_ (apply $ voteCommand (player ^. name) (jester ^. name))) game (game ^. players)++ none (is dead) (run_ checkStage game' ^. players)+ where+ jester = game ^?! players . jesters++prop_checkLynchingLynchesScapegoatWhenConflicted :: GameAtScapegoatsTurn -> Bool+prop_checkLynchingLynchesScapegoatWhenConflicted (GameAtScapegoatsTurn game) =+ is dead $ run_ checkStage game ^?! players . scapegoats++-- TODO (hjw): tidy this test+prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats :: Game -> Property+prop_checkLynchingLynchesNoOneWhenConflictedAndNoScapegoats game =+ forAll (runArbitraryCommands n game') $ \game'' ->+ length (getVoteResult game'') > 1+ ==> run_ checkStage game'' ^. players == game' ^. players+ where+ scapegoatsName = game ^?! players . scapegoats . name+ game' = killPlayer scapegoatsName game & stage .~ VillagesTurn+ n = length $ game' ^. players++prop_checkLynchingResetsVotes :: GameWithPassAtDevotedServantsTurn -> Property+prop_checkLynchingResetsVotes (GameWithPassAtDevotedServantsTurn game) =+ isn't devotedServant target+ ==> Map.null $ run_ checkStage game ^. votes+ where+ target = head $ getVoteResult game++prop_checkLynchingSetsAllowedVoters :: GameWithLynchVotes -> Property+prop_checkLynchingSetsAllowedVoters (GameWithLynchVotes game) =+ game' ^. allowedVoters === expectedAllowedVoters ^.. names+ where+ game' = run_ checkStage game+ expectedAllowedVoters+ | game' ^. jesterRevealed = filter (isn't jester) $ game' ^. players+ | otherwise = game' ^.. players . traverse . alive
+ test/src/Game/Werewolf/Test/Engine/Orphan.hs view
@@ -0,0 +1,72 @@+{-|+Module : Game.Werewolf.Test.Engine.Orphan+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Orphan (+ -- * Tests+ allOrphanEngineTests,+) where++import Control.Lens hiding (isn't)++import Data.Maybe++import Game.Werewolf+import Game.Werewolf.Command.DevotedServant+import Game.Werewolf.Command.Global+import Game.Werewolf.Command.Villager+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allOrphanEngineTests :: [TestTree]+allOrphanEngineTests =+ [ testProperty "check stage skips orphan's turn when no orphan" prop_checkStageSkipsOrphansTurnWhenNoOrphan++ , testProperty "check orphan's turn advances to protector's turn" prop_checkOrphansTurnAdvancesToProtectorsTurn+ , testProperty "check orphan's turn advances when no orphan" prop_checkOrphansTurnAdvancesWhenNoOrphan+ , testProperty "check orphan's turn does nothing unless chosen" prop_checkOrphansTurnDoesNothingUnlessRoleModelChosen++ , testProperty "check sunset sets orphan's allegiance when role model dead" prop_checkSunsetSetsOrphansAllegianceWhenRoleModelDead+ ]++prop_checkStageSkipsOrphansTurnWhenNoOrphan :: GameWithSee -> Bool+prop_checkStageSkipsOrphansTurnWhenNoOrphan (GameWithSee game) =+ hasn't (stage . _OrphansTurn) game'+ where+ orphansName = game ^?! players . orphans . name+ game' = run_ (apply (quitCommand orphansName) >> checkStage) game++prop_checkOrphansTurnAdvancesToProtectorsTurn :: GameAtOrphansTurn -> Property+prop_checkOrphansTurnAdvancesToProtectorsTurn (GameAtOrphansTurn game) =+ forAll (arbitraryOrphanChooseCommand game) $ \(Blind command) ->+ has (stage . _ProtectorsTurn) (run_ (apply command >> checkStage) game)++prop_checkOrphansTurnAdvancesWhenNoOrphan :: GameAtOrphansTurn -> Bool+prop_checkOrphansTurnAdvancesWhenNoOrphan (GameAtOrphansTurn game) = do+ let orphan = game ^?! players . orphans+ let command = quitCommand $ orphan ^. name++ hasn't (stage . _OrphansTurn) (run_ (apply command >> checkStage) game)++prop_checkOrphansTurnDoesNothingUnlessRoleModelChosen :: GameAtOrphansTurn -> Bool+prop_checkOrphansTurnDoesNothingUnlessRoleModelChosen (GameAtOrphansTurn game) =+ has (stage . _OrphansTurn) (run_ checkStage game)++prop_checkSunsetSetsOrphansAllegianceWhenRoleModelDead :: GameWithRoleModelAtVillagesTurn -> Property+prop_checkSunsetSetsOrphansAllegianceWhenRoleModelDead (GameWithRoleModelAtVillagesTurn game) = do+ let game' = foldr (\player -> run_ (apply $ voteCommand (player ^. name) (roleModel' ^. name))) game (game ^. players)++ let devotedServantsName = game ^?! players . devotedServants . name+ let command = passCommand devotedServantsName++ isn't angel roleModel' && isn't devotedServant roleModel' && isn't hunter roleModel' && isn't jester roleModel'+ ==> is werewolf $ run_ (checkStage >> apply command >> checkStage) game' ^?! players . orphans+ where+ roleModel' = game ^?! players . traverse . filteredBy name (fromJust $ game ^. roleModel)
+ test/src/Game/Werewolf/Test/Engine/Protector.hs view
@@ -0,0 +1,52 @@+{-|+Module : Game.Werewolf.Test.Engine.Protector+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Protector (+ -- * Tests+ allProtectorEngineTests,+) where++import Control.Lens++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.Tasty+import Test.Tasty.QuickCheck++allProtectorEngineTests :: [TestTree]+allProtectorEngineTests =+ [ testProperty "check stage skips protector's turn when no protector" prop_checkStageSkipsProtectorsTurnWhenNoProtector++ , testProperty "check protector's turn advances to werewolves' turn" prop_checkProtectorsTurnAdvancesToWerewolvesTurn+ , testProperty "check protector's turn advances when no protector" prop_checkProtectorsTurnAdvancesWhenNoProtector+ , testProperty "check protector's turn does nothing unless protected" prop_checkProtectorsTurnDoesNothingUnlessProtected+ ]++prop_checkStageSkipsProtectorsTurnWhenNoProtector :: GameWithRoleModel -> Bool+prop_checkStageSkipsProtectorsTurnWhenNoProtector (GameWithRoleModel game) =+ hasn't (stage . _ProtectorsTurn) game'+ where+ protectorsName = game ^?! players . protectors . name+ game' = run_ (apply (quitCommand protectorsName) >> checkStage) game++prop_checkProtectorsTurnAdvancesToWerewolvesTurn :: GameWithProtect -> Bool+prop_checkProtectorsTurnAdvancesToWerewolvesTurn (GameWithProtect game) =+ has (stage . _WerewolvesTurn) (run_ checkStage game)++prop_checkProtectorsTurnAdvancesWhenNoProtector :: GameAtProtectorsTurn -> Bool+prop_checkProtectorsTurnAdvancesWhenNoProtector (GameAtProtectorsTurn game) = do+ let protector = game ^?! players . protectors+ let command = quitCommand $ protector ^. name++ hasn't (stage . _ProtectorsTurn) (run_ (apply command >> checkStage) game)++prop_checkProtectorsTurnDoesNothingUnlessProtected :: GameAtProtectorsTurn -> Bool+prop_checkProtectorsTurnDoesNothingUnlessProtected (GameAtProtectorsTurn game) =+ has (stage . _ProtectorsTurn) (run_ checkStage game)
+ test/src/Game/Werewolf/Test/Engine/Scapegoat.hs view
@@ -0,0 +1,51 @@+{-|+Module : Game.Werewolf.Test.Engine.Scapegoat+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Scapegoat (+ -- * Tests+ allScapegoatEngineTests,+) where++import Control.Lens++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.Tasty+import Test.Tasty.QuickCheck++allScapegoatEngineTests :: [TestTree]+allScapegoatEngineTests =+ [ testProperty "check stage skips scapegoat's turn when no scapegoat" prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat++ , testProperty "check scapegoat's turn advances to wolf-hound's turn" prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn+ , testProperty "check scapegoat's turn skips wolf-hound's turn when allegiance chosen" prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen+ , testProperty "check scapegoat's turn does nothing while scapegoat blamed" prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed+ ]++prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat :: GameWithConflictingVote -> Bool+prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat (GameWithConflictingVote game) =+ hasn't (stage . _ScapegoatsTurn) game'+ where+ scapegoatsName = game ^?! players . scapegoats . name+ game' = run_ (apply (quitCommand scapegoatsName) >> checkStage) game++prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn :: GameWithAllowedVoters -> Bool+prop_checkScapegoatsTurnAdvancesToWolfHoundsTurn (GameWithAllowedVoters game) =+ has (stage . _WolfHoundsTurn) (run_ checkStage game)++prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen :: GameWithAllowedVoters -> Bool+prop_checkScapegoatsTurnSkipsWolfHoundsTurnWhenAllegianceChosen (GameWithAllowedVoters game) = do+ let game' = game & allegianceChosen .~ True++ hasn't (stage . _WolfHoundsTurn) (run_ checkStage game')++prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed :: GameAtScapegoatsTurn -> Bool+prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed (GameAtScapegoatsTurn game) =+ has (stage . _ScapegoatsTurn) (run_ checkStage game)
+ test/src/Game/Werewolf/Test/Engine/Seer.hs view
@@ -0,0 +1,59 @@+{-|+Module : Game.Werewolf.Test.Engine.Seer+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Seer (+ -- * Tests+ allSeerEngineTests,+) where++import Control.Lens++import Data.Maybe++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.Tasty+import Test.Tasty.QuickCheck++allSeerEngineTests :: [TestTree]+allSeerEngineTests =+ [ testProperty "check stage skips seer's turn when no seer" prop_checkStageSkipsSeersTurnWhenNoSeer++ , testProperty "check seer's turn advances to orphan's turn" prop_checkSeersTurnAdvancesToOrphansTurn+ , testProperty "check seer's turn advances when no seer" prop_checkSeersTurnAdvancesWhenNoSeer+ , testProperty "check seer's turn resets sees" prop_checkSeersTurnResetsSee+ , testProperty "check seer's turn does nothing unless seen" prop_checkSeersTurnDoesNothingUnlessSeen+ ]++prop_checkStageSkipsSeersTurnWhenNoSeer :: GameWithPassAtDevotedServantsTurn -> Bool+prop_checkStageSkipsSeersTurnWhenNoSeer (GameWithPassAtDevotedServantsTurn game) =+ hasn't (stage . _SeersTurn) game'+ where+ seersName = game ^?! players . seers . name+ game' = run_ (apply (quitCommand seersName) >> checkStage) game++prop_checkSeersTurnAdvancesToOrphansTurn :: GameWithSee -> Bool+prop_checkSeersTurnAdvancesToOrphansTurn (GameWithSee game) =+ has (stage . _OrphansTurn) (run_ checkStage game)++prop_checkSeersTurnAdvancesWhenNoSeer :: GameAtSeersTurn -> Bool+prop_checkSeersTurnAdvancesWhenNoSeer (GameAtSeersTurn game) = do+ let seer = game ^?! players . seers+ let command = quitCommand $ seer ^. name++ hasn't (stage . _SeersTurn) (run_ (apply command >> checkStage) game)++prop_checkSeersTurnResetsSee :: GameWithSee -> Bool+prop_checkSeersTurnResetsSee (GameWithSee game) =+ isNothing $ run_ checkStage game ^. see++prop_checkSeersTurnDoesNothingUnlessSeen :: GameAtSeersTurn -> Bool+prop_checkSeersTurnDoesNothingUnlessSeen (GameAtSeersTurn game) =+ has (stage . _SeersTurn) (run_ checkStage game)
+ test/src/Game/Werewolf/Test/Engine/Village.hs view
@@ -0,0 +1,55 @@+{-|+Module : Game.Werewolf.Test.Engine.Village+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Village (+ -- * Tests+ allVillageEngineTests,+) where++import Control.Lens hiding (isn't)++import Game.Werewolf+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allVillageEngineTests :: [TestTree]+allVillageEngineTests =+ [ testProperty "check stage skips village's turn when allowed voters empty" prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty++ , testProperty "check villages' turn advances to devoted servant's turn" prop_checkVillagesTurnAdvancesToDevotedServantsTurn+ , testProperty "check villages' turn skips devoted servant's turn when conflicted" prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted+ , testProperty "check villages' turn does nothing unless all voted" prop_checkVillagesTurnDoesNothingUnlessAllVoted+ ]++prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty :: GameAtWitchsTurn -> Property+prop_checkStageSkipsVillagesTurnWhenAllowedVotersEmpty (GameAtWitchsTurn game) =+ forAll (arbitraryWitchPassCommand game') $ \(Blind passWitchsTurnCommand) -> do+ hasn't (stage . _VillagesTurn) (run_ (apply passWitchsTurnCommand >> checkStage) game')+ where+ game' = game & allowedVoters .~ []++prop_checkVillagesTurnAdvancesToDevotedServantsTurn :: GameWithMajorityVote -> Property+prop_checkVillagesTurnAdvancesToDevotedServantsTurn (GameWithMajorityVote game) =+ isn't angel target && isn't devotedServant target+ ==> has (stage . _DevotedServantsTurn) (run_ checkStage game)+ where+ target = head $ getVoteResult game++prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted :: GameWithConflictingVote -> Bool+prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted (GameWithConflictingVote game) =+ hasn't (stage . _DevotedServantsTurn) (run_ checkStage game)++prop_checkVillagesTurnDoesNothingUnlessAllVoted :: GameAtVillagesTurn -> Property+prop_checkVillagesTurnDoesNothingUnlessAllVoted (GameAtVillagesTurn game) =+ forAll (runArbitraryCommands n game) $ \game' ->+ has (stage . _VillagesTurn) (run_ checkStage game')+ where+ n = length (game ^. players) - 1
+ test/src/Game/Werewolf/Test/Engine/Werewolf.hs view
@@ -0,0 +1,89 @@+{-|+Module : Game.Werewolf.Test.Engine.Werewolf+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Werewolf (+ -- * Tests+ allWerewolfEngineTests,+) where++import Control.Lens++import qualified Data.Map as Map+import Data.Maybe++import Game.Werewolf+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allWerewolfEngineTests :: [TestTree]+allWerewolfEngineTests =+ [ testProperty "check stage skips werewolves' turn when no werewolves" prop_checkStageSkipsWerewolvesTurnWhenNoWerewolves++ , testProperty "check werewolves' turn advances to witch's turn" prop_checkWerewolvesTurnAdvancesToWitchsTurn+ , testProperty "check werewolves' turn skips witch's turn when healed and poisoned" prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned+ , testProperty "check werewolves' turn kills one player when consensus" prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus+ , testProperty "check werewolves' turn kills no one when conflicted" prop_checkWerewolvesTurnKillsNoOneWhenConflicted+ , testProperty "check werewolves' turn kills no one when target defended" prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended+ , testProperty "check werewolves' turn resets protect" prop_checkWerewolvesTurnResetsProtect+ , testProperty "check werewolves' turn resets votes" prop_checkWerewolvesTurnResetsVotes+ , testProperty "check werewolves' turn does nothing unless all voted" prop_checkWerewolvesTurnDoesNothingUnlessAllVoted+ ]++prop_checkStageSkipsWerewolvesTurnWhenNoWerewolves :: GameWithNoWerewolvesAtProtectorsTurn -> Property+prop_checkStageSkipsWerewolvesTurnWhenNoWerewolves (GameWithNoWerewolvesAtProtectorsTurn game) =+ forAll (arbitraryProtectCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command) game++ hasn't (stage . _WerewolvesTurn) game'++prop_checkWerewolvesTurnAdvancesToWitchsTurn :: GameWithDevourVotes -> Property+prop_checkWerewolvesTurnAdvancesToWitchsTurn (GameWithDevourVotes game) =+ length (getVoteResult game) == 1+ ==> has (stage . _WitchsTurn) (run_ checkStage game)++prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned :: GameWithDevourVotes -> Bool+prop_checkWerewolvesTurnSkipsWitchsTurnWhenHealedAndPoisoned (GameWithDevourVotes game) =+ hasn't (stage . _WitchsTurn) (run_ checkStage game')+ where+ game' = game & healUsed .~ True & poisonUsed .~ True++prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus :: GameWithDevourVotes -> Property+prop_checkWerewolvesTurnKillsOnePlayerWhenConsensus (GameWithDevourVotes game) =+ length (getVoteResult game) == 1+ ==> has (events . traverse . _DevourEvent) (run_ checkStage game)++prop_checkWerewolvesTurnKillsNoOneWhenConflicted :: GameWithDevourVotes -> Property+prop_checkWerewolvesTurnKillsNoOneWhenConflicted (GameWithDevourVotes game) =+ length (getVoteResult game) > 1+ ==> hasn't (events . traverse . _DevourEvent) (run_ checkStage game)++prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended :: GameWithProtectAndDevourVotes -> Property+prop_checkWerewolvesTurnKillsNoOneWhenTargetDefended (GameWithProtectAndDevourVotes game) =+ length (getVoteResult game) == 1+ ==> hasn't (events . traverse . _DevourEvent) (run_ checkStage game')+ where+ target = head $ getVoteResult game+ game' = game & protect .~ Just (target ^. name)++prop_checkWerewolvesTurnResetsProtect :: GameWithProtectAndDevourVotes -> Bool+prop_checkWerewolvesTurnResetsProtect (GameWithProtectAndDevourVotes game) =+ isNothing $ run_ checkStage game ^. protect++prop_checkWerewolvesTurnResetsVotes :: GameWithDevourVotes -> Bool+prop_checkWerewolvesTurnResetsVotes (GameWithDevourVotes game) =+ Map.null $ run_ checkStage game ^. votes++prop_checkWerewolvesTurnDoesNothingUnlessAllVoted :: GameAtWerewolvesTurn -> Property+prop_checkWerewolvesTurnDoesNothingUnlessAllVoted (GameAtWerewolvesTurn game) =+ forAll (runArbitraryCommands n game) $ \game' ->+ has (stage . _WerewolvesTurn) (run_ checkStage game')+ where+ n = length (game ^.. players . werewolves) - 1
+ test/src/Game/Werewolf/Test/Engine/Witch.hs view
@@ -0,0 +1,103 @@+{-|+Module : Game.Werewolf.Test.Engine.Witch+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.Witch (+ -- * Tests+ allWitchEngineTests,+) where++import Control.Lens++import Data.Maybe++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allWitchEngineTests :: [TestTree]+allWitchEngineTests =+ [ testProperty "check stage skips witch's turn when no witch" prop_checkStageSkipsWitchsTurnWhenNoWitch++ , testProperty "check witch's turn advances to villages' turn" prop_checkWitchsTurnAdvancesToVillagesTurn+ , testProperty "check witch's turn advances when no witch" prop_checkWitchsTurnAdvancesWhenNoWitch+ , testProperty "check witch's turn heals devouree when healed" prop_checkWitchsTurnHealsDevoureeWhenHealed+ , testProperty "check witch's turn kills one player when poisoned" prop_checkWitchsTurnKillsOnePlayerWhenPoisoned+ , testProperty "check witch's turn does nothing when passed" prop_checkWitchsTurnDoesNothingWhenPassed+ , testProperty "check witch's turn does nothing unless actioned or passed" prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed+ , testProperty "check witch's turn resets heal" prop_checkWitchsTurnResetsHeal+ , testProperty "check witch's turn resets poison" prop_checkWitchsTurnResetsPoison+ , testProperty "check witch's turn clears passed" prop_checkWitchsTurnClearsPassed+ ]++prop_checkStageSkipsWitchsTurnWhenNoWitch :: GameWithDevourVotes -> Property+prop_checkStageSkipsWitchsTurnWhenNoWitch (GameWithDevourVotes game) =+ null (run_ checkStage game' ^.. players . angels . dead)+ ==> hasn't (stage . _WitchsTurn) game'+ where+ witchsName = game ^?! players . witches . name+ game' = run_ (apply (quitCommand witchsName) >> checkStage) game++prop_checkWitchsTurnAdvancesToVillagesTurn :: GameAtWitchsTurn -> Property+prop_checkWitchsTurnAdvancesToVillagesTurn (GameAtWitchsTurn game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->+ has (stage . _VillagesTurn) (run_ (apply command >> checkStage) game)++prop_checkWitchsTurnAdvancesWhenNoWitch :: GameAtWitchsTurn -> Bool+prop_checkWitchsTurnAdvancesWhenNoWitch (GameAtWitchsTurn game) = do+ let witch = game ^?! players . witches+ let command = quitCommand $ witch ^. name++ hasn't (stage . _WitchsTurn) (run_ (apply command >> checkStage) game)++prop_checkWitchsTurnHealsDevoureeWhenHealed :: GameWithHeal -> Property+prop_checkWitchsTurnHealsDevoureeWhenHealed (GameWithHeal game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->+ none (is dead) (run_ (apply command >> checkStage) game ^. players)++prop_checkWitchsTurnKillsOnePlayerWhenPoisoned :: GameWithPoison -> Property+prop_checkWitchsTurnKillsOnePlayerWhenPoisoned (GameWithPoison game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->+ length (run_ (apply command >> checkStage) game ^.. players . traverse . dead) == 1++prop_checkWitchsTurnDoesNothingWhenPassed :: GameAtWitchsTurn -> Property+prop_checkWitchsTurnDoesNothingWhenPassed (GameAtWitchsTurn game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command >> checkStage) game++ none (is dead) $ game' ^. players++prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed :: GameAtWitchsTurn -> Bool+prop_checkWitchsTurnDoesNothingUnlessActionedOrPassed (GameAtWitchsTurn game) = do+ let game' = run_ checkStage game++ has (stage . _WitchsTurn) game'++prop_checkWitchsTurnResetsHeal :: GameWithHeal -> Property+prop_checkWitchsTurnResetsHeal (GameWithHeal game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command >> checkStage) game++ not $ game' ^. heal++prop_checkWitchsTurnResetsPoison :: GameWithPoison -> Property+prop_checkWitchsTurnResetsPoison (GameWithPoison game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command >> checkStage) game++ isNothing $ game' ^. poison++prop_checkWitchsTurnClearsPassed :: GameAtWitchsTurn -> Property+prop_checkWitchsTurnClearsPassed (GameAtWitchsTurn game) =+ forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command >> checkStage) game++ not $ game' ^. passed
+ test/src/Game/Werewolf/Test/Engine/WolfHound.hs view
@@ -0,0 +1,56 @@+{-|+Module : Game.Werewolf.Test.Engine.WolfHound+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.WolfHound (+ -- * Tests+ allWolfHoundEngineTests,+) where++import Control.Lens++import Game.Werewolf+import Game.Werewolf.Command.Global+import Game.Werewolf.Test.Arbitrary+import Game.Werewolf.Test.Util++import Test.QuickCheck+import Test.Tasty+import Test.Tasty.QuickCheck++allWolfHoundEngineTests :: [TestTree]+allWolfHoundEngineTests =+ [ testProperty "check stage skips wolf-hound's turn when no wolf-hound" prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound++ , testProperty "check wolf-hound's turn advances to seer's turn" prop_checkWolfHoundsTurnAdvancesToSeersTurn+ , testProperty "check wolf-hound's turn advances when no wolf-hound" prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound+ , testProperty "check wolf-hound's turn does nothing unless allegiance chosen" prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen+ ]++prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound :: GameWithProtect -> Bool+prop_checkStageSkipsWolfHoundsTurnWhenNoWolfHound (GameWithProtect game) =+ hasn't (stage . _WolfHoundsTurn) game'+ where+ wolfHoundsName = game ^?! players . wolfHounds . name+ game' = run_ (apply (quitCommand wolfHoundsName) >> checkStage) game++prop_checkWolfHoundsTurnAdvancesToSeersTurn :: GameAtWolfHoundsTurn -> Property+prop_checkWolfHoundsTurnAdvancesToSeersTurn (GameAtWolfHoundsTurn game) =+ forAll (arbitraryWolfHoundChooseCommand game) $ \(Blind command) -> do+ let game' = run_ (apply command >> checkStage) game++ has (stage . _SeersTurn) game'++prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound :: GameAtWolfHoundsTurn -> Bool+prop_checkWolfHoundsTurnAdvancesWhenNoWolfHound (GameAtWolfHoundsTurn game) = do+ let wolfHound = game ^?! players . wolfHounds+ let command = quitCommand $ wolfHound ^. name++ hasn't (stage . _WolfHoundsTurn) (run_ (apply command >> checkStage) game)++prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen :: GameAtWolfHoundsTurn -> Bool+prop_checkWolfHoundsTurnDoesNothingUnlessAllegianceChosen (GameAtWolfHoundsTurn game) =+ has (stage . _WolfHoundsTurn) (run_ checkStage game)
test/src/Game/Werewolf/Test/Game.hs view
@@ -12,8 +12,6 @@ import Control.Lens -import Data.Maybe- import Game.Werewolf import Game.Werewolf.Test.Arbitrary () @@ -27,20 +25,24 @@ [ testProperty "new game starts at village's turn when angel in play" prop_newGameStartsAtVillagesTurnWhenAngelInPlay , testProperty "new game starts at sunset when no angel in play" prop_newGameStartsAtSunsetWhenNoAngelInPlay , testProperty "new game starts on first round" prop_newGameStartsOnFirstRound+ , testProperty "new game uses given players" prop_newGameUsesGivenPlayers , testProperty "new game starts with events empty" prop_newGameStartsWithEventsEmpty- , testProperty "new game starts with passes empty" prop_newGameStartsWithPassesEmpty+ , testProperty "new game starts with boots empty" prop_newGameStartsWithBootsEmpty+ , testProperty "new game starts with allegiance chosen false" prop_newGameStartsWithAllegianceChosenFalse , testProperty "new game starts with allowed voters full" prop_newGameStartsWithAllowedVotersFull , testProperty "new game starts with heal false" prop_newGameStartsWithHealFalse , testProperty "new game starts with heal used false" prop_newGameStartsWithHealUsedFalse+ , testProperty "new game starts with hunter retaliated false" prop_newGameStartsWithHunterRetaliatedFalse+ , testProperty "new game starts with jester revealed false" prop_newGameStartsWithJesterRevealedFalse+ , testProperty "new game starts with passed false" prop_newGameStartsWithPassedFalse , testProperty "new game starts with no poison" prop_newGameStartsWithNoPoison , testProperty "new game starts with poison used false" prop_newGameStartsWithPoisonUsedFalse , testProperty "new game starts with no prior protect" prop_newGameStartsWithNoPriorProtect , testProperty "new game starts with no protect" prop_newGameStartsWithNoProtect+ , testProperty "new game starts with no role model" prop_newGameStartsWithNoRoleModel , testProperty "new game starts with scapegoat blamed false" prop_newGameStartsWithScapegoatBlamedFalse , testProperty "new game starts with no see" prop_newGameStartsWithNoSee- , testProperty "new game starts with jester revealed false" prop_newGameStartsWithJesterRevealedFalse , testProperty "new game starts with votes empty" prop_newGameStartsWithVotesEmpty- , testProperty "new game uses given players" prop_newGameUsesGivenPlayers ] prop_newGameStartsAtVillagesTurnWhenAngelInPlay :: [Player] -> Property@@ -56,12 +58,18 @@ prop_newGameStartsOnFirstRound :: [Player] -> Bool prop_newGameStartsOnFirstRound players = isFirstRound $ newGame players +prop_newGameUsesGivenPlayers :: [Player] -> Bool+prop_newGameUsesGivenPlayers players' = newGame players' ^. players == players'+ prop_newGameStartsWithEventsEmpty :: [Player] -> Bool prop_newGameStartsWithEventsEmpty players = has (events . _Empty) (newGame players) -prop_newGameStartsWithPassesEmpty :: [Player] -> Bool-prop_newGameStartsWithPassesEmpty players = has (passes . _Empty) (newGame players)+prop_newGameStartsWithBootsEmpty :: [Player] -> Bool+prop_newGameStartsWithBootsEmpty players = has (boots . _Empty) (newGame players) +prop_newGameStartsWithAllegianceChosenFalse :: [Player] -> Bool+prop_newGameStartsWithAllegianceChosenFalse players = not $ newGame players ^. allegianceChosen+ prop_newGameStartsWithAllowedVotersFull :: [Player] -> Property prop_newGameStartsWithAllowedVotersFull players = newGame players ^. allowedVoters === players ^.. names @@ -71,30 +79,35 @@ prop_newGameStartsWithHealUsedFalse :: [Player] -> Bool prop_newGameStartsWithHealUsedFalse players = not $ newGame players ^. healUsed +prop_newGameStartsWithHunterRetaliatedFalse :: [Player] -> Bool+prop_newGameStartsWithHunterRetaliatedFalse players = not $ newGame players ^. hunterRetaliated++prop_newGameStartsWithJesterRevealedFalse :: [Player] -> Bool+prop_newGameStartsWithJesterRevealedFalse players = not $ newGame players ^. jesterRevealed++prop_newGameStartsWithPassedFalse :: [Player] -> Bool+prop_newGameStartsWithPassedFalse players = not $ newGame players ^. passed+ prop_newGameStartsWithNoPoison :: [Player] -> Bool-prop_newGameStartsWithNoPoison players = isNothing $ newGame players ^. poison+prop_newGameStartsWithNoPoison players = has (poison . _Nothing) (newGame players) prop_newGameStartsWithPoisonUsedFalse :: [Player] -> Bool prop_newGameStartsWithPoisonUsedFalse players = not $ newGame players ^. poisonUsed prop_newGameStartsWithNoPriorProtect :: [Player] -> Bool-prop_newGameStartsWithNoPriorProtect players = isNothing $ newGame players ^. priorProtect+prop_newGameStartsWithNoPriorProtect players = has (priorProtect . _Nothing) (newGame players) prop_newGameStartsWithNoProtect :: [Player] -> Bool-prop_newGameStartsWithNoProtect players = isNothing $ newGame players ^. protect+prop_newGameStartsWithNoProtect players = has (protect . _Nothing) (newGame players) +prop_newGameStartsWithNoRoleModel :: [Player] -> Bool+prop_newGameStartsWithNoRoleModel players = has (roleModel . _Nothing) (newGame players)+ prop_newGameStartsWithScapegoatBlamedFalse :: [Player] -> Bool prop_newGameStartsWithScapegoatBlamedFalse players = not $ newGame players ^. scapegoatBlamed prop_newGameStartsWithNoSee :: [Player] -> Bool-prop_newGameStartsWithNoSee players = isNothing $ newGame players ^. see--prop_newGameStartsWithJesterRevealedFalse :: [Player] -> Bool-prop_newGameStartsWithJesterRevealedFalse players =- not $ newGame players ^. jesterRevealed+prop_newGameStartsWithNoSee players = has (see . _Nothing) (newGame players) prop_newGameStartsWithVotesEmpty :: [Player] -> Bool prop_newGameStartsWithVotesEmpty players = has (votes . _Empty) (newGame players)--prop_newGameUsesGivenPlayers :: [Player] -> Bool-prop_newGameUsesGivenPlayers players' = newGame players' ^. players == players'
werewolf.cabal view
@@ -1,5 +1,5 @@ name: werewolf-version: 0.5.1.0+version: 0.5.2.0 author: Henry J. Wylde maintainer: public@hjwylde.com@@ -78,13 +78,14 @@ Game.Werewolf.Command Game.Werewolf.Command.DevotedServant Game.Werewolf.Command.Global+ Game.Werewolf.Command.Hunter+ Game.Werewolf.Command.Orphan Game.Werewolf.Command.Protector Game.Werewolf.Command.Scapegoat Game.Werewolf.Command.Seer Game.Werewolf.Command.Status Game.Werewolf.Command.Villager Game.Werewolf.Command.Werewolf- Game.Werewolf.Command.WildChild Game.Werewolf.Command.Witch Game.Werewolf.Command.WolfHound Game.Werewolf.Engine@@ -135,6 +136,18 @@ Game.Werewolf.Test.Command.See Game.Werewolf.Test.Command.Vote Game.Werewolf.Test.Engine+ Game.Werewolf.Test.Engine.Angel+ Game.Werewolf.Test.Engine.DevotedServant+ Game.Werewolf.Test.Engine.Hunter+ Game.Werewolf.Test.Engine.Lynching+ Game.Werewolf.Test.Engine.Orphan+ Game.Werewolf.Test.Engine.Protector+ Game.Werewolf.Test.Engine.Scapegoat+ Game.Werewolf.Test.Engine.Seer+ Game.Werewolf.Test.Engine.Village+ Game.Werewolf.Test.Engine.Werewolf+ Game.Werewolf.Test.Engine.Witch+ Game.Werewolf.Test.Engine.WolfHound Game.Werewolf.Test.Game Game.Werewolf.Test.Player Game.Werewolf.Test.Util