werewolf 0.5.2.0 → 0.5.3.0
raw patch · 37 files changed
+538/−1390 lines, 37 files
Files
- CHANGELOG.md +18/−0
- README.md +9/−16
- app/Main.hs +0/−2
- app/Werewolf/Command/Choose.hs +0/−2
- app/Werewolf/Command/Help.hs +6/−19
- app/Werewolf/Command/Pass.hs +2/−9
- app/Werewolf/Command/Reveal.hs +0/−44
- app/Werewolf/Game.hs +2/−2
- app/Werewolf/Options.hs +0/−5
- src/Game/Werewolf/Command/DevotedServant.hs +0/−72
- src/Game/Werewolf/Command/Status.hs +14/−16
- src/Game/Werewolf/Command/WolfHound.hs +0/−46
- src/Game/Werewolf/Engine.hs +6/−17
- src/Game/Werewolf/Game.hs +41/−52
- src/Game/Werewolf/Messages.hs +93/−167
- src/Game/Werewolf/Player.hs +28/−60
- src/Game/Werewolf/Role.hs +124/−184
- src/Game/Werewolf/Util.hs +15/−34
- test/src/Game/Werewolf/Test/Arbitrary.hs +35/−111
- test/src/Game/Werewolf/Test/Command.hs +0/−2
- test/src/Game/Werewolf/Test/Command/Choose.hs +1/−69
- test/src/Game/Werewolf/Test/Command/Pass.hs +7/−43
- test/src/Game/Werewolf/Test/Command/Quit.hs +20/−28
- test/src/Game/Werewolf/Test/Command/Reveal.hs +0/−133
- test/src/Game/Werewolf/Test/Engine.hs +14/−18
- test/src/Game/Werewolf/Test/Engine/Angel.hs +0/−39
- test/src/Game/Werewolf/Test/Engine/DevotedServant.hs +0/−57
- test/src/Game/Werewolf/Test/Engine/FallenAngel.hs +39/−0
- test/src/Game/Werewolf/Test/Engine/Lynching.hs +5/−8
- test/src/Game/Werewolf/Test/Engine/Orphan.hs +2/−6
- test/src/Game/Werewolf/Test/Engine/Scapegoat.hs +5/−12
- test/src/Game/Werewolf/Test/Engine/Seer.hs +2/−2
- test/src/Game/Werewolf/Test/Engine/Village.hs +14/−13
- test/src/Game/Werewolf/Test/Engine/Witch.hs +8/−8
- test/src/Game/Werewolf/Test/Engine/WolfHound.hs +0/−56
- test/src/Game/Werewolf/Test/Game.hs +26/−30
- werewolf.cabal +2/−8
CHANGELOG.md view
@@ -2,6 +2,24 @@ ### Upcoming +### v0.5.3.0++*Minor*++* Removed the Devoted Servant. ([#127](https://github.com/hjwylde/werewolf/issues/127))+* Renamed the Angel to the Fallen Angel. ([#130](https://github.com/hjwylde/werewolf/issues/130))+* Renamed the Villager-Villager to the True Villager. ([#137](https://github.com/hjwylde/werewolf/issues/137))+* Removed the Wolf-hound. ([#129](https://github.com/hjwylde/werewolf/issues/129))++*Revisions*++* Changed the Druid's balance to 3. ([#165](https://github.com/hjwylde/werewolf/issues/165))+* Updated the Fallen Angel's description and rules. ([#130](https://github.com/hjwylde/werewolf/issues/130))+* Updated the Simple Werewolf's description. ([#174](https://github.com/hjwylde/werewolf/issues/174))+* Updated the True Villager's description and rules. ([#137](https://github.com/hjwylde/werewolf/issues/137))+* Made the roles gender neutral. ([#101](https://github.com/hjwylde/werewolf/issues/101))+* Made the role descriptions use consistent tenses. ([#158](https://github.com/hjwylde/werewolf/issues/158))+ ### v0.5.2.0 *Minor*
README.md view
@@ -14,11 +14,6 @@ If you're here just to play werewolf, you may wish to skip straight to [chat interfaces](https://github.com/hjwylde/werewolf#chat-interfaces). -DISCLAIMER:-I recently asked the copyright owners of the Werewolves of Millers Hollow if I may have permission- to use some content from the rule book, but they have said no.-I am currently working on removing all copyrighted material from the project.- ### Game description Long has the woods been home to wild creatures, both kind and cruel.@@ -26,7 +21,7 @@ the village has yet to lay eyes on the merciless Werewolf. Each night Werewolves attack the village and devour the innocent.-For centuries no one knew how to fight this scourge, however recently a theory has taken ahold that+For centuries no-one knew how to fight this scourge, however recently a theory has taken ahold that mayhaps the Werewolves walk among the Villagers themselves... Objective of the Game: @@ -44,9 +39,7 @@ The Ambiguous are able to change allegiance throughout the game. -* Devoted Servant * Orphan-* Wolf-hound **The Loners:** @@ -54,7 +47,7 @@ The Loners must complete their own objective. -* Angel+* Fallen Angel **The Villagers:** @@ -72,7 +65,7 @@ * Scapegoat * Seer * Simple Villager-* Villager-Villager+* True Villager * Witch **The Werewolves:**@@ -114,8 +107,8 @@ > werewolf --caller @foo --tag werewolf start --extra-roles seer @bar @baz @qux @quux @corge @grault {"ok":true,"messages":[ {"to":null,"message":"A new game of werewolf is starting with @foo, @bar, @baz, @qux, @quux, @corge, @grault!"},- {"to":null,"message":"The roles in play are Seer (1), Simple Villager (4), Simple Werewolf (2) for a total balance of -2."},- {"to":"@foo","message":"You're a Simple Villager.\nA simple, ordinary townsperson in every way. Their only weapons are the ability to analyze behaviour to identify Werewolves, and the strength of their conviction to prevent the execution of the innocents like themselves."},+ {"to":null,"message":"The roles in play are Seer (1), Simple Villager (4) and Simple Werewolf (2) for a total balance of -2."},+ {"to":"@foo","message":"You're a Simple Villager.\nA simple, ordinary townsperson in every way. Some may be cobblers, others bakers or even nobles. No matter their differences though, the plight of Werewolves in Fougères unites all the Villagers in this unfortunate time.\nThe Simple Villager has no special abilities, they must use their guile to determine whom among them is not who they say they are."}, ..., {"to":null,"message":"Night falls, the village is asleep."}, {"to":null,"message":"The Seer wakes up."},@@ -140,9 +133,9 @@ > werewolf --caller @corge --tag werewolf see @grault {"ok":true,"messages":[ {"to":"@corge","message":"@grault is aligned with the Werewolves."},- {"to":"@quux","message":"You feel restless, like an old curse is keeping you from sleep. It seems you're not the only one... @grault are also emerging from their homes."},- {"to":"@grault","message":"You feel restless, like an old curse is keeping you from sleep. It seems you're not the only one... @quux are also emerging from their homes."},- {"to":null,"message":"The Werewolves wake up, recognise one another and choose a new victim."},+ {"to":"@quux","message":"You feel restless, like an old curse is keeping you from sleep. It seems you're not the only one... @grault is also emerging from their home."},+ {"to":"@grault","message":"You feel restless, like an old curse is keeping you from sleep. It seems you're not the only one... @quux is also emerging from their home."},+ {"to":null,"message":"The Werewolves wake up, transform and choose a new victim."}, {"to":"@quux","message":"Whom would you like to `vote` to devour?"}, {"to":"@grault","message":"Whom would you like to `vote` to devour?"} ]}@@ -160,7 +153,7 @@ {"to":"@quux","message":"@grault voted to devour @foo."}, {"to":null,"message":"The sun rises. Everybody wakes up and opens their eyes..."}, {"to":null,"message":"As you open them you notice a door broken down and @foo's guts half devoured and spilling out over the cobblestones. From the look of their personal effects, you deduce they were a Simple Villager."},- {"to":null,"message":"As the village gathers in the square the town clerk calls for a vote."},+ {"to":null,"message":"As the village gathers in the square the Town Clerk calls for a vote."}, {"to":null,"message":"Whom would you like to `vote` to lynch?"} ]} ```
app/Main.hs view
@@ -32,7 +32,6 @@ import qualified Werewolf.Command.Poison as Poison import qualified Werewolf.Command.Protect as Protect import qualified Werewolf.Command.Quit as Quit-import qualified Werewolf.Command.Reveal as Reveal import qualified Werewolf.Command.See as See import qualified Werewolf.Command.Start as Start import qualified Werewolf.Command.Status as Status@@ -68,7 +67,6 @@ Poison options -> Poison.handle callerName tag options Protect options -> Protect.handle callerName tag options Quit -> Quit.handle callerName tag- Reveal -> Reveal.handle callerName tag See options -> See.handle callerName tag options Start options -> Start.handle callerName tag options Status -> Status.handle callerName tag
app/Werewolf/Command/Choose.hs view
@@ -31,7 +31,6 @@ 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.WolfHound as WolfHound import Werewolf.Game import Werewolf.Messages@@ -53,7 +52,6 @@ HuntersTurn2 -> return $ Hunter.chooseCommand callerName (head args) OrphansTurn -> return $ Orphan.chooseCommand callerName (head args) ScapegoatsTurn -> return $ Scapegoat.chooseCommand callerName args- WolfHoundsTurn -> return $ WolfHound.chooseCommand callerName (head args) _ -> exitWith failure { messages = [playerCannotDoThatRightNowMessage callerName] }
app/Werewolf/Command/Help.hs view
@@ -87,11 +87,6 @@ , [ "Standard commands:" , "- `vote PLAYER`" ]- , whenPlayerHasRole callerName mGame devotedServantRole- [ "Devoted Servant commands:"- , "- `reveal`"- , "- `pass`"- ] , whenPlayerHasRole callerName mGame hunterRole [ "Hunter commands:" , "- `choose PLAYER`"@@ -118,10 +113,6 @@ , "- `poison PLAYER`" , "- `pass`" ]- , whenPlayerHasRole callerName mGame wolfHoundRole- [ "Wolf-hound commands:"- , "- `choose (villagers | werewolves)`"- ] ] roleMessage :: Role -> Text@@ -151,11 +142,11 @@ , filter (/= "") [ T.concat [ "Each player is informed of their role (see `help roles` for a list) at the start of the" , "game. A game begins at night and follows a standard cycle."- , whenRoleInPlay mGame angelRole- " (N.B., when the Angel is in play the game begins with the village vote.)"+ , whenRoleInPlay mGame fallenAngelRole+ " (N.B., when the Fallen Angel is in play the game begins with the village vote.)" ]- , whenRoleInPlay mGame angelRole- "- (When the Angel is in play) the village votes to lynch a suspect."+ , whenRoleInPlay mGame fallenAngelRole+ "- (When the Fallen Angel is in play) the village votes to lynch a suspect." , "- The village falls asleep." , whenRoleInPlay mGame orphanRole "- (First round only) the Orphan wakes up and chooses a role model."@@ -163,8 +154,6 @@ "- The Protector wakes up and protects someone." , whenRoleInPlay mGame seerRole "- The Seer wakes up and sees someone's allegiance."- , whenRoleInPlay mGame wolfHoundRole- "- (First round only) the Wolf-hound wakes up and chooses an allegiance." , "- The Werewolves wake up and vote to devour a victim." , whenRoleInPlay mGame witchRole "- The Witch wakes up and may heal the victim and/or poison someone."@@ -174,15 +163,13 @@ , 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 [ "The game is over when only Villagers or Werewolves are left alive"- , ifRoleInPlay mGame angelRole+ , ifRoleInPlay mGame fallenAngelRole ", or when one of the Loners completes their own objective." "." ]@@ -197,7 +184,7 @@ , "village has yet to lay eyes on the merciless Werewolf." ] , T.unwords- [ "Each night Werewolves attack the village and devour the innocent. For centuries no one"+ [ "Each night Werewolves attack the village and devour the innocent. For centuries no-one" , "knew how to fight this scourge, however recently a theory has taken ahold that mayhaps" , "the Werewolves walk among the Villagers themselves..." ]
app/Werewolf/Command/Pass.hs view
@@ -14,7 +14,6 @@ handle, ) where -import Control.Lens import Control.Monad.Except import Control.Monad.Extra import Control.Monad.State@@ -23,8 +22,7 @@ import Data.Text (Text) import Game.Werewolf-import Game.Werewolf.Command.DevotedServant as DevotedServant-import Game.Werewolf.Command.Witch as Witch+import Game.Werewolf.Command.Witch import Werewolf.Game import Werewolf.Messages@@ -37,12 +35,7 @@ game <- readGame tag - command <- case game ^. stage of- DevotedServantsTurn -> return $ DevotedServant.passCommand callerName- WitchsTurn -> return $ Witch.passCommand callerName- _ -> exitWith failure- { messages = [playerCannotDoThatRightNowMessage callerName]- }+ let command = passCommand callerName case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of Left errorMessages -> exitWith failure { messages = errorMessages }
− app/Werewolf/Command/Reveal.hs
@@ -1,44 +0,0 @@-{-|-Module : Werewolf.Command.Reveal-Description : Handler for the reveal subcommand.--Copyright : (c) Henry J. Wylde, 2016-License : BSD3-Maintainer : public@hjwylde.com--Handler for the reveal subcommand.--}--{-# LANGUAGE OverloadedStrings #-}--module Werewolf.Command.Reveal (- -- * Handle- handle,-) where--import Control.Monad.Except-import Control.Monad.Extra-import Control.Monad.State-import Control.Monad.Writer--import Data.Text (Text)--import Game.Werewolf-import Game.Werewolf.Command.DevotedServant--import Werewolf.Game-import Werewolf.Messages--handle :: MonadIO m => Text -> Text -> m ()-handle callerName tag = do- unlessM (doesGameExist tag) $ exitWith failure- { messages = [noGameRunningMessage callerName]- }-- game <- readGame tag-- let command = revealCommand callerName-- case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of- Left errorMessages -> exitWith failure { messages = errorMessages }- Right (game', messages) -> writeOrDeleteGame tag game' >> exitWith success { messages = messages }
app/Werewolf/Game.hs view
@@ -24,8 +24,8 @@ import Control.Monad.Except import Control.Monad.Random -import Data.List.Extra-import Data.Text (Text)+import Data.List.Extra+import Data.Text (Text) import qualified Data.Text as T import Game.Werewolf
app/Werewolf/Options.hs view
@@ -57,7 +57,6 @@ | Poison Poison.Options | Protect Protect.Options | Quit- | Reveal | See See.Options | Start Start.Options | Status@@ -108,7 +107,6 @@ , command "poison" $ info (helper <*> poison) (fullDesc <> progDesc "Poison a player") , command "protect" $ info (helper <*> protect) (fullDesc <> progDesc "Protect a player") , command "quit" $ info (helper <*> quit) (fullDesc <> progDesc "Quit the current game")- , command "reveal" $ info (helper <*> reveal) (fullDesc <> progDesc "Reveal yourself") , command "see" $ info (helper <*> see) (fullDesc <> progDesc "See a player's allegiance") , command "start" $ info (helper <*> start) (fullDesc <> progDesc "Start a new game") , command "status" $ info (helper <*> status) (fullDesc <> progDesc "Get the status of the current game")@@ -167,9 +165,6 @@ quit :: Parser Command quit = pure Quit--reveal :: Parser Command-reveal = pure Reveal see :: Parser Command see = See . See.Options <$> playerArgument
− src/Game/Werewolf/Command/DevotedServant.hs
@@ -1,72 +0,0 @@-{-|-Module : Game.Werewolf.Command.DevotedServant-Description : Devoted Servant commands.--Copyright : (c) Henry J. Wylde, 2016-License : BSD3-Maintainer : public@hjwylde.com--Devoted Servant commands.--}--{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE MultiParamTypeClasses #-}--module Game.Werewolf.Command.DevotedServant (- -- * Commands- passCommand, revealCommand,-) where--import Control.Lens-import Control.Monad.Except-import Control.Monad.Extra-import Control.Monad.State hiding (state)-import Control.Monad.Writer--import Data.List-import Data.Text (Text)--import Game.Werewolf hiding (getVoteResult)-import Game.Werewolf.Messages-import Game.Werewolf.Util--passCommand :: Text -> Command-passCommand callerName = Command $ do- validateCommand callerName-- passed .= True--revealCommand :: Text -> Command-revealCommand callerName = Command $ do- validateCommand callerName-- target <- head <$> getVoteResult-- let targetRole = target ^. role- let targetName = target ^. name-- setPlayerRole callerName targetRole- setPlayerRole targetName devotedServantRole-- tell [devotedServantRevealedMessage callerName]- tell [roleTakenMessage callerName targetRole]-- resetRole callerName targetRole--validateCommand :: (MonadError [Message] m, MonadState Game m) => Text -> m ()-validateCommand callerName = do- validatePlayer callerName callerName- unlessM (isPlayerDevotedServant callerName) $ throwError [playerCannotDoThatMessage callerName]- unlessM isDevotedServantsTurn $ throwError [playerCannotDoThatRightNowMessage callerName]--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 == witchRole = healUsed .= False >> poisonUsed .= False- | role == wolfHoundRole = allegianceChosen .= False- | otherwise = return ()
src/Game/Werewolf/Command/Status.hs view
@@ -39,22 +39,20 @@ pingCommand :: Text -> Command pingCommand callerName = Command $ use stage >>= \stage' -> case stage' of- DevotedServantsTurn -> pingRole devotedServantRole- FerinasGrunt -> return ()- GameOver -> tell [gameIsOverMessage callerName]- HuntersTurn1 -> pingRole hunterRole- HuntersTurn2 -> pingRole hunterRole- Lynching -> return ()- OrphansTurn -> pingRole orphanRole- ProtectorsTurn -> pingRole protectorRole- ScapegoatsTurn -> pingRole scapegoatRole- SeersTurn -> pingRole seerRole- Sunrise -> return ()- Sunset -> return ()- VillagesTurn -> pingVillagers- WerewolvesTurn -> pingWerewolves- WitchsTurn -> pingRole witchRole- WolfHoundsTurn -> pingRole wolfHoundRole+ FerinasGrunt -> return ()+ GameOver -> tell [gameIsOverMessage callerName]+ HuntersTurn1 -> pingRole hunterRole+ HuntersTurn2 -> pingRole hunterRole+ Lynching -> return ()+ OrphansTurn -> pingRole orphanRole+ ProtectorsTurn -> pingRole protectorRole+ ScapegoatsTurn -> pingRole scapegoatRole+ SeersTurn -> pingRole seerRole+ Sunrise -> return ()+ Sunset -> return ()+ VillagesTurn -> pingVillagers+ WerewolvesTurn -> pingWerewolves+ WitchsTurn -> pingRole witchRole pingRole :: (MonadState Game m, MonadWriter [Message] m) => Role -> m () pingRole role' = do
− src/Game/Werewolf/Command/WolfHound.hs
@@ -1,46 +0,0 @@-{-|-Module : Game.Werewolf.Command.WolfHound-Description : Wolf-hound commands.--Copyright : (c) Henry J. Wylde, 2016-License : BSD3-Maintainer : public@hjwylde.com--Wolf-hound commands.--}--{-# LANGUAGE OverloadedStrings #-}--module Game.Werewolf.Command.WolfHound (- -- * Commands- chooseCommand,-) where--import Control.Lens-import Control.Monad.Except-import Control.Monad.Extra--import Data.Maybe-import Data.Text (Text)-import qualified Data.Text as T--import Game.Werewolf-import Game.Werewolf.Messages-import Game.Werewolf.Util--chooseCommand :: Text -> Text -> Command-chooseCommand callerName allegianceName = Command $ do- validatePlayer callerName callerName- unlessM (isPlayerWolfHound callerName) $ throwError [playerCannotDoThatMessage callerName]- unlessM isWolfHoundsTurn $ throwError [playerCannotDoThatRightNowMessage callerName]- when (isNothing mAllegiance) $ throwError [allegianceDoesNotExistMessage callerName allegianceName]-- setPlayerAllegiance callerName allegiance-- allegianceChosen .= True- where- allegiance = fromJust mAllegiance- mAllegiance = case T.toLower allegianceName of- "villagers" -> Just Villagers- "werewolves" -> Just Werewolves- _ -> Nothing
src/Game/Werewolf/Engine.hs view
@@ -34,8 +34,8 @@ import qualified Data.Text as T import Game.Werewolf.Game hiding (doesPlayerExist, getAllowedVoters, getPendingVoters,- getVoteResult, hasAngelWon, hasAnyoneWon, hasVillagersWon,- hasWerewolvesWon, killPlayer)+ getVoteResult, hasAnyoneWon, hasFallenAngelWon,+ hasVillagersWon, hasWerewolvesWon, killPlayer) import Game.Werewolf.Messages import Game.Werewolf.Player import Game.Werewolf.Response@@ -67,12 +67,6 @@ checkStage' :: (MonadState Game m, MonadWriter [Message] m) => m () checkStage' = use stage >>= \stage' -> case stage' of- DevotedServantsTurn -> do- whenM (has (players . devotedServants . dead) <$> get) advanceStage-- whenM (has devotedServants <$> getVoteResult) advanceStage- whenM (use passed) advanceStage- FerinasGrunt -> do druid <- findPlayerBy_ role druidRole players' <- getAdjacentAlivePlayers (druid ^. name)@@ -129,11 +123,11 @@ Sunrise -> do round += 1 - whenJustM (preuse $ players . angels . alive) $ \angel ->- unless (is villager angel) $ do- tell [angelJoinedVillagersMessage]+ whenJustM (preuse $ players . fallenAngels . alive) $ \fallenAngel ->+ unless (is villager fallenAngel) $ do+ tell [fallenAngelJoinedVillagersMessage] - setPlayerAllegiance (angel ^. name) Villagers+ setPlayerAllegiance (fallenAngel ^. name) Villagers advanceStage @@ -178,11 +172,6 @@ whenM (use healUsed &&^ use poisonUsed) advanceStage whenM (use passed) advanceStage-- WolfHoundsTurn -> do- whenM (has (players . wolfHounds . dead) <$> get) advanceStage-- whenM (use allegianceChosen) advanceStage lynchVotees :: (MonadState Game m, MonadWriter [Message] m) => [Player] -> m () lynchVotees [votee]
src/Game/Werewolf/Game.hs view
@@ -17,14 +17,14 @@ module Game.Werewolf.Game ( -- * Game Game,- stage, round, players, events, boots, allegianceChosen, allowedVoters, heal, healUsed,- hunterRetaliated, jesterRevealed, passed, poison, poisonUsed, priorProtect, protect, roleModel,- scapegoatBlamed, see, votes,+ stage, round, players, events, boots, allowedVoters, heal, healUsed, hunterRetaliated,+ jesterRevealed, passed, poison, poisonUsed, priorProtect, protect, roleModel, scapegoatBlamed,+ see, votes, Stage(..),- _DevotedServantsTurn, _FerinasGrunt, _GameOver, _HuntersTurn1, _HuntersTurn2, _Lynching,- _OrphansTurn, _ProtectorsTurn, _ScapegoatsTurn, _SeersTurn, _Sunrise, _Sunset, _VillagesTurn,- _WerewolvesTurn, _WitchsTurn, _WolfHoundsTurn,+ _FerinasGrunt, _GameOver, _HuntersTurn1, _HuntersTurn2, _Lynching, _OrphansTurn,+ _ProtectorsTurn, _ScapegoatsTurn, _SeersTurn, _Sunrise, _Sunset, _VillagesTurn, _WerewolvesTurn,+ _WitchsTurn, allStages, stageCycle, stageAvailable,@@ -43,7 +43,7 @@ -- ** Queries isFirstRound, doesPlayerExist,- hasAnyoneWon, hasAngelWon, hasVillagersWon, hasWerewolvesWon,+ hasAnyoneWon, hasFallenAngelWon, hasVillagersWon, hasWerewolvesWon, ) where import Control.Lens hiding (isn't)@@ -86,13 +86,12 @@ , _players :: [Player] , _events :: [Event] , _boots :: Map Text [Text]- , _allegianceChosen :: Bool -- ^ Wolf-hound , _allowedVoters :: [Text] -- ^ Scapegoat , _heal :: Bool -- ^ Witch , _healUsed :: Bool -- ^ Witch , _hunterRetaliated :: Bool -- ^ Hunter , _jesterRevealed :: Bool -- ^ Jester- , _passed :: Bool -- ^ Devoted Servant, Witch+ , _passed :: Bool -- ^ Witch , _poison :: Maybe Text -- ^ Witch , _poisonUsed :: Bool -- ^ Witch , _priorProtect :: Maybe Text -- ^ Protector@@ -109,9 +108,9 @@ -- -- 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 | HuntersTurn1 | HuntersTurn2 | Lynching- | OrphansTurn | ProtectorsTurn | ScapegoatsTurn | SeersTurn | Sunrise | Sunset- | VillagesTurn | WerewolvesTurn | WitchsTurn | WolfHoundsTurn+data Stage = FerinasGrunt | GameOver | HuntersTurn1 | HuntersTurn2 | Lynching | OrphansTurn+ | ProtectorsTurn | ScapegoatsTurn | SeersTurn | Sunrise | Sunset | VillagesTurn+ | WerewolvesTurn | WitchsTurn deriving (Eq, Read, Show) -- TODO (hjw): remove events@@ -137,12 +136,10 @@ allStages :: [Stage] allStages = [ VillagesTurn- , DevotedServantsTurn , Lynching , HuntersTurn1 , ScapegoatsTurn , Sunset- , WolfHoundsTurn , SeersTurn , OrphansTurn , ProtectorsTurn@@ -161,13 +158,9 @@ -- | Checks whether the stage is available for the given 'Game'. Most often this just involves -- checking if there is an applicable role alive, but sometimes it is more complex. ----- One of the more complex checks here is for the 'VillagesTurn'. If the Angel is in play, then--- the 'VillagesTurn' is available on the first day rather than only after the first night.+-- One of the more complex checks here is for the 'VillagesTurn'. If the Fallen Angel is in play,+-- then the 'VillagesTurn' is available on the first day rather than only after the first night. stageAvailable :: Game -> Stage -> Bool-stageAvailable game DevotedServantsTurn =- has (players . devotedServants . alive) game- && length (getVoteResult game) == 1- && isn't devotedServant (head $ getVoteResult game) stageAvailable game FerinasGrunt = has (players . druids . alive) game stageAvailable _ GameOver = False stageAvailable game HuntersTurn1 =@@ -183,7 +176,7 @@ stageAvailable _ Sunrise = True stageAvailable _ Sunset = True stageAvailable game VillagesTurn =- (has (players . angels . alive) game || not (isFirstRound game))+ (has (players . fallenAngels . alive) game || not (isFirstRound game)) && any (is alive) (getAllowedVoters game) stageAvailable game WerewolvesTurn = has (players . werewolves . alive) game stageAvailable game OrphansTurn =@@ -192,9 +185,6 @@ stageAvailable game WitchsTurn = has (players . witches . alive) game && (not (game ^. healUsed) || not (game ^. poisonUsed))-stageAvailable game WolfHoundsTurn =- has (players . wolfHounds . alive) game- && not (game ^. allegianceChosen) -- | Creates a new 'Game' with the given players. No validations are performed here, those are left -- to 'Game.Werewolf.Engine.startGame'.@@ -202,26 +192,25 @@ newGame players = game & stage .~ head (filter (stageAvailable game) stageCycle) where game = Game- { _stage = Sunset- , _round = 0- , _players = players- , _events = []- , _boots = Map.empty- , _passed = False- , _allegianceChosen = False- , _allowedVoters = players ^.. names- , _heal = False- , _healUsed = False- , _hunterRetaliated = False- , _jesterRevealed = False- , _poison = Nothing- , _poisonUsed = False- , _priorProtect = Nothing- , _protect = Nothing- , _roleModel = Nothing- , _scapegoatBlamed = False- , _see = Nothing- , _votes = Map.empty+ { _stage = Sunset+ , _round = 0+ , _players = players+ , _events = []+ , _boots = Map.empty+ , _passed = False+ , _allowedVoters = players ^.. names+ , _heal = False+ , _healUsed = False+ , _hunterRetaliated = False+ , _jesterRevealed = False+ , _poison = Nothing+ , _poisonUsed = False+ , _priorProtect = Nothing+ , _protect = Nothing+ , _roleModel = Nothing+ , _scapegoatBlamed = False+ , _see = Nothing+ , _votes = Map.empty } -- | Kills the given player! This function should be used carefully as it doesn't clear any state@@ -262,17 +251,17 @@ -- | Queries whether anyone has won. hasAnyoneWon :: Game -> Bool-hasAnyoneWon game = any ($ game) [hasAngelWon, hasVillagersWon, hasWerewolvesWon]+hasAnyoneWon game = any ($ game) [hasFallenAngelWon, hasVillagersWon, hasWerewolvesWon] --- | Queries whether the Angel has won. The Angel wins if they manage to get themselves killed on--- the first round.+-- | Queries whether the Fallen Angel has won. The Fallen Angel wins if they manage to get+-- themselves killed on the first round. ----- N.B., we check that the Angel isn't a 'villager' as the Angel's role is altered if they don't--- win.-hasAngelWon :: Game -> Bool-hasAngelWon game = has (players . angels) game && is dead angel && isn't villager angel+-- N.B., we check that the Fallen Angel isn't a 'villager' as the Fallen Angel's role is altered+-- if they don't win.+hasFallenAngelWon :: Game -> Bool+hasFallenAngelWon game = has (players . fallenAngels) game && is dead fallenAngel && isn't villager fallenAngel where- angel = game ^?! players . angels+ fallenAngel = game ^?! players . fallenAngels -- | Queries whether the 'Villagers' have won. The 'Villagers' win if they are the only players -- surviving.
src/Game/Werewolf/Messages.hs view
@@ -40,15 +40,12 @@ -- * Status messages currentStageMessages, rolesInGameMessage, playersInGameMessage, waitingOnMessage, - -- * Angel's turn messages- angelJoinedVillagersMessage,-- -- * Devoted Servant's turn messages- devotedServantRevealedMessage, roleTakenMessage, devotedServantJoinedPackMessages,- -- * Druid's turn messages ferinaGruntsMessage, + -- * Fallen Angel's turn messages+ fallenAngelJoinedVillagersMessage,+ -- * Hunter's turn messages playerShotMessage, @@ -90,11 +87,6 @@ -- ** Error messages playerHasAlreadyHealedMessage, playerHasAlreadyPoisonedMessage,-- -- * Wolf-hound's turn messages-- -- ** Error messages- allegianceDoesNotExistMessage, ) where import Control.Arrow@@ -115,20 +107,18 @@ [ [newPlayersInGameMessage $ players' ^.. names] , [rolesInGameMessage Nothing $ players' ^.. roles] , map newPlayerMessage players'- , villagerVillagerMessages+ , trueVillagerMessages , stageMessages game ] where- players' = game ^. players- villagerVillagerMessages = case players' ^? villagerVillagers of- Just villagerVillager -> [villagerVillagerMessage $ villagerVillager ^. name]- _ -> []+ players' = game ^. players+ trueVillagerMessages = case players' ^? trueVillagers of+ Just trueVillager -> [trueVillagerMessage $ trueVillager ^. name]+ _ -> [] newPlayersInGameMessage :: [Text] -> Message newPlayersInGameMessage playerNames = publicMessage $ T.concat- [ "A new game of werewolf is starting with "- , concatList playerNames, "!"- ]+ ["A new game of werewolf is starting with ", concatList playerNames, "!"] newPlayerMessage :: Player -> Message newPlayerMessage player = privateMessage (player ^. name) $ T.intercalate "\n"@@ -139,60 +129,45 @@ where playerRole = player ^. role -villagerVillagerMessage :: Text -> Message-villagerVillagerMessage name = publicMessage $ T.unwords- [ "Unguarded advice is seldom given, for advice is a dangerous gift,"- , "even from the wise to the wise, and all courses may run ill."- , "Yet as you feel like you need help, I begrudgingly leave you with this:"- , name, "is the Villager-Villager."+trueVillagerMessage :: Text -> Message+trueVillagerMessage name = publicMessage $ T.unwords+ [ "Unguarded advice is seldom given, for advice is a dangerous gift, even from the wise to the"+ , "wise, and all courses may run ill. Yet as you feel like you need help, I begrudgingly leave"+ , "you with this:", name, "is the True Villager." ] stageMessages :: Game -> [Message] stageMessages game = case game ^. stage of- 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- Sunrise -> [sunriseMessage]- Sunset -> [nightFallsMessage]- VillagesTurn -> if isFirstRound game+ FerinasGrunt -> []+ GameOver -> []+ HuntersTurn1 -> huntersTurnMessages huntersName+ HuntersTurn2 -> huntersTurnMessages huntersName+ Lynching -> []+ OrphansTurn -> orphansTurnMessages orphansName+ ProtectorsTurn -> protectorsTurnMessages protectorsName+ ScapegoatsTurn -> scapegoatsTurnMessages scapegoatsName+ SeersTurn -> seersTurnMessages seersName+ Sunrise -> [sunriseMessage]+ Sunset -> [nightFallsMessage]+ VillagesTurn -> if isFirstRound game then firstVillagesTurnMessages else villagesTurnMessages- WerewolvesTurn -> if isFirstRound game+ WerewolvesTurn -> if isFirstRound game then firstWerewolvesTurnMessages aliveWerewolfNames else werewolvesTurnMessages aliveWerewolfNames- WitchsTurn -> witchsTurnMessages game- WolfHoundsTurn -> wolfHoundsTurnMessages wolfHoundsName+ WitchsTurn -> witchsTurnMessages game where players' = game ^. players- 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- wolfHoundsName = players' ^?! wolfHounds . name -devotedServantsTurnMessages :: Text -> Text -> [Message]-devotedServantsTurnMessages to victimsName =- [ publicMessage "The Devoted Servant ponders."- , privateMessage to $ T.concat- [ "Would you like to `reveal` yourself and take on ", victimsName, "'s role?"- , " (Or you can type `pass`.)"- ]- ]- huntersTurnMessages :: Text -> [Message] huntersTurnMessages huntersName =- [ publicMessage $ T.unwords ["Just before", huntersName, "was struck down he let off a shot."]+ [ publicMessage $ T.unwords ["Just before", huntersName, "was murdered they let off a shot."] , privateMessage huntersName "Whom do you `choose` to kill with your last shot?" ] @@ -210,7 +185,7 @@ scapegoatsTurnMessages :: Text -> [Message] scapegoatsTurnMessages scapegoatsName =- [ publicMessage "Just before he burns to a complete crisp, he cries out a dying wish."+ [ publicMessage "Just before the Scapegoat burns to a complete crisp, they cry out a dying wish." , publicMessage $ T.concat [scapegoatsName, ", whom do you `choose` to vote on the next day?"] ] @@ -227,17 +202,17 @@ nightFallsMessage = publicMessage "Night falls, the village is asleep." firstVillagesTurnMessages :: [Message]-firstVillagesTurnMessages = angelInPlayMessage : villagesTurnMessages+firstVillagesTurnMessages = fallenAngelInPlayMessage : villagesTurnMessages where- angelInPlayMessage = publicMessage $ T.unwords- [ "Alas, again I regrettably yield advice: an angelic menace walks among you."- , "Do not cast your votes lightly,"- , "for he will relish in this opportunity to be free from his terrible nightmare."+ fallenAngelInPlayMessage = publicMessage $ T.unwords+ [ "Alas, again I regrettably yield advice: an angelic menace walks among you. Do not"+ , "cast your votes lightly, for they will relish in this opportunity to be free from"+ , "their terrible nightmare." ] villagesTurnMessages :: [Message] villagesTurnMessages =- [ publicMessage "As the village gathers in the square the town clerk calls for a vote."+ [ publicMessage "As the village gathers in the square the Town Clerk calls for a vote." , publicMessage "Whom would you like to `vote` to lynch?" ] @@ -247,9 +222,8 @@ ++ werewolvesTurnMessages tos where packMessage werewolfName = T.unwords- [ "You feel restless, like an old curse is keeping you from sleep."- , "It seems you're not the only one..."- , packNames werewolfName+ [ "You feel restless, like an old curse is keeping you from sleep. It seems you're not"+ , "the only one...", packNames werewolfName , conjugateToBe (length tos - 1), "also emerging from their" , tryPlural (length tos - 1) "home" ]@@ -286,30 +260,23 @@ | game ^. poisonUsed = [] | otherwise = [privateMessage witchsName "Would you like to `poison` anyone?"] -wolfHoundsTurnMessages :: Text -> [Message]-wolfHoundsTurnMessages to =- [ publicMessage "The Wolf-hound wakes up."- , privateMessage to- "Which allegiance do you `choose` to be aligned with? (Either `villagers` or `werewolves`.)"- ]- gameOverMessages :: Game -> [Message] gameOverMessages game- | hasAngelWon game = concat- [ [publicMessage "You should have heeded my warning, for now the Angel has been set free!"]- , [publicMessage "The game is over! The Angel has won."]+ | hasFallenAngelWon game = concat+ [ [publicMessage "You should have heeded my warning, for now the Fallen Angel has been set free!"]+ , [publicMessage "The game is over! The Fallen Angel has won."] , [playerRolesMessage]- , playerWonMessages+ , [playerWonMessage $ game ^?! players . fallenAngels . name] , playerLostMessages ]- | hasVillagersWon game = concat+ | hasVillagersWon game = concat [ [publicMessage "The game is over! The Villagers have won."] , [playerRolesMessage] , playerWonMessages , playerContributedMessages , playerLostMessages ]- | hasWerewolvesWon game = concat+ | hasWerewolvesWon game = concat [ [publicMessage "The game is over! The Werewolves have won."] , [playerRolesMessage] , playerWonMessages@@ -327,10 +294,10 @@ ] winningAllegiance- | hasAngelWon game = Angel- | hasVillagersWon game = Villagers- | hasWerewolvesWon game = Werewolves- | otherwise = undefined+ | hasFallenAngelWon game = FallenAngel+ | hasVillagersWon game = Villagers+ | hasWerewolvesWon game = Werewolves+ | otherwise = undefined winningPlayers = game ^.. players . traverse . filteredBy (role . allegiance) winningAllegiance losingPlayers = game ^. players \\ winningPlayers@@ -414,22 +381,20 @@ ]] where showTurn :: Stage -> Text- 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"- showTurn Sunrise = undefined- showTurn Sunset = undefined- showTurn VillagesTurn = "village's"- showTurn WerewolvesTurn = "Werewolves'"- showTurn WitchsTurn = "Witch's"- showTurn WolfHoundsTurn = "Wolf-hound'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"+ showTurn Sunrise = undefined+ showTurn Sunset = undefined+ showTurn VillagesTurn = "village's"+ showTurn WerewolvesTurn = "Werewolves'"+ showTurn WitchsTurn = "Witch's" rolesInGameMessage :: Maybe Text -> [Role] -> Message rolesInGameMessage mTo roles = Message mTo $ T.concat@@ -452,7 +417,7 @@ alivePlayersText = T.concat [ "The following players are still alive: "- , concatList $ map (\player -> if is villagerVillager player then playerNameWithRole player else player ^. name) alivePlayers, "."+ , concatList $ map (\player -> if is trueVillager player then playerNameWithRole player else player ^. name) alivePlayers, "." ] deadPlayersText = T.concat [ "The following players are dead: "@@ -464,49 +429,15 @@ waitingOnMessage mTo playerNames = Message mTo $ T.concat ["Waiting on ", concatList playerNames, "..."] -angelJoinedVillagersMessage :: Message-angelJoinedVillagersMessage = publicMessage $ T.unwords- [ "You hear the Angel wrought with anger off in the distance."- , "He failed to attract the discriminatory vote of the village"- , "or the devouring vindictiveness of the lycanthropes."- , "Now he is stuck here, doomed forever to live out a mortal life as a Villager."- ]--devotedServantRevealedMessage :: Text -> Message-devotedServantRevealedMessage devotedServantsName = publicMessage $ T.unwords- [ "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)- : groupMessages werewolfNames (T.unwords- [ devotedServantsName, "heads towards the woods in search of his master's home and family."- ])- where- masterWasWerewolfMessage = T.unwords- [ "Upon learning your master was a Werewolf,"- , "you head towards the woods to learn more about his home and family."- ]- packMessages- | null werewolfNames = []- | otherwise =- [ T.unwords- ["As you enter you see his pack", concatList werewolfNames , "waiting for you."]- ]- ferinaGruntsMessage :: Message-ferinaGruntsMessage = publicMessage $ T.unwords- [ "Ferina wakes from her slumber, disturbed and on edge."- , "She loudly grunts as she smells danger."+ferinaGruntsMessage = publicMessage+ "Ferina wakes from her slumber, disturbed and on edge. She loudly grunts as she smells danger."++fallenAngelJoinedVillagersMessage :: Message+fallenAngelJoinedVillagersMessage = publicMessage $ T.unwords+ [ "You hear the Fallen Angel wrought with anger off in the distance. They failed to attract the"+ , "prejudiced vote of the village to leave this world. Now they are stuck here, doomed forever"+ , "to live out a mortal life as a Villager." ] playerShotMessage :: Player -> Message@@ -521,15 +452,14 @@ 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."+ [ "The death of your role model is distressing. Without second thought you abandon the"+ , "Villagers and run off into the woods, towards a new home. As you arrive you see the"+ , tryPlural (length werewolfNames) "face", "of"+ , concatList werewolfNames, "waiting for you." ]) : groupMessages werewolfNames (T.unwords- [ orphansName, "the Orphan scampers off into the woods."- , "Without their role model nothing is holding back their true, wolfish, nature."+ [ orphansName, "the Orphan scampers off into the woods. Without their role model they have"+ , "abandoned the village and are in search of a new home. You welcome them into your pack." ]) playerCannotProtectSamePlayerTwiceInARowMessage :: Text -> Message@@ -538,8 +468,8 @@ scapegoatChoseAllowedVotersMessage :: [Text] -> Message scapegoatChoseAllowedVotersMessage allowedVoters = publicMessage $ T.unwords- [ "On the next day only", concatList allowedVoters, "shall be allowed to vote."- , "The town crier, realising how foolish it was to kill him, grants him this wish."+ [ "On the next day only", concatList allowedVoters, "shall be allowed to vote. The Town Crier,"+ , "realising how foolish it was to kill the Scapegoat, grants them this wish." ] playerMustChooseAtLeastOneTargetMessage :: Text -> Message@@ -552,11 +482,13 @@ playerSeenMessage :: Text -> Player -> Message playerSeenMessage to target = privateMessage to $ T.concat- [ targetName, " is aligned with the ", T.pack $ show allegiance', "."- ]+ [targetName, " is aligned with the ", allegiance', "."] where targetName = target ^. name- allegiance' = target ^. role . allegiance+ allegiance' = case target ^. role . allegiance of+ FallenAngel -> "Fallen Angel"+ Villagers -> "Villagers"+ Werewolves -> "Werewolves" playerMadeLynchVoteMessage :: Text -> Text -> Message playerMadeLynchVoteMessage voterName targetName = publicMessage $ T.concat@@ -566,16 +498,15 @@ playerLynchedMessage :: Player -> Message playerLynchedMessage player | is simpleWerewolf player = publicMessage $ T.concat- [ playerName, " is tied up to a pyre and set alight."- , " As they scream their body starts to contort and writhe, transforming into "- , article playerRole, " ", playerRole ^. Role.name, "."- , " Thankfully they go limp before breaking free of their restraints."+ [ playerName, " is tied up to a pyre and set alight. As they scream their body starts to "+ , "contort and writhe, transforming into ", article playerRole, " "+ , playerRole ^. Role.name, ".", " Thankfully they go limp before breaking free of their "+ , "restraints." ] | otherwise = publicMessage $ T.concat- [ playerName, " is tied up to a pyre and set alight."- , " Eventually the screams start to die and with their last breath,"- , " they reveal themselves as "- , article playerRole, " ", playerRole ^. Role.name, "."+ [ playerName, " is tied up to a pyre and set alight. Eventually the screams start to die "+ , "and with their last breath, they reveal themselves as ", article playerRole, " "+ , playerRole ^. Role.name, "." ] where playerName = player ^. name@@ -583,8 +514,8 @@ noPlayerLynchedMessage :: Message noPlayerLynchedMessage = publicMessage $ T.unwords- [ "Daylight is wasted as the townsfolk squabble over whom to tie up."- , "Looks like no-one is being burned this day."+ [ "Daylight is wasted as the townsfolk squabble over whom to tie up. Looks like no-one is being"+ , "burned this day." ] jesterLynchedMessage :: Text -> Message@@ -646,11 +577,6 @@ playerHasAlreadyPoisonedMessage :: Text -> Message playerHasAlreadyPoisonedMessage to = privateMessage to "You've already poisoned someone!"--allegianceDoesNotExistMessage :: Text -> Text -> Message-allegianceDoesNotExistMessage to name = privateMessage to $ T.unwords- [ "Allegiance", name, "does not exist."- ] article :: Role -> Text article role
src/Game/Werewolf/Player.hs view
@@ -26,16 +26,16 @@ newPlayer, -- ** Traversals- angel, devotedServant, druid, hunter, jester, orphan, protector, scapegoat, seer,- simpleVillager, simpleWerewolf, villagerVillager, witch, wolfHound,+ druid, fallenAngel, hunter, jester, orphan, protector, scapegoat, seer, simpleVillager,+ simpleWerewolf, trueVillager, witch, 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, hunters, jesters, orphans, protectors, scapegoats, seers,- simpleVillagers, simpleWerewolves, villagerVillagers, witches, wolfHounds,+ druids, fallenAngels, hunters, jesters, orphans, protectors, scapegoats, seers, simpleVillagers,+ simpleWerewolves, trueVillagers, witches, villagers, werewolves, alive, dead, @@ -75,22 +75,6 @@ newPlayer :: Text -> Role -> Player newPlayer name role = Player name role Alive --- | The traversal of 'Player's with an 'angelRole'.------ @--- 'angel' = 'role' . 'only' 'angelRole'--- @-angel :: Traversal' Player ()-angel = role . only angelRole---- | The traversal of 'Player's with a 'devotedServantRole'.------ @--- 'devotedServant' = 'role' . 'only' 'devotedServantRole'--- @-devotedServant :: Traversal' Player ()-devotedServant = role . only devotedServantRole- -- | The traversal of 'Player's with a 'druidRole'. -- -- @@@ -99,6 +83,14 @@ druid :: Traversal' Player () druid = role . only druidRole +-- | The traversal of 'Player's with an 'fallenAngelRole'.+--+-- @+-- 'fallenAngel' = 'role' . 'only' 'fallenAngelRole'+-- @+fallenAngel :: Traversal' Player ()+fallenAngel = role . only fallenAngelRole+ -- | The traversal of 'Player's with a 'hunterRole'. -- -- @@@ -163,13 +155,13 @@ simpleWerewolf :: Traversal' Player () simpleWerewolf = role . only simpleWerewolfRole --- | The traversal of 'Player's with a 'villagerVillagerRole'.+-- | The traversal of 'Player's with a 'trueVillagerRole'. -- -- @--- 'villagerVillager' = 'role' . 'only' 'villagerVillagerRole'+-- 'trueVillager' = 'role' . 'only' 'trueVillagerRole' -- @-villagerVillager :: Traversal' Player ()-villagerVillager = role . only villagerVillagerRole+trueVillager :: Traversal' Player ()+trueVillager = role . only trueVillagerRole -- | The traversal of 'Player's with a 'witchRole'. --@@ -179,14 +171,6 @@ witch :: Traversal' Player () witch = role . only witchRole --- | The traversal of 'Player's with a 'wolfHoundRole'.------ @--- 'wolfHound' = 'role' . 'only' 'wolfHoundRole'--- @-wolfHound :: Traversal' Player ()-wolfHound = role . only wolfHoundRole- -- | The traversal of 'Player's aligned with the 'Villagers'. -- -- @@@ -227,22 +211,6 @@ states :: Traversable t => Traversal' (t Player) State states = traverse . state --- | This 'Traversal' provides the traversal of 'angel' 'Player's.------ @--- 'angels' = 'traverse' . 'filtered' ('is' 'angel')--- @-angels :: Traversable t => Traversal' (t Player) Player-angels = traverse . filtered (is angel)---- | This 'Traversal' provides the traversal of 'devotedServant' 'Player's.------ @--- 'devotedServants' = 'traverse' . 'filtered' ('is' 'devotedServant')--- @-devotedServants :: Traversable t => Traversal' (t Player) Player-devotedServants = traverse . filtered (is devotedServant)- -- | This 'Traversal' provides the traversal of 'druid' 'Player's. -- -- @@@ -251,6 +219,14 @@ druids :: Traversable t => Traversal' (t Player) Player druids = traverse . filtered (is druid) +-- | This 'Traversal' provides the traversal of 'fallenAngel' 'Player's.+--+-- @+-- 'fallenAngels' = 'traverse' . 'filtered' ('is' 'fallenAngel')+-- @+fallenAngels :: Traversable t => Traversal' (t Player) Player+fallenAngels = traverse . filtered (is fallenAngel)+ -- | This 'Traversal' provides the traversal of 'hunter' 'Player's. -- -- @@@ -315,13 +291,13 @@ simpleWerewolves :: Traversable t => Traversal' (t Player) Player simpleWerewolves = traverse . filtered (is simpleWerewolf) --- | This 'Traversal' provides the traversal of 'villagerVillager' 'Player's.+-- | This 'Traversal' provides the traversal of 'trueVillager' 'Player's. -- -- @--- 'villagerVillagers' = 'traverse' . 'filtered' ('is' 'villagerVillager')+-- 'trueVillagers' = 'traverse' . 'filtered' ('is' 'trueVillager') -- @-villagerVillagers :: Traversable t => Traversal' (t Player) Player-villagerVillagers = traverse . filtered (is villagerVillager)+trueVillagers :: Traversable t => Traversal' (t Player) Player+trueVillagers = traverse . filtered (is trueVillager) -- | This 'Traversal' provides the traversal of 'witch' 'Player's. --@@ -330,14 +306,6 @@ -- @ witches :: Traversable t => Traversal' (t Player) Player witches = traverse . filtered (is witch)---- | This 'Traversal' provides the traversal of 'wolfHound' 'Player's.------ @--- 'wolfHounds' = 'traverse' . 'filtered' ('is' 'wolfHound')--- @-wolfHounds :: Traversable t => Traversal' (t Player) Player-wolfHounds = traverse . filtered (is wolfHound) -- | This 'Traversal' provides the traversal of 'villager' 'Player's. --
src/Game/Werewolf/Role.hs view
@@ -24,7 +24,7 @@ name, allegiance, balance, description, rules, Allegiance(..),- _Angel, _Villagers, _Werewolves,+ _FallenAngel, _Villagers, _Werewolves, -- ** Instances allRoles, restrictedRoles,@@ -33,13 +33,13 @@ -- | 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, orphanRole, wolfHoundRole,+ orphanRole, -- *** The Loners -- | The Loners look out for themselves and themselves alone. -- The Loners must complete their own objective.- angelRole,+ fallenAngelRole, -- *** The Villagers -- | Fraught with fear of the unseen enemy, the Villagers must work together to determine the@@ -48,7 +48,7 @@ -- The Villagers must lynch all of the Werewolves. druidRole, hunterRole, jesterRole, protectorRole, scapegoatRole, seerRole, simpleVillagerRole,- villagerVillagerRole, witchRole,+ trueVillagerRole, witchRole, -- *** The Werewolves -- | Hiding in plain sight, the Werewolves are not a small trifle.@@ -87,7 +87,7 @@ } deriving (Read, Show) -- | The Loner allegiances are seldom used, rather they are present for correctness.-data Allegiance = Angel | Villagers | Werewolves+data Allegiance = FallenAngel | Villagers | Werewolves deriving (Eq, Read, Show) makeLenses ''Role@@ -100,9 +100,8 @@ -- | A list containing all the roles defined in this file. allRoles :: [Role] allRoles =- [ angelRole- , devotedServantRole- , druidRole+ [ druidRole+ , fallenAngelRole , hunterRole , jesterRole , orphanRole@@ -111,9 +110,8 @@ , seerRole , simpleVillagerRole , simpleWerewolfRole- , villagerVillagerRole+ , trueVillagerRole , witchRole- , wolfHoundRole ] -- | A list containing roles that are restricted to a single instance per 'Game'.@@ -124,43 +122,16 @@ restrictedRoles :: [Role] restrictedRoles = allRoles \\ [simpleVillagerRole, simpleWerewolfRole] --- | /Who could dream of a better servant than one willing to give up her life for that of her/--- /masters? Don't rejoice too fast, as the devouring ambition within her could spell the end of/--- /the village!/------ Before the revelation of the card of the player eliminated by the village's vote, the Devoted--- Servant can reveal herself by showing her card and taking on the role of the eliminated player.--- Upon taking on her master's role, any special abilities are reset and any first turns are--- replayed.-devotedServantRole :: Role-devotedServantRole = Role- { _name = "Devoted Servant"- , _allegiance = Villagers- , _balance = 2- , _description = T.unwords- [ "Who could dream of a better servant than one willing to give up her life for that of her"- , "masters? Don't rejoice too fast, as the devouring ambition within her could spell the"- , "end of the village!"- ]- , _rules = T.unwords- [ "Before the revelation of the card of the player eliminated by the village's vote, the"- , "Devoted Servant can reveal herself by showing her card and taking on the role of the"- , "eliminated player. Upon taking on her master's role, any special abilities are reset and"- , "any first turns are replayed."- ]- }- -- | /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.../+-- /feed, the Orphan was left to fend for themself. No-one looked twice at the Orphan and even/+-- /fewer showed kindness towards the lonely child. One day however, one townsperson changed all/+-- /this. He offered the Orphan food, water and a roof over their head. Grateful for his chairty/+-- /and affection, the Orphan made him their role model. Pray that no ill should befall their/+-- /role model, for they are the only one conforming the Orphan as 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.+-- On the first night, the Orphan chooses a player to become their role model. So long as the role+-- model is alive, the Orphan is a Villager. If however the role model is eliminated, then the+-- Orphan becomes a Werewolf. orphanRole :: Role orphanRole = Role { _name = "Orphan"@@ -168,72 +139,51 @@ , _balance = -1 , _description = T.unwords [ "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 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"+ , "to feed, the Orphan was left to fend for themself. No-one looked twice at the Orphan and"+ , "even fewer showed kindness towards the lonely child. One day however, one townsperson"+ , "changed all this. He offered the Orphan food, water and a roof over their head. Grateful"+ , "for his chairty and affection, the Orphan made him their role model. Pray that no ill"+ , "should befall their role model, for they are the only one conforming the Orphan as a" , "Villager." ]- }---- | /All dogs know in the depths of their soul that their ancestors were wolves and that it's/--- /mankind who has kept them in the state of childishness and fear, the faithful and generous/--- /companions. In any case, only the Wolf-hound can decide if he'll obey his human and civilized/--- /master or if he'll listen to the call of wild nature buried within him./------ On the first night, the Wolf-hound chooses if he wants to be a Simple Villager or Werewolf. The--- choice is final.-wolfHoundRole :: Role-wolfHoundRole = Role- { _name = "Wolf-hound"- , _allegiance = Villagers- , _balance = -1- , _description = T.unwords- [ "All dogs know in the depths of their soul that their ancestors were wolves and that it's"- , "mankind who has kept them in the state of childishness and fear, the faithful and"- , "generous companions. In any case, only the Wolf-hound can decide if he'll obey his human"- , "and civilized master or if he'll listen to the call of wild nature buried within him."- ] , _rules = T.unwords- [ "On the first night, the Wolf-hound chooses if he wants to be a Simple Villager or"- , "Werewolf. The choice is final."+ [ "On the first night, the Orphan chooses a player to become their role model. So long as"+ , "the role model is alive, the Orphan is a Villager. If however the role model is"+ , "eliminated, then the Orphan becomes a Werewolf." ] } --- | /The muddy life of a village infested with evil creatures repulses him; he wishes to believe/--- /he's the victim of a terrible nightmare, in order to finally wake up in his comfortable bed./+-- | /Long ago during the War in Heaven, angels fell from the sky as one by one those that followed/+-- /Lucifer were defeated. For centuries they lived amongst mortal Villagers as punishment for/+-- /their sins and wrongdoings. The Fallen Angel was one such being and is now one of the few/+-- /angels left on Earth. Nothing is worse punishment for them, the Fallen Angel yearns for death/+-- /to once again be free!/ ----- When the Angel is in play, the game always begins with the village's debate followed by an--- elimination vote, and then the first night.+-- When the Fallen Angel is in play, the game begins with the village's vote and then the first+-- night. ----- The Angel wins if he manages to get eliminated on the first round (day or night).--- If he fails, then he becomes a Simple Villager for the rest of the game.-angelRole :: Role-angelRole = Role- { _name = "Angel"- , _allegiance = Angel+-- The Fallen Angel wins if they manage to get eliminated on the first round (day or night). If+-- however they fail, they become a Villager for the rest of the game.+fallenAngelRole :: Role+fallenAngelRole = Role+ { _name = "Fallen Angel"+ , _allegiance = FallenAngel , _balance = 0 , _description = T.unwords- [ "The muddy life of a village infested with evil creatures repulses him; he wishes to"- , "believe he's the victim of a terrible nightmare, in order to finally wake up in his"- , "comfortable bed."+ [ "Long ago during the War in Heaven, angels fell from the sky as one by one those that"+ , "followed Lucifer were defeated. For centuries they lived amongst mortal Villagers as"+ , "punishment for their sins and wrongdoings. The Fallen Angel was one such being and is"+ , "now one of the few angels left on Earth. Nothing is worse punishment for them, the"+ , "Fallen Angel yearns for death to once again be free!" ] , _rules = T.intercalate "\n" [ T.unwords- [ "When the Angel is in play, the game always begins with the village's debate followed"- , "by an elimination vote, and then the first night."+ [ "When the Fallen Angel is in play, the game begins with the village's vote and then"+ , "the first night." ] , T.unwords- [ "The Angel wins if he manages to get eliminated on the first round (day or night). If"- , "he fails, then he becomes a Simple Villager for the rest of the game."+ [ "The Fallen Angel wins if they manage to get eliminated on the first round (day or"+ , "night). If however they fail, they become a Villager for the rest of the game." ] ] }@@ -242,7 +192,7 @@ -- /marks an exceptional time in Fougères's history! Friend of the woodland creatures, practiced/ -- /philosopher and now, with the help of Ferina their companion, a bane to the Werewolves/ -- /themselves! My does she have a nose on her, strong enough to sniff out lycanthropes in close/--- /proximity! Listen for her grunt and heed the Druid's words for they will not let you down./+-- /proximity! Listen for her grunt and heed her warning for she will not let you down./ -- -- Each morning when Ferina wakes from her slumber she will be alert and cautious. If the Druid is -- next to a Werewolf then Ferina will grunt in warning.@@ -250,14 +200,14 @@ druidRole = Role { _name = "Druid" , _allegiance = Villagers- , _balance = 2+ , _balance = 3 , _description = T.unwords [ "How honoured we are to be in the presence of such a noble leader. The return of the" , "Druid marks an exceptional time in Fougères's history! Friend of the woodland creatures," , "practiced philosopher and now, with the help of Ferina their companion, a bane to the" , "Werewolves themselves! My does she have a nose on her, strong enough to sniff out"- , "lycanthropes in close proximity! Listen for her grunt and heed the Druid's words for"- , "they will not let you down."+ , "lycanthropes in close proximity! Listen for her grunt and heed her warning for she will"+ , "not let you down." ] , _rules = T.unwords [ "Each morning when Ferina wakes from her slumber she will be alert and cautious. If the"@@ -266,10 +216,10 @@ } -- | /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./+-- /killed unjustly, they 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+-- If the Hunter is killed they choose one player, believed to be an attacker, to kill -- immediately. hunterRole :: Role hunterRole = Role@@ -278,22 +228,21 @@ , _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."+ , "jumped and killed unjustly, they 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."+ [ "If the Hunter is killed they 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/--- /saving an innocents life./+-- | /The Protector is one of the few pure of heart and altruistic Villagers; they are forever/+-- /putting others needs above their own. Each night they fight against the Werewolves with/+-- /naught but a sword and shield, potentially saving an innocents life./ ----- Each night the Protector may choose a player deemed worthy of their protection. That player is--- safe for that night night (and only that night) against the Werewolves.+-- Each night the Protector chooses a player deemed worthy of their protection. That player is+-- safe for that night (and only that night) against the Werewolves. -- -- The Protector may not protect the same player two nights in a row. protectorRole :: Role@@ -302,15 +251,14 @@ , _allegiance = Villagers , _balance = 2 , _description = T.unwords- [ "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 saving an innocents life."+ [ "The Protector is one of the few pure of heart and altruistic Villagers; they are forever"+ , "putting others needs above their own. Each night they fight against the Werewolves with"+ , "naught but a sword and shield, potentially saving an innocents life." ] , _rules = T.intercalate "\n" [ T.unwords- [ "Each night the Protector may choose a player deemed worthy of their protection. That"- , "player is safe for that night night (and only that night) against the Werewolves."+ [ "Each night the Protector chooses a player deemed worthy of their protection. That"+ , "player is safe for that night (and only that night) against the Werewolves." ] , "The Protector may not protect the same player two nights in a row." ]@@ -322,8 +270,8 @@ -- -- If the village's vote ends in a tie, it's the Scapegoat who is eliminated instead of no-one. ----- In this event, the Scapegoat has one last task to complete: he must choose whom is permitted to--- vote or not on the next day.+-- In this event, the Scapegoat has one last task to complete: they must choose whom is permitted+-- to vote or not on the next day. scapegoatRole :: Role scapegoatRole = Role { _name = "Scapegoat"@@ -341,37 +289,36 @@ , "no-one." ] , T.unwords- [ "In this event, the Scapegoat has one last task to complete: he must choose whom is"+ [ "In this event, the Scapegoat has one last task to complete: they must choose whom is" , "permitted to vote or not on the next day." ] ] } --- | /Frequently misunderstood and thought to be a fortune teller, the Seer has the ability to see/--- /into fellow townsfolk and determine their true nature. This ability to see is not given out/--- /lightly, for certain it is a gift! Visions will always be true, but only for the present as/--- /not even the Seer knowns what the future holds./+-- | /The Seer has the ability to see into fellow townsfolk and determine their true nature. This/+-- /ability to see is not given out lightly, for certain it is a gift! The visions will always be/+-- /true, but only for the present as not even the Seer knows what the future holds./ ----- Each night the Seer sees the allegiance of a player of their choice.+-- Each night the Seer sees the allegiance of one player of their choice. seerRole :: Role seerRole = Role { _name = "Seer" , _allegiance = Villagers , _balance = 2 , _description = T.unwords- [ "Frequently misunderstood and thought to be a fortune teller, the Seer has the ability to"- , "see into fellow townsfolk and determine their true nature. This ability to see is not"- , "given out lightly, for certain it is a gift! Visions will always be true, but only for"- , "the present as not even the Seer knowns what the future holds."+ [ "The Seer has the ability to see into fellow townsfolk and determine their true nature."+ , "This ability to see is not given out lightly, for certain it is a gift! The visions will"+ , "always be true, but only for the present as not even the Seer knows what the future"+ , "holds." ]- , _rules = "Each night the Seer sees the allegiance of a player of their choice."+ , _rules = "Each night the Seer sees the allegiance of one player of their choice." } -- | /A simple, ordinary townsperson in every way. Some may be cobblers, others bakers or even/--- /nobles. No matter their differences though, the plight of Werewolves in Fougères unites them/--- /in this unfortunate time./+-- /nobles. No matter their differences though, the plight of Werewolves in Fougères unites all/+-- /the Villagers in this unfortunate time./ ----- A Simple Villager has no special abilities, they must use their guile to determine whom among+-- The Simple Villager has no special abilities, they must use their guile to determine whom among -- them is not who they say they are. simpleVillagerRole :: Role simpleVillagerRole = Role@@ -381,71 +328,63 @@ , _description = T.unwords [ "A simple, ordinary townsperson in every way. Some may be cobblers, others bakers or even" , "nobles. No matter their differences though, the plight of Werewolves in Fougères unites"- , "them in this unfortunate time."+ , "all the Villagers in this unfortunate time." ] , _rules = T.unwords- [ "A Simple Villager has no special abilities, they must use their guile to determine whom"- , "among them is not who they say they are."+ [ "The Simple Villager has no special abilities, they must use their guile to determine"+ , "whom among them is not who they say they are." ] } --- | /Every village needs a Jester, they're so stupid but provide so much entertainment! The Jester/--- /may not have any special abilities, but at least no one in the village would want to hurt/--- /him./+-- | /Every village needs a Jester; they're so stupid, but provide so much entertainment! The/+-- /Jester may not have any special abilities, but at least no one in the village wants to hurt/+-- /them./ ----- If the village votes to lynch the Jester, his identity is revealed. The village realise there's--- no point in burning him and so he is set free.+-- If the village votes to lynch the Jester, their identity is revealed. The village realise+-- there's no point in burning them and so they are set free. ----- The Jester continues to play but may no longer vote as no one can take him seriously.+-- The Jester continues to play but may no longer vote as no one can take them seriously. jesterRole :: Role jesterRole = Role { _name = "Jester" , _allegiance = Villagers , _balance = 0 , _description = T.unwords- [ "Every village needs a Jester, they're so stupid but provide so much entertainment! The"- , "Jester may not have any special abilities, but at least no one in the village would want"- , "to hurt him."+ [ "Every village needs a Jester; they're so stupid, but provide so much entertainment! The"+ , "Jester may not have any special abilities, but at least no one in the village wants to"+ , "hurt them." ] , _rules = T.intercalate "\n" [ T.unwords- [ "If the village votes to lynch the Jester, his identity is revealed. The village"- , "realise there's no point in burning him and so he is set free."- ]- , T.unwords- [ "The Jester continues to play but may no longer vote as no one can take him"- , "seriously."+ [ "If the village votes to lynch the Jester, their identity is revealed. The village"+ , "realise there's no point in burning them and so they are set free." ]+ , "The Jester continues to play but may no longer vote as no one can take them seriously." ] } --- | /This person has a soul as clear and transparent as the water from a mountain stream. They/--- /will deserve the attentive ear of their peers and will make their word decisive in crucial/--- /moments./+-- | /The True Villager has a heart and soul as clear as day! Their allegiance and devotion to the/+-- /village are beyond reproach. If there is one person whom you should confide in, listen to and/+-- /trust, it is the True Villager./ ----- When the game begins, the village is told the identity of the Villager-Villager, thus ensuring--- certainty that its owner is truly an innocent Villager.-villagerVillagerRole :: Role-villagerVillagerRole = Role- { _name = "Villager-Villager"+-- At the start of the game the True Villager's identity is revealed.+trueVillagerRole :: Role+trueVillagerRole = Role+ { _name = "True Villager" , _allegiance = Villagers , _balance = 2 , _description = T.unwords- [ "This person has a soul as clear and transparent as the water from a mountain stream."- , "They will deserve the attentive ear of their peers and will make their word decisive in"- , "crucial moments."- ]- , _rules = T.unwords- [ "When the game begins, the village is told the identity of the Villager-Villager, thus"- , "ensuring certainty that its owner is truly an innocent Villager."+ [ "The True Villager has a heart and soul as clear as day! Their allegiance and devotion to"+ , "the village are beyond reproach. If there is one person whom you should confide in,"+ , "listen to and trust, it is the True Villager." ]+ , _rules = "At the start of the game the True Villager's identity is revealed." } -- | /Somehow forgotten with the coming of the Werewolves, the Witch has a chance to prove themself/--- /valuable to the village. The Witch is blessed (or maybe cursed) with the ability to make two/--- /powerful potions; one of which may heal a victim of the Werewolves, the other able to poison/--- /a player. The use of these potions could alter the village's currently misguided perception/--- /of the Witch./+-- /valuable to the village and maybe abolish the absurd pastime of burning and drowning their/+-- /cult. The Witch is blessed (or maybe cursed) with the ability to make two powerful potions;/+-- /one of which heals a victim of the Werewolves, the other poisons a player./ -- -- The Witch is called after the Werewolves. They are able to heal and poison one player per game. -- There is no restriction on using both potions in one night or to heal themself.@@ -456,10 +395,10 @@ , _balance = 3 , _description = T.unwords [ "Somehow forgotten with the coming of the Werewolves, the Witch has a chance to prove"- , "themself valuable to the village. The Witch is blessed (or maybe cursed) with the"- , "ability to make two powerful potions; one of which may heal a victim of the Werewolves,"- , "the other able to poison a player. The use of these potions could alter the village's"- , "currently misguided perception of the Witch."+ , "themself valuable to the village and maybe abolish the absurd pastime of burning and"+ , "drowning their cult. The Witch is blessed (or maybe cursed) with the ability to make two"+ , "powerful potions; one of which heals a victim of the Werewolves, the other poisons a"+ , "player." ] , _rules = T.unwords [ "The Witch is called after the Werewolves. They are able to heal and poison one player"@@ -468,10 +407,10 @@ ] } --- | /It's difficult to tell, but a Werewolf is merely a Villager underneath; unfortunately one/--- /that has been afflicted with lycanthropy and consequently transforms each night into a/--- /fearsome lupine. Not all hope is yet lost, some Villagers would like to try and cure the/--- /curse of lycanthropy. Perhaps one day this dream will be realised./+-- | /The Simple Werewolf is a fearsome lupine, cunning like no other creature that roams the/+-- /forest. Their origin is unknown, but that matters little, for they present a grave threat to/+-- /Fougères. While each day they hide in plain sight as an ordinary Villager, each night they/+-- /transform and devour an innocent. There is little hope left for the village./ -- -- A Werewolf may never devour another Werewolf. simpleWerewolfRole :: Role@@ -480,10 +419,11 @@ , _allegiance = Werewolves , _balance = -4 , _description = T.unwords- [ "It's difficult to tell, but a Werewolf is merely a Villager underneath; unfortunately"- , "one that has been afflicted with lycanthropy and consequently transforms each night into"- , "a fearsome lupine. Not all hope is yet lost, some Villagers would like to try and cure"- , "the curse of lycanthropy. Perhaps one day this dream will be realised."+ [ "The Simple Werewolf is a fearsome lupine, cunning like no other creature that roams the"+ , "forest. Their origin is unknown, but that matters little, for they present a grave"+ , "threat to Fougères. While each day they hide in plain sight as an ordinary Villager,"+ , "each night they transform and devour an innocent. There is little hope left for the"+ , "village." ] , _rules = "A Werewolf may never devour another Werewolf." }
src/Game/Werewolf/Util.hs view
@@ -17,24 +17,23 @@ -- * Game -- ** Manipulations- killPlayer, removePlayer, setPlayerAllegiance, setPlayerRole,+ killPlayer, removePlayer, setPlayerAllegiance, -- ** Searches findPlayerBy_, getAdjacentAlivePlayers, getPlayerVote, getAllowedVoters, getPendingVoters, getVoteResult, -- ** Queries- isDevotedServantsTurn, isGameOver, isHuntersTurn, isOrphansTurn, isProtectorsTurn,- isScapegoatsTurn, isSeersTurn, isSunrise, isVillagesTurn, isWerewolvesTurn, isWitchsTurn,- isWolfHoundsTurn,- hasAnyoneWon, hasAngelWon, hasVillagersWon, hasWerewolvesWon,+ isGameOver, isHuntersTurn, isOrphansTurn, isProtectorsTurn, isScapegoatsTurn, isSeersTurn,+ isSunrise, isVillagesTurn, isWerewolvesTurn, isWitchsTurn,+ hasAnyoneWon, hasFallenAngelWon, hasVillagersWon, hasWerewolvesWon, -- * Player -- ** Queries doesPlayerExist,- isPlayerDevotedServant, isPlayerHunter, isPlayerJester, isPlayerOrphan, isPlayerProtector,- isPlayerScapegoat, isPlayerSeer, isPlayerWitch, isPlayerWolfHound,+ isPlayerHunter, isPlayerJester, isPlayerOrphan, isPlayerProtector, isPlayerScapegoat,+ isPlayerSeer, isPlayerWitch, isPlayerWerewolf, isPlayerAlive, isPlayerDead, ) where@@ -49,8 +48,8 @@ import Data.Text (Text) import Game.Werewolf.Game hiding (doesPlayerExist, getAllowedVoters, getPendingVoters,- getVoteResult, hasAngelWon, hasAnyoneWon, hasVillagersWon,- hasWerewolvesWon, killPlayer)+ getVoteResult, hasAnyoneWon, hasFallenAngelWon,+ hasVillagersWon, hasWerewolvesWon, killPlayer) import qualified Game.Werewolf.Game as Game import Game.Werewolf.Player import Game.Werewolf.Role hiding (name)@@ -68,29 +67,23 @@ player <- findPlayerBy_ name name' - when (is angel player) $ setPlayerAllegiance name' Villagers- when (is orphan player) $ roleModel .= Nothing- when (is protector player) $ do+ when (is fallenAngel 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 witch player) $ do+ when (is seer player) $ see .= Nothing+ when (is witch player) $ do heal .= False healUsed .= False poison .= Nothing poisonUsed .= False- when (is wolfHound player) $ allegianceChosen .= True -- | 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' --- | Fudges the player's role. This function is useful for roles such as the Devoted Servant where--- they take on a different role.-setPlayerRole :: MonadState Game m => Text -> Role -> m ()-setPlayerRole name' role' = modify $ players . traverse . filteredBy name name' . role .~ role'- findPlayerBy_ :: (Eq a, MonadState Game m) => Lens' Player a -> a -> m Player findPlayerBy_ lens value = fromJust <$> preuse (players . traverse . filteredBy lens value) @@ -116,9 +109,6 @@ getVoteResult :: MonadState Game m => m [Player] getVoteResult = gets Game.getVoteResult -isDevotedServantsTurn :: MonadState Game m => m Bool-isDevotedServantsTurn = has (stage . _DevotedServantsTurn) <$> get- isGameOver :: MonadState Game m => m Bool isGameOver = has (stage . _GameOver) <$> get @@ -152,14 +142,11 @@ isWitchsTurn :: MonadState Game m => m Bool isWitchsTurn = has (stage . _WitchsTurn) <$> get -isWolfHoundsTurn :: MonadState Game m => m Bool-isWolfHoundsTurn = has (stage . _WolfHoundsTurn) <$> get- hasAnyoneWon :: MonadState Game m => m Bool hasAnyoneWon = gets Game.hasAnyoneWon -hasAngelWon :: MonadState Game m => m Bool-hasAngelWon = gets Game.hasAngelWon+hasFallenAngelWon :: MonadState Game m => m Bool+hasFallenAngelWon = gets Game.hasFallenAngelWon hasVillagersWon :: MonadState Game m => m Bool hasVillagersWon = gets Game.hasVillagersWon@@ -170,9 +157,6 @@ doesPlayerExist :: MonadState Game m => Text -> m Bool doesPlayerExist name = gets $ Game.doesPlayerExist name -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' @@ -193,9 +177,6 @@ isPlayerWitch :: MonadState Game m => Text -> m Bool isPlayerWitch name' = is witch <$> findPlayerBy_ name name'--isPlayerWolfHound :: MonadState Game m => Text -> m Bool-isPlayerWolfHound name' = is wolfHound <$> findPlayerBy_ name name' isPlayerWerewolf :: MonadState Game m => Text -> m Bool isPlayerWerewolf name' = is werewolf <$> findPlayerBy_ name name'
test/src/Game/Werewolf/Test/Arbitrary.hs view
@@ -12,18 +12,17 @@ -- ** Game NewGame(..),- GameAtDevotedServantsTurn(..), GameAtGameOver(..), GameAtHuntersTurn(..), GameAtOrphansTurn(..),- GameAtProtectorsTurn(..), GameAtScapegoatsTurn(..), GameAtSeersTurn(..), GameAtSunrise(..),- GameAtVillagesTurn(..), GameAtWerewolvesTurn(..), GameAtWitchsTurn(..),- GameAtWolfHoundsTurn(..),+ GameAtGameOver(..), GameAtHuntersTurn(..), GameAtOrphansTurn(..), GameAtProtectorsTurn(..),+ GameAtScapegoatsTurn(..), GameAtSeersTurn(..), GameAtSunrise(..), GameAtVillagesTurn(..),+ GameAtWerewolvesTurn(..), GameAtWitchsTurn(..), GameOnSecondRound(..),- GameWithAllegianceChosen(..), GameWithAllowedVoters(..), GameWithConflictingVote(..),- GameWithDeadPlayers(..), GameWithDevourEvent(..), GameWithDevourVotes(..), GameWithHeal(..),+ GameWithAllowedVoters(..), GameWithConflictingVote(..), GameWithDeadPlayers(..),+ GameWithDevourEvent(..), GameWithDevourVotes(..), GameWithHeal(..), GameWithJesterRevealedAtVillagesTurn(..), GameWithLynchVotes(..), GameWithMajorityVote(..), GameWithNoAllowedVotersAtVillagesTurn(..), GameWithNoWerewolvesAtProtectorsTurn(..),- GameWithOneAllegianceAlive(..), GameWithPassAtDevotedServantsTurn(..), GameWithPoison(..),- GameWithProtect(..), GameWithProtectAndDevourVotes(..), GameWithRoleModel(..),- GameWithRoleModelAtVillagesTurn(..), GameWithSee(..),+ GameWithOneAllegianceAlive(..), GameWithPoison(..), GameWithProtect(..),+ GameWithProtectAndDevourVotes(..), GameWithRoleModel(..), GameWithRoleModelAtVillagesTurn(..),+ GameWithSee(..), -- ** Player arbitraryPlayerSet,@@ -32,9 +31,8 @@ -- ** Command arbitraryCommand, arbitraryHunterChooseCommand, arbitraryOrphanChooseCommand,- arbitraryWolfHoundChooseCommand, arbitraryScapegoatChooseCommand, arbitraryHealCommand,- arbitraryDevotedServantPassCommand, arbitraryWitchPassCommand, arbitraryPoisonCommand,- arbitraryProtectCommand, arbitraryQuitCommand, arbitraryRevealCommand, arbitrarySeeCommand,+ arbitraryScapegoatChooseCommand, arbitraryHealCommand, arbitraryPassCommand,+ arbitraryPoisonCommand, arbitraryProtectCommand, arbitraryQuitCommand, arbitrarySeeCommand, arbitraryWerewolfVoteCommand, arbitraryVillagerVoteCommand, runArbitraryCommands, @@ -50,17 +48,15 @@ import qualified Data.Text as T 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.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.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.Witch as Witch-import Game.Werewolf.Command.WolfHound as WolfHound+import Game.Werewolf.Command.Villager as Villager+import Game.Werewolf.Command.Werewolf as Werewolf+import Game.Werewolf.Command.Witch import Game.Werewolf.Test.Util import Prelude hiding (round)@@ -98,16 +94,6 @@ instance Arbitrary NewGame where arbitrary = NewGame . newGame <$> arbitraryPlayerSet -newtype GameAtDevotedServantsTurn = GameAtDevotedServantsTurn Game- deriving (Eq, Show)--instance Arbitrary GameAtDevotedServantsTurn where- arbitrary = do- (GameWithMajorityVote game) <- suchThat arbitrary $ \(GameWithMajorityVote game) ->- isn't devotedServant (head $ getVoteResult game)-- return $ GameAtDevotedServantsTurn (run_ checkStage game)- newtype GameAtGameOver = GameAtGameOver Game deriving (Eq, Show) @@ -199,15 +185,6 @@ return $ GameAtWitchsTurn (game & stage .~ WitchsTurn) -newtype GameAtWolfHoundsTurn = GameAtWolfHoundsTurn Game- deriving (Eq, Show)--instance Arbitrary GameAtWolfHoundsTurn where- arbitrary = do- game <- arbitrary-- return $ GameAtWolfHoundsTurn (game & stage .~ WolfHoundsTurn)- newtype GameOnSecondRound = GameOnSecondRound Game deriving (Eq, Show) @@ -217,16 +194,6 @@ return $ GameOnSecondRound (game & round .~ 1) -newtype GameWithAllegianceChosen = GameWithAllegianceChosen Game- deriving (Eq, Show)--instance Arbitrary GameWithAllegianceChosen where- arbitrary = do- (GameAtWolfHoundsTurn game) <- arbitrary- (Blind command) <- arbitraryWolfHoundChooseCommand game-- return $ GameWithAllegianceChosen (run_ (apply command) game)- newtype GameWithAllowedVoters = GameWithAllowedVoters Game deriving (Eq, Show) @@ -326,15 +293,6 @@ return $ GameWithMajorityVote game -newtype GameWithMajorityVoteAtDevotedServantsTurn = GameWithMajorityVoteAtDevotedServantsTurn Game- deriving (Eq, Show)--instance Arbitrary GameWithMajorityVoteAtDevotedServantsTurn where- arbitrary = do- (GameWithMajorityVote game) <- arbitrary-- return . GameWithMajorityVoteAtDevotedServantsTurn $ run_ checkStage game- newtype GameWithNoAllowedVotersAtVillagesTurn = GameWithNoAllowedVotersAtVillagesTurn Game deriving (Eq, Show) @@ -367,16 +325,6 @@ return $ GameWithOneAllegianceAlive game' -newtype GameWithPassAtDevotedServantsTurn = GameWithPassAtDevotedServantsTurn Game- deriving (Eq, Show)--instance Arbitrary GameWithPassAtDevotedServantsTurn where- arbitrary = do- (GameAtDevotedServantsTurn game) <- arbitrary- (Blind command) <- arbitraryDevotedServantPassCommand game-- return $ GameWithPassAtDevotedServantsTurn (run_ (apply command) game)- newtype GameWithPassAtWitchsTurn = GameWithPassAtWitchsTurn Game deriving (Eq, Show) @@ -384,7 +332,7 @@ arbitrary = do game <- arbitrary let game' = game & stage .~ WitchsTurn- (Blind command) <- arbitraryWitchPassCommand game'+ (Blind command) <- arbitraryPassCommand game' return $ GameWithPassAtWitchsTurn (run_ (apply command) game') @@ -465,29 +413,24 @@ arbitraryCommand :: Game -> Gen (Blind Command) arbitraryCommand game = case game ^. stage of- DevotedServantsTurn -> oneof- [ arbitraryDevotedServantPassCommand game- , arbitraryRevealCommand game- ]- 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- Sunrise -> return $ Blind noopCommand- Sunset -> return $ Blind noopCommand- VillagesTurn -> arbitraryVillagerVoteCommand game- WerewolvesTurn -> arbitraryWerewolfVoteCommand game- WitchsTurn -> oneof+ 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+ Sunrise -> return $ Blind noopCommand+ Sunset -> return $ Blind noopCommand+ VillagesTurn -> arbitraryVillagerVoteCommand game+ WerewolvesTurn -> arbitraryWerewolfVoteCommand game+ WitchsTurn -> oneof [ arbitraryHealCommand game- , arbitraryWitchPassCommand game+ , arbitraryPassCommand game , arbitraryPoisonCommand game ]- WolfHoundsTurn -> arbitraryWolfHoundChooseCommand game arbitraryHunterChooseCommand :: Game -> Gen (Blind Command) arbitraryHunterChooseCommand game = do@@ -503,13 +446,6 @@ 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- arbitraryScapegoatChooseCommand :: Game -> Gen (Blind Command) arbitraryScapegoatChooseCommand game = do let scapegoatsName = game ^?! players . scapegoats . name@@ -525,17 +461,11 @@ then noopCommand else healCommand witchsName -arbitraryDevotedServantPassCommand :: Game -> Gen (Blind Command)-arbitraryDevotedServantPassCommand game = do- let devotedServantsName = game ^?! players . devotedServants . name-- return . Blind $ DevotedServant.passCommand devotedServantsName--arbitraryWitchPassCommand :: Game -> Gen (Blind Command)-arbitraryWitchPassCommand game = do+arbitraryPassCommand :: Game -> Gen (Blind Command)+arbitraryPassCommand game = do let witchsName = game ^?! players . witches . name - return . Blind $ Witch.passCommand witchsName+ return . Blind $ passCommand witchsName arbitraryPoisonCommand :: Game -> Gen (Blind Command) arbitraryPoisonCommand game = do@@ -564,12 +494,6 @@ then return $ Blind noopCommand else elements applicableCallerNames >>= \callersName -> return . Blind $ quitCommand callersName--arbitraryRevealCommand :: Game -> Gen (Blind Command)-arbitraryRevealCommand game = do- let devotedServantsName = game ^?! players . devotedServants . name-- return . Blind $ revealCommand devotedServantsName arbitrarySeeCommand :: Game -> Gen (Blind Command) arbitrarySeeCommand game = do
test/src/Game/Werewolf/Test/Command.hs view
@@ -16,7 +16,6 @@ import Game.Werewolf.Test.Command.Poison import Game.Werewolf.Test.Command.Protect import Game.Werewolf.Test.Command.Quit-import Game.Werewolf.Test.Command.Reveal import Game.Werewolf.Test.Command.See import Game.Werewolf.Test.Command.Vote @@ -30,7 +29,6 @@ , allPoisonCommandTests , allProtectCommandTests , allQuitCommandTests- , allRevealCommandTests , allSeeCommandTests , allVoteCommandTests ]
test/src/Game/Werewolf/Test/Command/Choose.hs view
@@ -14,15 +14,12 @@ import Control.Lens hiding (elements, isn't) -import Data.Maybe-import Data.Text (Text)-import qualified Data.Text as T+import Data.Maybe 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.WolfHound as WolfHound import Game.Werewolf.Test.Arbitrary import Game.Werewolf.Test.Util @@ -50,15 +47,6 @@ , 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 "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 , testProperty "scapegoat choose command errors when any target does not exist" prop_scapegoatChooseCommandErrorsWhenAnyTargetDoesNotExist@@ -201,62 +189,6 @@ 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/Pass.hs view
@@ -13,8 +13,7 @@ import Control.Lens hiding (elements, isn't) import Game.Werewolf-import Game.Werewolf.Command.DevotedServant as DevotedServant-import Game.Werewolf.Command.Witch as Witch+import Game.Werewolf.Command.Witch import Game.Werewolf.Test.Arbitrary import Game.Werewolf.Test.Util @@ -23,73 +22,38 @@ allPassCommandTests :: [TestTree] allPassCommandTests =- [ testProperty "devoted servant pass command errors when game is over" prop_devotedServantPassCommandErrorsWhenGameIsOver- , 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 sets passed" prop_devotedServantPassCommandSetsPassed-- , testProperty "witch pass command errors when game is over" prop_witchPassCommandErrorsWhenGameIsOver+ [ 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 sets passed" prop_witchPassCommandSetsPassed ] -prop_devotedServantPassCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property-prop_devotedServantPassCommandErrorsWhenGameIsOver (GameAtGameOver game) =- forAll (arbitraryDevotedServantPassCommand game) $ verbose_runCommandErrors game . getBlind--prop_devotedServantPassCommandErrorsWhenCallerDoesNotExist :: GameAtDevotedServantsTurn -> Player -> Property-prop_devotedServantPassCommandErrorsWhenCallerDoesNotExist (GameAtDevotedServantsTurn game) caller =- not (doesPlayerExist (caller ^. name) game)- ==> verbose_runCommandErrors game (DevotedServant.passCommand (caller ^. name))--prop_devotedServantPassCommandErrorsWhenCallerIsDead :: GameAtDevotedServantsTurn -> Property-prop_devotedServantPassCommandErrorsWhenCallerIsDead (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let game' = killPlayer devotedServantsName game- let command = DevotedServant.passCommand devotedServantsName-- verbose_runCommandErrors game' command--prop_devotedServantPassCommandErrorsWhenNotDevotedServantsTurn :: Game -> Property-prop_devotedServantPassCommandErrorsWhenNotDevotedServantsTurn game =- hasn't (stage . _DevotedServantsTurn) game- ==> forAll (arbitraryDevotedServantPassCommand game) $ verbose_runCommandErrors game . getBlind--prop_devotedServantPassCommandSetsPassed :: GameAtDevotedServantsTurn -> Property-prop_devotedServantPassCommandSetsPassed (GameAtDevotedServantsTurn game) =- forAll (arbitraryDevotedServantPassCommand game) $ \(Blind command) -> do- let game' = run_ (apply command) game-- game' ^. passed- prop_witchPassCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_witchPassCommandErrorsWhenGameIsOver (GameAtGameOver game) =- forAll (arbitraryWitchPassCommand game) $ verbose_runCommandErrors game . getBlind+ forAll (arbitraryPassCommand game) $ verbose_runCommandErrors game . getBlind prop_witchPassCommandErrorsWhenCallerDoesNotExist :: GameAtWitchsTurn -> Player -> Property prop_witchPassCommandErrorsWhenCallerDoesNotExist (GameAtWitchsTurn game) caller = not (doesPlayerExist (caller ^. name) game)- ==> verbose_runCommandErrors game (Witch.passCommand (caller ^. name))+ ==> verbose_runCommandErrors game (passCommand $ caller ^. name) prop_witchPassCommandErrorsWhenCallerIsDead :: GameAtWitchsTurn -> Property prop_witchPassCommandErrorsWhenCallerIsDead (GameAtWitchsTurn game) = do let witchsName = game ^?! players . witches . name let game' = killPlayer witchsName game- let command = Witch.passCommand witchsName+ let command = passCommand witchsName verbose_runCommandErrors game' command prop_witchPassCommandErrorsWhenNotWitchsTurn :: Game -> Property prop_witchPassCommandErrorsWhenNotWitchsTurn game = hasn't (stage . _WitchsTurn) game- ==> forAll (arbitraryWitchPassCommand game) $ verbose_runCommandErrors game . getBlind+ ==> forAll (arbitraryPassCommand game) $ verbose_runCommandErrors game . getBlind prop_witchPassCommandSetsPassed :: GameAtWitchsTurn -> Property prop_witchPassCommandSetsPassed (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ forAll (arbitraryPassCommand game) $ \(Blind command) -> do let game' = run_ (apply command) game game' ^. passed
test/src/Game/Werewolf/Test/Command/Quit.hs view
@@ -24,21 +24,20 @@ allQuitCommandTests :: [TestTree] allQuitCommandTests =- [ testProperty "quit command errors when game is over" prop_quitCommandErrorsWhenGameIsOver- , testProperty "quit command errors when caller does not exist" prop_quitCommandErrorsWhenCallerDoesNotExist- , testProperty "quit command errors when caller is dead" prop_quitCommandErrorsWhenCallerIsDead- , testProperty "quit command kills player" prop_quitCommandKillsPlayer- , testProperty "quit command clears allegiance chosen when caller is wolf-hound" prop_quitCommandClearsAllegianceChosenWhenCallerIsWolfHound- , testProperty "quit command clears heal when caller is witch" prop_quitCommandClearsHealWhenCallerIsWitch- , testProperty "quit command clears heal used when caller is witch" prop_quitCommandClearsHealUsedWhenCallerIsWitch- , testProperty "quit command clears poison when caller is witch" prop_quitCommandClearsPoisonWhenCallerIsWitch- , testProperty "quit command clears poison used when caller is witch" prop_quitCommandClearsPoisonUsedWhenCallerIsWitch- , testProperty "quit command clears prior protect when caller is protector" prop_quitCommandClearsPriorProtectWhenCallerIsProtector- , 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 orphan" prop_quitCommandClearsRoleModelWhenCallerIsOrphan- , testProperty "quit command sets angel's allegiance when caller is angel" prop_quitCommandSetsAngelsAllegianceWhenCallerIsAngel+ [ testProperty "quit command errors when game is over" prop_quitCommandErrorsWhenGameIsOver+ , testProperty "quit command errors when caller does not exist" prop_quitCommandErrorsWhenCallerDoesNotExist+ , testProperty "quit command errors when caller is dead" prop_quitCommandErrorsWhenCallerIsDead+ , testProperty "quit command kills player" prop_quitCommandKillsPlayer+ , testProperty "quit command clears heal when caller is witch" prop_quitCommandClearsHealWhenCallerIsWitch+ , testProperty "quit command clears heal used when caller is witch" prop_quitCommandClearsHealUsedWhenCallerIsWitch+ , testProperty "quit command clears poison when caller is witch" prop_quitCommandClearsPoisonWhenCallerIsWitch+ , testProperty "quit command clears poison used when caller is witch" prop_quitCommandClearsPoisonUsedWhenCallerIsWitch+ , testProperty "quit command clears prior protect when caller is protector" prop_quitCommandClearsPriorProtectWhenCallerIsProtector+ , 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 orphan" prop_quitCommandClearsRoleModelWhenCallerIsOrphan+ , testProperty "quit command sets fallen angel's allegiance when caller is fallen angel" prop_quitCommandSetsFallenAngelsAllegianceWhenCallerIsFallenAngel ] prop_quitCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property@@ -66,13 +65,6 @@ length (game' ^.. players . traverse . dead) == 1 -prop_quitCommandClearsAllegianceChosenWhenCallerIsWolfHound :: GameWithAllegianceChosen -> Bool-prop_quitCommandClearsAllegianceChosenWhenCallerIsWolfHound (GameWithAllegianceChosen game) = do- let wolfHoundsName = game ^?! players . wolfHounds . name- let command = quitCommand wolfHoundsName-- run_ (apply command) game ^. allegianceChosen- prop_quitCommandClearsHealWhenCallerIsWitch :: GameWithHeal -> Bool prop_quitCommandClearsHealWhenCallerIsWitch (GameWithHeal game) = do let witch = game ^?! players . witches@@ -136,10 +128,10 @@ isNothing $ run_ (apply command) game ^. roleModel -prop_quitCommandSetsAngelsAllegianceWhenCallerIsAngel :: Game -> Bool-prop_quitCommandSetsAngelsAllegianceWhenCallerIsAngel game = do- let angelsName = game ^?! players . angels . name- let command = quitCommand angelsName- let game' = run_ (apply command) game+prop_quitCommandSetsFallenAngelsAllegianceWhenCallerIsFallenAngel :: Game -> Bool+prop_quitCommandSetsFallenAngelsAllegianceWhenCallerIsFallenAngel game = do+ let fallenAngelsName = game ^?! players . fallenAngels . name+ let command = quitCommand fallenAngelsName+ let game' = run_ (apply command) game - is villager $ game' ^?! players . angels+ is villager $ game' ^?! players . fallenAngels
− test/src/Game/Werewolf/Test/Command/Reveal.hs
@@ -1,133 +0,0 @@-{-|-Module : Game.Werewolf.Test.Command.Reveal-Copyright : (c) Henry J. Wylde, 2016-License : BSD3-Maintainer : public@hjwylde.com--}--module Game.Werewolf.Test.Command.Reveal (- -- * Tests- allRevealCommandTests,-) where--import Control.Lens hiding (isn't)--import Data.Maybe--import Game.Werewolf-import Game.Werewolf.Command.DevotedServant-import Game.Werewolf.Test.Arbitrary-import Game.Werewolf.Test.Util--import Test.Tasty-import Test.Tasty.QuickCheck--allRevealCommandTests :: [TestTree]-allRevealCommandTests =- [ testProperty "reveal command errors when game is over" prop_revealCommandErrorsWhenGameIsOver- , testProperty "reveal command errors when caller does not exist" prop_revealCommandErrorsWhenCallerDoesNotExist- , testProperty "reveal command errors when caller is dead" prop_revealCommandErrorsWhenCallerIsDead- , testProperty "reveal command errors when not devoted servant's turn" prop_revealCommandErrorsWhenNotDevotedServantsTurn- , testProperty "reveal command errors when caller not devoted servant" prop_revealCommandErrorsWhenCallerNotDevotedServant- , 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 orphan" prop_revealCommandResetsRoleWhenOrphan- , testProperty "reveal command resets role when witch" prop_revealCommandResetsRoleWhenWitch- , testProperty "reveal command resets role when wolf-hound" prop_revealCommandResetsRoleWhenWolfHound- ]--prop_revealCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property-prop_revealCommandErrorsWhenGameIsOver (GameAtGameOver game) =- forAll (arbitraryRevealCommand game) $ verbose_runCommandErrors game . getBlind--prop_revealCommandErrorsWhenCallerDoesNotExist :: GameAtDevotedServantsTurn -> Player -> Property-prop_revealCommandErrorsWhenCallerDoesNotExist (GameAtDevotedServantsTurn game) caller = do- let command = revealCommand $ caller ^. name-- not (doesPlayerExist (caller ^. name) game)- ==> verbose_runCommandErrors game command--prop_revealCommandErrorsWhenCallerIsDead :: GameAtDevotedServantsTurn -> Property-prop_revealCommandErrorsWhenCallerIsDead (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let game' = killPlayer devotedServantsName game- let command = revealCommand devotedServantsName-- verbose_runCommandErrors game' command--prop_revealCommandErrorsWhenNotDevotedServantsTurn :: Game -> Property-prop_revealCommandErrorsWhenNotDevotedServantsTurn game =- hasn't (stage . _DevotedServantsTurn) game- ==> forAll (arbitraryRevealCommand game) $ verbose_runCommandErrors game . getBlind--prop_revealCommandErrorsWhenCallerNotDevotedServant :: GameAtDevotedServantsTurn -> Property-prop_revealCommandErrorsWhenCallerNotDevotedServant (GameAtDevotedServantsTurn game) =- forAll (suchThat (arbitraryPlayer game) (isn't devotedServant)) $ \caller -> do- let command = revealCommand $ caller ^. name-- verbose_runCommandErrors game command--prop_revealCommandSetsCallersRole :: GameAtDevotedServantsTurn -> Property-prop_revealCommandSetsCallersRole (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = revealCommand devotedServantsName- let game' = run_ (apply command) game-- game' ^?! players . traverse . filteredBy name devotedServantsName . role === target ^. role- where- target = head $ getVoteResult game--prop_revealCommandSetsTargetsRole :: GameAtDevotedServantsTurn -> Bool-prop_revealCommandSetsTargetsRole (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = revealCommand devotedServantsName- let game' = run_ (apply command) game-- is devotedServant $ game' ^?! players . traverse . filteredBy name targetsName- where- targetsName = head (getVoteResult game) ^. name--prop_revealCommandResetsRoleWhenJester :: GameAtDevotedServantsTurn -> Bool-prop_revealCommandResetsRoleWhenJester (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = revealCommand devotedServantsName- let game'' = run_ (apply command) game'-- not $ game'' ^. jesterRevealed- where- targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ jesterRole & jesterRevealed .~ True--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'-- isNothing $ game'' ^. roleModel- where- targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ orphanRole & roleModel .~ Just targetsName--prop_revealCommandResetsRoleWhenWitch :: GameAtDevotedServantsTurn -> Bool-prop_revealCommandResetsRoleWhenWitch (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = revealCommand devotedServantsName- let game'' = run_ (apply command) game'-- not (game'' ^. healUsed) && not (game'' ^. poisonUsed)- where- targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ witchRole & healUsed .~ True & poisonUsed .~ True--prop_revealCommandResetsRoleWhenWolfHound :: GameAtDevotedServantsTurn -> Bool-prop_revealCommandResetsRoleWhenWolfHound (GameAtDevotedServantsTurn game) = do- let devotedServantsName = game ^?! players . devotedServants . name- let command = revealCommand devotedServantsName- let game'' = run_ (apply command) game'-- not $ game'' ^. allegianceChosen- where- targetsName = head (getVoteResult game) ^. name- game' = game & players . traverse . filteredBy name targetsName . role .~ wolfHoundRole & allegianceChosen .~ True
test/src/Game/Werewolf/Test/Engine.hs view
@@ -21,8 +21,7 @@ import Game.Werewolf import Game.Werewolf.Test.Arbitrary-import Game.Werewolf.Test.Engine.Angel-import Game.Werewolf.Test.Engine.DevotedServant+import Game.Werewolf.Test.Engine.FallenAngel import Game.Werewolf.Test.Engine.Hunter import Game.Werewolf.Test.Engine.Lynching import Game.Werewolf.Test.Engine.Orphan@@ -32,7 +31,6 @@ 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)@@ -43,8 +41,7 @@ allEngineTests :: [TestTree] allEngineTests = concat- [ allAngelEngineTests- , allDevotedServantEngineTests+ [ allFallenAngelEngineTests , allHunterEngineTests , allLynchingEngineTests , allOrphanEngineTests@@ -54,7 +51,6 @@ , allVillageEngineTests , allWerewolfEngineTests , allWitchEngineTests- , allWolfHoundEngineTests , allGameOverTests , allStartGameTests@@ -62,10 +58,10 @@ 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 game over advances stage when one allegiance alive" prop_checkGameOverAdvancesStageWhenOneAllegianceAlive+ , testProperty "check game over advances stage when after first round and fallen angel dead" prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndFallenAngelDead+ , testProperty "check game over does nothing when fallen angel dead but aligned with villagers" prop_checkGameOverDoesNothingWhenFallenAngelDeadButAlignedWithVillagers+ , testProperty "check game over does nothing when game over" prop_checkGameOverDoesNothingWhenGameOver ] allStartGameTests :: [TestTree]@@ -93,17 +89,17 @@ -- length (nub . map (view $ role . allegiance) . filterAlive $ game ^. players) > 1 -- ==> not . is gameOver $ run_ checkGameOver game -prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndAngelDead :: GameOnSecondRound -> Bool-prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndAngelDead (GameOnSecondRound game) = do- let angelsName = game ^?! players . angels . name- let game' = killPlayer angelsName game+prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndFallenAngelDead :: GameOnSecondRound -> Bool+prop_checkGameOverAdvancesStageWhenAfterFirstRoundAndFallenAngelDead (GameOnSecondRound game) = do+ let fallenAngelsName = game ^?! players . fallenAngels . name+ let game' = killPlayer fallenAngelsName game has (stage . _GameOver) $ run_ checkGameOver game' -prop_checkGameOverDoesNothingWhenAngelDeadButAlignedWithVillagers :: GameOnSecondRound -> Bool-prop_checkGameOverDoesNothingWhenAngelDeadButAlignedWithVillagers (GameOnSecondRound game) = do- let angelsName = game ^?! players . angels . name- let game' = killPlayer angelsName game & players . traverse . filteredBy name angelsName . role . allegiance .~ Villagers+prop_checkGameOverDoesNothingWhenFallenAngelDeadButAlignedWithVillagers :: GameOnSecondRound -> Bool+prop_checkGameOverDoesNothingWhenFallenAngelDeadButAlignedWithVillagers (GameOnSecondRound game) = do+ let fallenAngelsName = game ^?! players . fallenAngels . name+ let game' = killPlayer fallenAngelsName game & players . traverse . filteredBy name fallenAngelsName . role . allegiance .~ Villagers hasn't (stage . _GameOver) $ run_ checkGameOver game'
− test/src/Game/Werewolf/Test/Engine/Angel.hs
@@ -1,39 +0,0 @@-{-|-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
@@ -1,57 +0,0 @@-{-|-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/FallenAngel.hs view
@@ -0,0 +1,39 @@+{-|+Module : Game.Werewolf.Test.Engine.FallenAngel+Copyright : (c) Henry J. Wylde, 2016+License : BSD3+Maintainer : public@hjwylde.com+-}++module Game.Werewolf.Test.Engine.FallenAngel (+ -- * Tests+ allFallenAngelEngineTests,+) 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++allFallenAngelEngineTests :: [TestTree]+allFallenAngelEngineTests =+ [ testProperty "check sunrise increments round" prop_checkSunriseIncrementsRound+ , testProperty "check sunrise sets fallen angel's allegiance" prop_checkSunriseSetsFallenAngelsAllegiance+ ]++prop_checkSunriseIncrementsRound :: GameAtSunrise -> Property+prop_checkSunriseIncrementsRound (GameAtSunrise game) =+ run_ checkStage game ^. round === game ^. round + 1++prop_checkSunriseSetsFallenAngelsAllegiance :: GameAtSunrise -> Bool+prop_checkSunriseSetsFallenAngelsAllegiance (GameAtSunrise game) = do+ let game' = run_ checkStage game++ is villager $ game' ^?! players . fallenAngels
test/src/Game/Werewolf/Test/Engine/Lynching.hs view
@@ -41,8 +41,8 @@ hasn't (stage . _Lynching) game' -prop_checkLynchingLynchesOnePlayerWhenConsensus :: GameWithPassAtDevotedServantsTurn -> Property-prop_checkLynchingLynchesOnePlayerWhenConsensus (GameWithPassAtDevotedServantsTurn game) =+prop_checkLynchingLynchesOnePlayerWhenConsensus :: GameWithMajorityVote -> Property+prop_checkLynchingLynchesOnePlayerWhenConsensus (GameWithMajorityVote game) = isn't jester target ==> length (run_ checkStage game ^.. players . traverse . dead) == 1 where@@ -71,12 +71,9 @@ 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_checkLynchingResetsVotes :: GameWithMajorityVote -> Bool+prop_checkLynchingResetsVotes (GameWithMajorityVote game) =+ Map.null $ run_ checkStage game ^. votes prop_checkLynchingSetsAllowedVoters :: GameWithLynchVotes -> Property prop_checkLynchingSetsAllowedVoters (GameWithLynchVotes game) =
test/src/Game/Werewolf/Test/Engine/Orphan.hs view
@@ -15,7 +15,6 @@ 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@@ -63,10 +62,7 @@ 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+ isn't fallenAngel roleModel' && isn't hunter roleModel' && isn't jester roleModel'+ ==> is werewolf $ run_ checkStage game' ^?! players . orphans where roleModel' = game ^?! players . traverse . filteredBy name (fromJust $ game ^. roleModel)
test/src/Game/Werewolf/Test/Engine/Scapegoat.hs view
@@ -24,9 +24,8 @@ 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+ , testProperty "check scapegoat's turn advances to seer's turn" prop_checkScapegoatsTurnAdvancesToSeersTurn+ , testProperty "check scapegoat's turn does nothing while scapegoat blamed" prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed ] prop_checkStageSkipsScapegoatsTurnWhenNoScapegoat :: GameWithConflictingVote -> Bool@@ -36,15 +35,9 @@ 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_checkScapegoatsTurnAdvancesToSeersTurn :: GameWithAllowedVoters -> Bool+prop_checkScapegoatsTurnAdvancesToSeersTurn (GameWithAllowedVoters game) =+ has (stage . _SeersTurn) (run_ checkStage game) prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed :: GameAtScapegoatsTurn -> Bool prop_checkScapegoatsTurnDoesNothingWhileScapegoatBlamed (GameAtScapegoatsTurn game) =
test/src/Game/Werewolf/Test/Engine/Seer.hs view
@@ -32,8 +32,8 @@ , testProperty "check seer's turn does nothing unless seen" prop_checkSeersTurnDoesNothingUnlessSeen ] -prop_checkStageSkipsSeersTurnWhenNoSeer :: GameWithPassAtDevotedServantsTurn -> Bool-prop_checkStageSkipsSeersTurnWhenNoSeer (GameWithPassAtDevotedServantsTurn game) =+prop_checkStageSkipsSeersTurnWhenNoSeer :: GameWithMajorityVote -> Bool+prop_checkStageSkipsSeersTurnWhenNoSeer (GameWithMajorityVote game) = hasn't (stage . _SeersTurn) game' where seersName = game ^?! players . seers . name
test/src/Game/Werewolf/Test/Engine/Village.hs view
@@ -20,32 +20,33 @@ import Test.Tasty import Test.Tasty.QuickCheck +-- TODO (hjw): merge with lynching tests 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 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')+ forAll (arbitraryPassCommand game') $ \(Blind command) -> do+ hasn't (stage . _VillagesTurn) (run_ (apply command >> 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_checkVillagesTurnAdvancesToDevotedServantsTurn :: GameWithMajorityVote -> Property+--prop_checkVillagesTurnAdvancesToDevotedServantsTurn (GameWithMajorityVote game) =+-- isn't fallenAngel 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_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted :: GameWithConflictingVote -> Bool+--prop_checkVillagesTurnSkipsDevotedServantsTurnWhenConflicted (GameWithConflictingVote game) =+-- hasn't (stage . _DevotedServantsTurn) (run_ checkStage game) prop_checkVillagesTurnDoesNothingUnlessAllVoted :: GameAtVillagesTurn -> Property prop_checkVillagesTurnDoesNothingUnlessAllVoted (GameAtVillagesTurn game) =
test/src/Game/Werewolf/Test/Engine/Witch.hs view
@@ -40,7 +40,7 @@ prop_checkStageSkipsWitchsTurnWhenNoWitch :: GameWithDevourVotes -> Property prop_checkStageSkipsWitchsTurnWhenNoWitch (GameWithDevourVotes game) =- null (run_ checkStage game' ^.. players . angels . dead)+ null (run_ checkStage game' ^.. players . fallenAngels . dead) ==> hasn't (stage . _WitchsTurn) game' where witchsName = game ^?! players . witches . name@@ -48,7 +48,7 @@ prop_checkWitchsTurnAdvancesToVillagesTurn :: GameAtWitchsTurn -> Property prop_checkWitchsTurnAdvancesToVillagesTurn (GameAtWitchsTurn game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->+ forAll (arbitraryPassCommand game) $ \(Blind command) -> has (stage . _VillagesTurn) (run_ (apply command >> checkStage) game) prop_checkWitchsTurnAdvancesWhenNoWitch :: GameAtWitchsTurn -> Bool@@ -60,17 +60,17 @@ prop_checkWitchsTurnHealsDevoureeWhenHealed :: GameWithHeal -> Property prop_checkWitchsTurnHealsDevoureeWhenHealed (GameWithHeal game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) ->+ forAll (arbitraryPassCommand 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) ->+ forAll (arbitraryPassCommand 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+ forAll (arbitraryPassCommand game) $ \(Blind command) -> do let game' = run_ (apply command >> checkStage) game none (is dead) $ game' ^. players@@ -83,21 +83,21 @@ prop_checkWitchsTurnResetsHeal :: GameWithHeal -> Property prop_checkWitchsTurnResetsHeal (GameWithHeal game) =- forAll (arbitraryWitchPassCommand game) $ \(Blind command) -> do+ forAll (arbitraryPassCommand 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+ forAll (arbitraryPassCommand 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+ forAll (arbitraryPassCommand game) $ \(Blind command) -> do let game' = run_ (apply command >> checkStage) game not $ game' ^. passed
− test/src/Game/Werewolf/Test/Engine/WolfHound.hs
@@ -1,56 +0,0 @@-{-|-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
@@ -22,37 +22,36 @@ allGameTests :: [TestTree] allGameTests =- [ 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 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 votes empty" prop_newGameStartsWithVotesEmpty+ [ testProperty "new game starts at village's turn when fallen angel in play" prop_newGameStartsAtVillagesTurnWhenFallenAngelInPlay+ , testProperty "new game starts at sunset when no fallen angel in play" prop_newGameStartsAtSunsetWhenNoFallenAngelInPlay+ , 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 boots empty" prop_newGameStartsWithBootsEmpty+ , 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 votes empty" prop_newGameStartsWithVotesEmpty ] -prop_newGameStartsAtVillagesTurnWhenAngelInPlay :: [Player] -> Property-prop_newGameStartsAtVillagesTurnWhenAngelInPlay players =- has angels players+prop_newGameStartsAtVillagesTurnWhenFallenAngelInPlay :: [Player] -> Property+prop_newGameStartsAtVillagesTurnWhenFallenAngelInPlay players =+ has fallenAngels players ==> has (stage . _VillagesTurn) (newGame players) -prop_newGameStartsAtSunsetWhenNoAngelInPlay :: [Player] -> Property-prop_newGameStartsAtSunsetWhenNoAngelInPlay players =- hasn't angels players+prop_newGameStartsAtSunsetWhenNoFallenAngelInPlay :: [Player] -> Property+prop_newGameStartsAtSunsetWhenNoFallenAngelInPlay players =+ hasn't fallenAngels players ==> has (stage . _Sunset) (newGame players) prop_newGameStartsOnFirstRound :: [Player] -> Bool@@ -66,9 +65,6 @@ 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
werewolf.cabal view
@@ -1,5 +1,5 @@ name: werewolf-version: 0.5.2.0+version: 0.5.3.0 author: Henry J. Wylde maintainer: public@hjwylde.com@@ -40,7 +40,6 @@ Werewolf.Command.Poison Werewolf.Command.Protect Werewolf.Command.Quit- Werewolf.Command.Reveal Werewolf.Command.See Werewolf.Command.Start Werewolf.Command.Status@@ -76,7 +75,6 @@ exposed-modules: Game.Werewolf Game.Werewolf.Command- Game.Werewolf.Command.DevotedServant Game.Werewolf.Command.Global Game.Werewolf.Command.Hunter Game.Werewolf.Command.Orphan@@ -87,7 +85,6 @@ Game.Werewolf.Command.Villager Game.Werewolf.Command.Werewolf Game.Werewolf.Command.Witch- Game.Werewolf.Command.WolfHound Game.Werewolf.Engine Game.Werewolf.Game Game.Werewolf.Player@@ -132,12 +129,10 @@ Game.Werewolf.Test.Command.Poison Game.Werewolf.Test.Command.Protect Game.Werewolf.Test.Command.Quit- Game.Werewolf.Test.Command.Reveal 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.FallenAngel Game.Werewolf.Test.Engine.Hunter Game.Werewolf.Test.Engine.Lynching Game.Werewolf.Test.Engine.Orphan@@ -147,7 +142,6 @@ 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