module ALife.Creatur.Task
(
AgentProgram,
AgentsProgram,
withAgent,
withAgents,
runNoninteractingAgents,
runInteractingAgents,
simpleDaemon,
startupHandler,
shutdownHandler,
exceptionHandler,
nothing
) where
import ALife.Creatur.Daemon (Daemon(..))
import ALife.Creatur.Universe (Universe, Agent, AgentProgram,
AgentsProgram, writeToLog, lineup, refreshLineup, markDone, endOfRound,
withAgent, withAgents, incTime, popSize)
import Control.Conditional (whenM)
import Control.Exception (SomeException)
import Control.Monad.State (StateT, execStateT)
import Data.Serialize (Serialize)
simpleDaemon :: Universe u => Daemon u
simpleDaemon = Daemon
{
onStartup = startupHandler,
onShutdown = shutdownHandler,
onException = exceptionHandler,
task = undefined,
username = "",
sleepTime = 100
}
startupHandler :: Universe u => u -> IO u
startupHandler = execStateT (writeToLog $ "Starting")
shutdownHandler :: Universe u => u -> IO ()
shutdownHandler u = do
_ <- execStateT (writeToLog "Shutdown requested") u
return ()
exceptionHandler :: Universe u => u -> SomeException -> IO (Bool, u)
exceptionHandler u x = do
u' <- execStateT (writeToLog ("WARNING: " ++ show x)) u
return (True, u')
runNoninteractingAgents
:: (Universe u, Serialize (Agent u))
=> AgentProgram u -> (Int, Int) -> StateT u IO () -> StateT u IO ()
-> StateT u IO Bool
runNoninteractingAgents agentProgram popRange startRoundProgram
endRoundProgram = do
atStartOfRound startRoundProgram
as <- lineup
if null as
then return False
else do
let a = head as
markDone a
withAgent agentProgram a
atEndOfRound endRoundProgram
popSizeInBounds popRange
runInteractingAgents
:: (Universe u, Serialize (Agent u))
=> AgentsProgram u -> (Int, Int) -> StateT u IO () -> StateT u IO ()
-> StateT u IO Bool
runInteractingAgents agentsProgram popRange startRoundProgram
endRoundProgram = do
atStartOfRound startRoundProgram
as <- lineup
markDone (head as)
withAgents agentsProgram as
atEndOfRound endRoundProgram
popSizeInBounds popRange
popSizeInBounds :: Universe u => (Int, Int) -> StateT u IO Bool
popSizeInBounds (minAgents, maxAgents) = do
n <- popSize
writeToLog $ "Pop. size=" ++ show n
if n < minAgents
then do
writeToLog "Requesting shutdown (population too small)"
return False
else
if n > maxAgents
then do
writeToLog "Requesting shutdown (population too big)"
return False
else return True
atStartOfRound :: Universe u => StateT u IO () -> StateT u IO ()
atStartOfRound program = do
whenM endOfRound $ do
refreshLineup
incTime
writeToLog "Beginning of round"
program
atEndOfRound :: Universe u => StateT u IO () -> StateT u IO ()
atEndOfRound program = do
whenM endOfRound $ do
writeToLog "End of round"
program
nothing :: StateT u IO ()
nothing = return ()