module Game.Werewolf.Game (
Game(..), stage, players, events, see, votes,
newGame,
killPlayer,
isGameOver, isSeersTurn, isSunrise, isSunset, isVillagesTurn, isWerewolvesTurn, getPlayerVote,
getPendingVoters, getVoteResult,
Stage(..),
stageCycle, stageAvailable,
Event(..),
) where
import Control.Lens
import Data.List.Extra
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Text (Text)
import Game.Werewolf.Player
import Game.Werewolf.Role hiding (Villagers, Werewolves, _name)
data Game = Game
{ _stage :: Stage
, _players :: [Player]
, _events :: [Event]
, _see :: Maybe Text
, _votes :: Map Text Text
} deriving (Eq, Read, Show)
data Stage = GameOver | SeersTurn | Sunrise | Sunset | VillagesTurn | WerewolvesTurn
deriving (Eq, Read, Show)
data Event = Devour Text
deriving (Eq, Read, Show)
makeLenses ''Game
makeLenses ''Stage
newGame :: [Player] -> Game
newGame players = Game stage players [] Nothing Map.empty
where
stage = head $ filter (stageAvailable aliveRoles) stageCycle
aliveRoles = map _role $ filterAlive players
killPlayer :: Game -> Player -> Game
killPlayer game player = game & players %~ map (\player' -> if player' == player then player' & state .~ Dead else player')
isGameOver :: Game -> Bool
isGameOver game = game ^. stage == GameOver
isSeersTurn :: Game -> Bool
isSeersTurn game = game ^. stage == SeersTurn
isSunrise :: Game -> Bool
isSunrise game = game ^. stage == Sunrise
isSunset :: Game -> Bool
isSunset game = game ^. stage == Sunset
isVillagesTurn :: Game -> Bool
isVillagesTurn game = game ^. stage == VillagesTurn
isWerewolvesTurn :: Game -> Bool
isWerewolvesTurn game = game ^. stage == WerewolvesTurn
getPlayerVote :: Text -> Game -> Maybe Text
getPlayerVote playerName game = game ^. votes . at playerName
getPendingVoters :: Game -> [Player]
getPendingVoters game = filter (flip Map.notMember votes' . _name) alivePlayers
where
votes' = game ^. votes
alivePlayers = filterAlive $ game ^. players
getVoteResult :: Game -> [Player]
getVoteResult game = map (`findByName_` players') result
where
players' = game ^. players
votees = Map.elems $ game ^. votes
result = last $ groupSortOn (\votee -> length $ elemIndices votee votees) (nub votees)
stageCycle :: [Stage]
stageCycle = cycle [Sunset, SeersTurn, WerewolvesTurn, Sunrise, VillagesTurn]
stageAvailable :: [Role] -> Stage -> Bool
stageAvailable _ GameOver = False
stageAvailable aliveRoles SeersTurn = seerRole `elem` aliveRoles
stageAvailable _ Sunrise = True
stageAvailable _ Sunset = True
stageAvailable _ VillagesTurn = True
stageAvailable aliveRoles WerewolvesTurn = werewolfRole `elem` aliveRoles