packages feed

hanabi-dealer-0.10.1.0: Game/Hanabi/Strategies/StatefulStrategy.hs

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
module Game.Hanabi.Strategies.StatefulStrategy where
import Game.Hanabi hiding (main)
import Game.Hanabi.Strategies.SimpleStrategy
import System.Random
import Data.Maybe(isNothing)
import Data.List(sortOn)
import Data.Bits(bit, (.&.))
import qualified Data.IntMap as IM

-- An example of a strategy with state.
newtype Stateful = SF [Annotation]

lookupOn :: Eq b => (a -> b) -> a -> [a] -> [a]
lookupOn fun key xs = [ result | result <- xs, fun key == fun result ]

instance Monad m => Strategy Stateful m where
  strategyName ms = return "Stateful strategy"
  move (pv:pvs) mvs (SF lastGuess) = let
                           consistentGuess = [ case lookupOn ixDeck realAnn $ hintedAnns ++ lastGuess of
                                                 guessedAnn:_ | narrowedPos /= 0 -> realAnn{possibilities = (fst realPos, narrowedPos)}
                                                              where narrowedPos = snd realPos .&. snd (possibilities guessedAnn)
                                                                    realPos = possibilities realAnn
                                                 _            -> realAnn
                                             | realAnn <- myAnns ]

                           hintedColors = [ c | (p, Hint q (Left c)) <- zip [1..] $ take (numPlayers $ gameSpec pub) mvs,
                                                p==q,
                                                not $ or [ isObviouslyPlayable pub m | Ann{marks=(Just i, _),possibilities=m} <- myAnns, c==i ] -- Exclude if there is a playable card with the color.
                                              ]
                           hintedAnns = [ ann{possibilities = (fst $ possibilities ann, newNumberPos)}
                                                | c <- hintedColors,
                                                  let i   = length $ takeWhile ((/=Just c) . fst . marks) myAnns
                                                      ann = myAnns !! i
                                                      newNumberPos = bit $ rankToBitPos (succ $ achievedRank pub c), -- This is undefined when achievedRank pub c == K5, but then isDefinitelyUnplayable pv ann should be True.
                                                  not $ isDefinitelyUnplayable pv ann,
                                                  newNumberPos .&. snd (possibilities ann) /= 0 ]
                           pub = publicView pv
                           myAnns = head $ annotations pub
                       in move (pv{publicView=pub{annotations=consistentGuess : tail (annotations pub)}} : pvs) mvs S >>= \(mov,S) -> return (mov, SF consistentGuess)

main = do g <- newStdGen
          ((eg,_),_) <- start defaultGS [] ([SF[]],[stdio]) g -- Play it with standard I/O (human player).
--          ((eg,_),_) <- start defaultGS [peek] [SF[],SF[]] g -- Play it with itself.
          putStrLn $ prettyEndGame eg