Archived
1
0
Fork 0

Simplified and greatly improved scoring for the duck game.

This commit is contained in:
Julien Dessaux 2011-06-05 01:12:46 +02:00
parent bc8299374e
commit 066b271510

View file

@ -22,46 +22,29 @@ import Hsbot.Message
import Hsbot.Types import Hsbot.Types
import Hsbot.Utils import Hsbot.Utils
-- | A user statistic
data Stat = Stat
{ statRounds :: Int
, statShot :: Int
, statKilled :: Int
} deriving (Show, Typeable)
-- | Default values for new stat
emptyStat :: Stat
emptyStat = Stat { statRounds = 0
, statShot = 0
, statKilled = 0 }
-- The statistics database -- The statistics database
data StatDB = StatDB data StatDB = StatDB
{ nickStats :: M.Map String Stat { nickStats :: M.Map String Int
} deriving (Show, Typeable) } deriving (Show, Typeable)
-- | Statistics database initial state -- | Statistics database initial state
emptyStatDB :: StatDB emptyStatDB :: StatDB
emptyStatDB = StatDB { nickStats = M.empty } emptyStatDB = StatDB { nickStats = M.empty }
$(deriveSafeCopy 0 'base ''Stat)
$(deriveSafeCopy 0 'base ''StatDB) $(deriveSafeCopy 0 'base ''StatDB)
-- | Statistics database transactions -- | Statistics database transactions
scoreAction :: String -> Int -> Int -> Int -> Update StatDB () updateScore :: String -> Int -> Update StatDB ()
scoreAction sender rounds shots kills = do updateScore sender score = do
statDB <- get statDB <- get
let stats = nickStats statDB let stats = nickStats statDB
stat = fromMaybe emptyStat $ M.lookup sender stats stat = fromMaybe 0 $ M.lookup sender stats
stat' = stat { statRounds = rounds + statRounds stat put statDB { nickStats = M.insert sender (stat + score) stats }
, statShot = shots + statShot stat
, statKilled = kills + statKilled stat }
put statDB { nickStats = M.insert sender stat' stats }
getDuckStats :: Query StatDB StatDB getDuckStats :: Query StatDB StatDB
getDuckStats = ask getDuckStats = ask
$(makeAcidic ''StatDB ['getDuckStats, 'scoreAction]) $(makeAcidic ''StatDB ['getDuckStats, 'updateScore])
-- | The duck plugin identity -- | The duck plugin identity
duck :: PluginId duck :: PluginId
@ -85,20 +68,18 @@ theDuck channel seconds = do
-- First we kill the ducks that we find in the message -- First we kill the ducks that we find in the message
let kills = howManyDucksInThere . concat $ IRC.msg_params msg let kills = howManyDucksInThere . concat $ IRC.msg_params msg
when (kills /= "") $ answerMsg msg kills when (kills /= "") $ answerMsg msg kills
-- Then we check if someone shot some duck
when (getDestination msg == channel) $ do when (getDestination msg == channel) $ do
-- Then we check if someone shot some duck
let shots = howManyBulletFiredInThere . concat $ IRC.msg_params msg let shots = howManyBulletFiredInThere . concat $ IRC.msg_params msg
when (shots > 0) $ do when (shots > 0) $ do
_ <- update' statDB (ScoreAction (getSender msg) 0 shots 0) empty <- liftIO $ isEmptyMVar ducksMVar
noDucksToShoot <- liftIO $ isEmptyMVar ducksMVar ducksWaitingForDeath <- if empty then return 0
unless noDucksToShoot $ do else liftIO $ modifyMVar ducksMVar (\x -> return (x - shots, x))
ducksWaitingForDeath <- liftIO $ modifyMVar ducksMVar (\x -> return (x - shots, x)) _ <- update' statDB . UpdateScore (getSender msg) $ computeScore ducksWaitingForDeath shots
_ <- update' statDB (ScoreAction (getSender msg) 0 0 (min ducksWaitingForDeath shots)) when (and [ ducksWaitingForDeath > 0, shots >= ducksWaitingForDeath ]) $ do
when (shots >= ducksWaitingForDeath) $ do
_ <- liftIO $ takeMVar ducksMVar _ <- liftIO $ takeMVar ducksMVar
time <- liftIO $ readMVar timeMVar time <- liftIO $ readMVar timeMVar
duckSpawner channel time ducksMVar duckSpawner channel time ducksMVar
_ <- update' statDB (ScoreAction (getSender msg) 1 0 0)
return () return ()
-- Finally we check if we received some command -- Finally we check if we received some command
cmdArgs <- lift $ getCommand msg cmdArgs <- lift $ getCommand msg
@ -113,6 +94,11 @@ theDuck channel seconds = do
_ -> return () _ -> return ()
| otherwise = return () | otherwise = return ()
eval _ _ _ _ = return () eval _ _ _ _ = return ()
computeScore :: Int -> Int -> Int
computeScore ducksWaitingForDeath shots
| shots < ducksWaitingForDeath = shots - 1
| shots == ducksWaitingForDeath = shots + 1
| otherwise = negate shots
-- | Spawns ducks on a channel, just waiting to be shot -- | Spawns ducks on a channel, just waiting to be shot
duckSpawner :: String -> Int -> MVar Int -> Plugin (Env IO) () duckSpawner :: String -> Int -> MVar Int -> Plugin (Env IO) ()
@ -162,9 +148,8 @@ printDuckStats channel statDB = do
sendLine "Duck slaughter simulator - Hall of Fame" sendLine "Duck slaughter simulator - Hall of Fame"
mapM_ (sendLine . buildLine) $ M.toList (nickStats statDB) mapM_ (sendLine . buildLine) $ M.toList (nickStats statDB)
where where
buildLine :: (String, Stat) -> String buildLine :: (String, Int) -> String
buildLine (nick, stat) = concat [ nick, ": ", show $ statRounds stat, " rounds won, ", show $ statShot stat buildLine (nick, score) = concat [ nick, ": ", show score ]
, " shots fired, ", show $ statKilled stat, " ducks killed" ]
sendLine :: String -> Plugin (Env IO) () sendLine :: String -> Plugin (Env IO) ()
sendLine msg = writeMsg . OutgoingMsg $ IRC.Message Nothing "PRIVMSG" [channel, msg] sendLine msg = writeMsg . OutgoingMsg $ IRC.Message Nothing "PRIVMSG" [channel, msg]