Skip to content

Commit

Permalink
convenience function for making a game state for some given options a…
Browse files Browse the repository at this point in the history
…nd players
  • Loading branch information
egonSchiele committed Feb 8, 2014
1 parent 349e523 commit e961fb6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 22 deletions.
48 changes: 37 additions & 11 deletions spec/Main.hs
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
import Test.Hspec
import Dominion
import Dominion.Cards
import qualified Dominion.Types as T
import Control.Applicative
import Control.Applicative
import Control.Lens hiding (has, indices, uses)
import Control.Monad.State hiding (state)
import Dominion
import qualified Dominion.Cards as CA
import Dominion.Internal
import qualified Dominion.Types as T
import Prelude hiding (log)
import Test.Hspec

bigMoney playerId = playerId `buysByPreference` [province, gold, duchy, silver, copper]
stupidStrategy playerId = playerId `buysByPreference` [province, gold]
-- | Use this to run a strategy once and inspect the gamestate.
runOnce :: T.Player -> T.Strategy -> IO T.GameState
runOnce player strategy = do
state <- makeGameState [] [player]
snd <$> runStateT (game [strategy]) state

-- | Give a hand of cards and a function. You play one round
-- with this given hand of cards. The function returns True or False.
withHand :: [T.Card] -> (T.PlayerId -> T.Dominion Bool) -> IO Bool
withHand hand func = do
let player = T.Player "testPlayer" (7 `cardsOf` CA.copper ++ 3 `cardsOf` CA.estate) [] hand 1 1 0
state <- makeGameState [] [player]
fst <$> runStateT (func 0) state

bigMoney playerId = playerId `buysByPreference` [CA.province, CA.gold, CA.duchy, CA.silver, CA.copper]
stupidStrategy playerId = playerId `buysByPreference` [CA.province, CA.gold]

bigMoney2 playerId = do
roundNum <- getRound
if (roundNum < 6)
then playerId `buysByPreference` [province, gold, silver]
then playerId `buysByPreference` [CA.province, CA.gold, CA.silver]
else bigMoney playerId

bigMoneySmithy playerId = do
playerId `plays` smithy
playerId `plays` CA.smithy
roundNum <- getRound
if (roundNum < 6)
then playerId `buysByPreference` [province, gold, smithy, silver]
then playerId `buysByPreference` [CA.province, CA.gold, CA.smithy, CA.silver]
else bigMoney playerId

io = flip shouldReturn
Expand All @@ -38,5 +56,13 @@ main = do

it "bigMoneySmithy should win 1.1 times as often as bigMoney2" $ do
io True $ do
winners <- map T.winner <$> dominionWithOpts [Cards [smithy]] ["sherlock" `uses` bigMoneySmithy, "watson" `uses` bigMoney2]
winners <- map T.winner <$> dominionWithOpts [Cards [CA.smithy]] ["sherlock" `uses` bigMoneySmithy, "watson" `uses` bigMoney2]
return $ (count "sherlock" winners) >= (1.1 * (count "watson" winners))

-- silly spec, shows an example of how to use `withHand`
it "market should add to the players cards, buys, money, and actions" $ do
io True $ do
withHand [CA.market, CA.copper, CA.copper, CA.estate, CA.estate] $ \playerId -> do
playerId `plays` CA.market
player <- getPlayer playerId
return $ player ^. T.actions == 1 && player ^. T.extraMoney == 1 && player ^. T.buys == 2
14 changes: 4 additions & 10 deletions src/Dominion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,17 @@ dominion = dominionWithOpts []
-- > dominionWithOpts [Iterations 5, Log True] ["adit" `uses` bigMoney, "maggie" `uses` bigMoney]
dominionWithOpts :: [T.Option] -> [(T.Player, T.Strategy)] -> IO [T.Result]
dominionWithOpts options list = do
actionCards_ <- deckShuffle CA.allActionCards
let actionCards = take (10 - length requiredCards) actionCards_ ++ requiredCards
cards = M.fromList ([(CA.copper, 60), (CA.silver, 40), (CA.gold, 30),
(CA.estate, 12), (CA.duchy, 12), (CA.province, 12)]
++ [(c, 10) | c <- actionCards])
when verbose_ $ putStrLn $ "Playing with: " ++ (join ", " . map T._name $ actionCards)
results <- forM [1..iterations] $ \i -> run (T.GameState (rotate i players) cards 1 verbose_) (rotate i strategies)
results <- forM [1..iterations] $ \i -> do
gameState <- makeGameState options (rotate i players)
run gameState (rotate i strategies)
let winnerNames = map T.winner results
forM_ players $ \player -> do
let name = player ^. T.playerName
putStrLn $ printf "player %s won %d times" name (count name winnerNames)
return results
where (players, strategies) = unzip list
iterations = fromMaybe 1000 (findIteration options)
verbose_ = fromMaybe False (findLog options)
requiredCards = take 10 $ fromMaybe [] (findCards options)


-- | Player buys a card. Example:
--
-- > playerId `buys` smithy
Expand Down
14 changes: 13 additions & 1 deletion src/Dominion/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ module Dominion.Internal (
import Control.Applicative
import Control.Arrow
import Control.Lens hiding (has, indices)
import Control.Monad (liftM)
import Control.Monad (liftM)
import Control.Monad.State hiding (state)
import Data.List
import Data.Map.Lazy ((!))
import qualified Data.Map.Lazy as M
import Data.Maybe
import Data.Ord
import qualified Dominion.Cards as CA
import qualified Dominion.Types as T
Expand Down Expand Up @@ -158,6 +159,17 @@ playTurn playerId strategy = do
-- even if its not their turn.
setupForTurn playerId

makeGameState :: [T.Option] -> [T.Player] -> IO T.GameState
makeGameState options players = do
actionCards_ <- deckShuffle CA.allActionCards
let requiredCards = take 10 $ fromMaybe [] (findCards options)
verbose = fromMaybe False (findLog options)
actionCards = take (10 - length requiredCards) actionCards_ ++ requiredCards
cards = M.fromList ([(CA.copper, 60), (CA.silver, 40), (CA.gold, 30),
(CA.estate, 12), (CA.duchy, 12), (CA.province, 12)]
++ [(c, 10) | c <- actionCards])
return $ T.GameState players cards 1 verbose

game :: [T.Strategy] -> T.Dominion ()
game strategies = do
state <- get
Expand Down

0 comments on commit e961fb6

Please sign in to comment.