werewolf-0.4.3.0: test/src/Game/Werewolf/Test/Arbitrary.hs
{-|
Module : Game.Werewolf.Test.Arbitrary
Copyright : (c) Henry J. Wylde, 2015
License : BSD3
Maintainer : public@hjwylde.com
-}
{-# OPTIONS_HADDOCK hide, prune #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Game.Werewolf.Test.Arbitrary (
-- * Initial arbitraries
-- ** Game
arbitraryNewGame, arbitraryGameWithDevourVotes, arbitraryGameWithDevourEventForVillager,
arbitraryGameWithProtect, arbitraryGameWithProtectAndDevourVotes,
-- ** Player
arbitraryPlayerSet,
-- * Contextual arbitraries
-- ** Command
arbitraryCommand, arbitraryDevourVoteCommand, arbitraryHealCommand, arbitraryLynchVoteCommand,
arbitraryPassCommand, arbitraryPoisonCommand, arbitraryProtectCommand, arbitraryQuitCommand,
arbitrarySeeCommand, runArbitraryCommands,
-- ** Player
arbitraryPlayer, arbitraryDefender, arbitrarySeer, arbitraryWerewolf, arbitraryWitch,
) where
import Control.Lens hiding (elements)
import Data.List.Extra
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T
import Game.Werewolf.Command
import Game.Werewolf.Engine (checkStage)
import Game.Werewolf.Game
import Game.Werewolf.Player
import Game.Werewolf.Role hiding (name, _name)
import Game.Werewolf.Test.Util
import Test.QuickCheck
instance Show Command where
show _ = "command"
instance Arbitrary Game where
arbitrary = do
game <- arbitraryNewGame
stage <- arbitrary
return $ game { _stage = stage }
instance Arbitrary Stage where
arbitrary = elements
[GameOver, DefendersTurn, SeersTurn, VillagesTurn, WerewolvesTurn, WitchsTurn]
instance Arbitrary Player where
arbitrary = newPlayer <$> arbitrary <*> arbitrary
instance Arbitrary State where
arbitrary = elements [Alive, Dead]
instance Arbitrary Role where
arbitrary = elements allRoles
instance Arbitrary Text where
arbitrary = T.pack <$> vectorOf 6 (elements ['a'..'z'])
arbitraryNewGame :: Gen Game
arbitraryNewGame = newGame <$> arbitraryPlayerSet
arbitraryGameWithDevourVotes :: Gen Game
arbitraryGameWithDevourVotes = arbitrary >>= runArbitraryDevourVoteCommands
arbitraryGameWithDevourEvent :: Gen Game
arbitraryGameWithDevourEvent = do
game <- suchThat arbitraryGameWithDevourVotes $ \game -> length (getVoteResult game) == 1
return $ run_ checkStage game
arbitraryGameWithDevourEventForVillager :: Gen Game
arbitraryGameWithDevourEventForVillager =
suchThat arbitraryGameWithDevourEvent $ \game -> all isVillager (filterDead $ game ^. players)
arbitraryGameWithProtect :: Gen Game
arbitraryGameWithProtect = do
game <- arbitrary
let game' = game { _stage = DefendersTurn }
command <- arbitraryProtectCommand game'
return $ run_ (apply command) game'
arbitraryGameWithProtectAndDevourVotes :: Gen Game
arbitraryGameWithProtectAndDevourVotes = arbitraryGameWithProtect >>= runArbitraryDevourVoteCommands
arbitraryPlayerSet :: Gen [Player]
arbitraryPlayerSet = do
n <- choose (10, 24)
players <- nubOn _name <$> infiniteList
let defender = head $ filterDefenders players
let scapegoat = head $ filterScapegoats players
let seer = head $ filterSeers players
let villagerVillager = head $ filterVillagerVillagers players
let witch = head $ filterWitches players
let werewolves = take (n `quot` 6 + 1) $ filterWerewolves players
let villagers = take (n - 5 - (length werewolves)) $ filterVillagers players
return $ defender:scapegoat:seer:villagerVillager:witch:werewolves ++ villagers
arbitraryCommand :: Game -> Gen Command
arbitraryCommand game = case game ^. stage of
GameOver -> return noopCommand
DefendersTurn -> arbitraryProtectCommand game
Sunrise -> return noopCommand
Sunset -> return noopCommand
SeersTurn -> arbitrarySeeCommand game
VillagesTurn -> arbitraryLynchVoteCommand game
WerewolvesTurn -> arbitraryDevourVoteCommand game
WitchsTurn -> oneof [
arbitraryHealCommand game,
arbitraryPassCommand game,
arbitraryPoisonCommand game
]
arbitraryDevourVoteCommand :: Game -> Gen Command
arbitraryDevourVoteCommand game = do
let applicableCallers = filterWerewolves $ getPendingVoters game
target <- suchThat (arbitraryPlayer game) $ not . isWerewolf
if null applicableCallers
then return noopCommand
else elements applicableCallers >>= \caller ->
return $ devourVoteCommand (caller ^. name) (target ^. name)
arbitraryLynchVoteCommand :: Game -> Gen Command
arbitraryLynchVoteCommand game = do
let applicableCallers = getPendingVoters game
target <- arbitraryPlayer game
if null applicableCallers
then return noopCommand
else elements applicableCallers >>= \caller ->
return $ lynchVoteCommand (caller ^. name) (target ^. name)
arbitraryHealCommand :: Game -> Gen Command
arbitraryHealCommand game = do
let witch = head . filterWitches $ game ^. players
return $ if game ^. healUsed
then noopCommand
else seq (fromJust (getDevourEvent game)) $ healCommand (witch ^. name)
arbitraryPassCommand :: Game -> Gen Command
arbitraryPassCommand game = do
witch <- arbitraryWitch game
return $ passCommand (witch ^. name)
arbitraryPoisonCommand :: Game -> Gen Command
arbitraryPoisonCommand game = do
let witch = head . filterWitches $ game ^. players
target <- arbitraryPlayer game
return $ if isJust (game ^. poison)
then noopCommand
else poisonCommand (witch ^. name) (target ^. name)
arbitraryProtectCommand :: Game -> Gen Command
arbitraryProtectCommand game = do
let defender = head . filterDefenders $ game ^. players
target <- suchThat (arbitraryPlayer game) (defender /=)
return $ if isJust (game ^. protect)
then noopCommand
else protectCommand (defender ^. name) (target ^. name)
arbitraryQuitCommand :: Game -> Gen Command
arbitraryQuitCommand game = do
let applicableCallers = filterAlive $ game ^. players
if null applicableCallers
then return noopCommand
else elements applicableCallers >>= \caller -> return $ quitCommand (caller ^. name)
arbitrarySeeCommand :: Game -> Gen Command
arbitrarySeeCommand game = do
let seer = head . filterSeers $ game ^. players
target <- arbitraryPlayer game
return $ if isJust (game ^. see)
then noopCommand
else seeCommand (seer ^. name) (target ^. name)
runArbitraryCommands :: Int -> Game -> Gen Game
runArbitraryCommands n = iterateM n $ \game -> do
command <- arbitraryCommand game
return $ run_ (apply command) game
runArbitraryDevourVoteCommands :: Game -> Gen Game
runArbitraryDevourVoteCommands game = do
let game' = game { _stage = WerewolvesTurn }
let n = length . filterWerewolves $ game' ^. players
runArbitraryCommands n game'
iterateM :: Monad m => Int -> (a -> m a) -> a -> m a
iterateM 0 _ a = return a
iterateM n f a = f a >>= iterateM (n - 1) f
arbitraryPlayer :: Game -> Gen Player
arbitraryPlayer = elements . filterAlive . _players
arbitraryDefender :: Game -> Gen Player
arbitraryDefender = elements . filterAlive . filterDefenders . _players
arbitrarySeer :: Game -> Gen Player
arbitrarySeer = elements . filterAlive . filterSeers . _players
arbitraryWerewolf :: Game -> Gen Player
arbitraryWerewolf = elements . filterAlive . filterWerewolves . _players
arbitraryWitch :: Game -> Gen Player
arbitraryWitch = elements . filterAlive . filterWitches . _players