packages feed

Nomyx-0.1.0: src/Game.hs

{-# LANGUAGE StandaloneDeriving, GADTs, DeriveDataTypeable,
    FlexibleContexts, GeneralizedNewtypeDeriving,
    MultiParamTypeClasses, TemplateHaskell, TypeFamilies,
    TypeOperators, FlexibleInstances, NoMonomorphismRestriction,
    TypeSynonymInstances #-}

-- | This module implements Game management.
-- a game is a set of rules, and results of actions made by players (usually vote results)
-- the module manages the effects of rules over each others.
module Game (initialGame, activeRules, execWithGame, pendingRules, rejectedRules) where

import Language.Nomyx.Rule
import Control.Monad.State
import Data.List
import Language.Nomyx.Expression
import Language.Nomyx.Evaluation
import Language.Nomyx.Examples

-- | the initial rule set for a game.
rVoteUnanimity = Rule  {
    rNumber       = 1,
    rName         = "Unanimity Vote",
    rDescription  = "A proposed rule will be activated if all players vote for it",
    rProposedBy   = 0,
    rRuleCode     = "onRuleProposed $ voteWith unanimity",
    rRuleFunc     = onRuleProposed $ voteWith unanimity,
    rStatus       = Active,
    rAssessedBy   = Nothing}

rVictory5Rules = Rule  {
    rNumber       = 2,
    rName         = "Victory 5 accepted rules",
    rDescription  = "Victory is achieved if you have 5 active rules",
    rProposedBy   = 0,
    rRuleCode     = "victoryXRules 5",
    rRuleFunc     = victoryXRules 5,
    rStatus       = Active,
    rAssessedBy   = Nothing}

emptyGame name desc date = Game { gameName      = name,
                             gameDesc      = desc,
                             rules         = [],
                             players       = [],
                             variables     = [],
                             events        = [],
                             outputs       = [],
                             victory       = [],
                             currentTime   = date}

initialGame :: GameName -> String -> UTCTime -> Game
initialGame name desc date = flip execState (emptyGame name desc date) $ do
    evAddRule rVoteUnanimity
    evActivateRule (rNumber rVoteUnanimity) 0
    evAddRule rVictory5Rules
    evActivateRule (rNumber rVictory5Rules) 0

-- | the initial rule set for a game.
rApplicationMetaRule = Rule  {
    rNumber       = 0,
    rName         = "Evaluate rule using meta-rules",
    rDescription  = "a proposed rule will be activated if all active metarules return true",
    rProposedBy   = 0,
    rRuleCode     = "applicationMetaRule",
    rRuleFunc     = onRuleProposed checkWithMetarules,
    rStatus       = Active,
    rAssessedBy   = Nothing}

-- | An helper function to use the state transformer GameState.
-- It additionally sets the current time.
execWithGame :: UTCTime -> State Game () -> Game -> Game
execWithGame t gs g = execState gs g {currentTime = t}


--accessors

activeRules :: Game -> [Rule]
activeRules = sort . filter (\(Rule {rStatus=rs}) -> rs==Active) . rules

pendingRules :: Game -> [Rule]
pendingRules = sort . filter (\(Rule {rStatus=rs}) -> rs==Pending) . rules

rejectedRules :: Game -> [Rule]
rejectedRules = sort . filter (\(Rule {rStatus=rs}) -> rs==Reject) . rules

instance Ord PlayerInfo where
   h <= g = (playerNumber h) <= (playerNumber g)