dominion-0.1.0.4: A simulator for the board game Dominion.

Safe HaskellNone

Dominion

Synopsis

Documentation

How to use: https://github.com/egonschiele/dominion

uses :: String -> Strategy -> (Player, Strategy)Source

Convenience function. name `uses` strategy is the same as writing (name, strategy)

dominion :: [(Player, Strategy)] -> IO [Result]Source

The main method to simulate a dominion game. Example:

 import Dominion
 import Dominion.Strategies

 main = dominion ["adit" `uses` bigMoney, "maggie" `uses` bigMoney]

dominionWithOpts :: [Option] -> [(Player, Strategy)] -> IO [Result]Source

Same as dominion, but allows you to pass in some options. Example:

 dominionWithOpts [Iterations 5, Log True] ["adit" `uses` bigMoney, "maggie" `uses` bigMoney]

buys :: PlayerId -> Card -> Dominion (PlayResult ())Source

Player buys a card. Example:

 playerId `buys` smithy

buysByPreference :: PlayerId -> [Card] -> Dominion ()Source

Give an array of cards, in order of preference. This function will buy as many cards as possible, in order of preference. For example, suppose you use:

 playerId `buysByPreference` [province, duchy]

And you have 16 money and two buys. You will buy two provinces. This runs all the same validations as buys.

playsByPreference :: PlayerId -> [Card] -> Dominion ()Source

Give an array of cards, in order of preference. This function will try to play as many cards as possible, in order of preference. Note: if any card requires a Followup (like cellar or chapel), you need to use plays instead. This runs all the same validations as plays.

plays :: PlayerId -> Card -> Dominion (PlayResult (Maybe Followup))Source

In the simplest case, this lets you play a card, like this:

 playerId `plays` smithy

You can just use this function blindly, without checking to see if you have enough actions, or whether you have a smithy in your hand. plays will perform those validations for you. It returns a PlayResult, which is an Either with an error message or a return value.

Some cards require an additional action. For example, if you use a workshop, you need to specify what card you're going to get. In that case, this function returns a Followup. A Followup just contains some information about the card you used. You can use the extra action of the card like this:

 playerId `plays` workshop `with` (Workshop gardens)

with takes a FollowUp and a FollowupAction, and applies the FollowupAction. Here's another example:

 playerId `plays` throneRoom `with` (ThroneRoom market)

with :: Dominion (PlayResult (Maybe Followup)) -> FollowupAction -> Dominion (PlayResult (Maybe [Followup]))Source

You can use with to play an FollowupAction. For example:

 playerId `plays` chapel `with` (Chapel [4 `cardsOf` estate])

This will trash up to four estates from your hand (depending on how many you have). The input of this function is directly the output of plays, so you can chain these functions together easily. This automatically handles checking whether the PlayResult was a Right, and whether there is a Followup, and whether the FollowupAction you gave matches the Followup, and applies the FollowupAction.

The FollowupAction needs to match the Followup. You can't do this, for example:

 playerId `plays` throneRoom `with` (Workshop village)

You need this instead:

 playerId `plays` throneRoom `with` (ThroneRoom village)

with might lead to more Followups, in which case you can chain calls using withMulti.

withMulti :: Dominion (PlayResult (Maybe [Followup])) -> [FollowupAction] -> Dominion (PlayResult (Maybe [Followup]))Source

This is just like with, except you can give it an array of Followups, and another array of FollowupActions. Most cards will only generate one Followup. There's only one case I know about that would generate multiple Followups: playing a throne room on a throne room.

 playerId `plays` throneRoom `with` (ThroneRoom throneRoom) `withMulti` [ThroneRoom market, ThroneRoom smithy]

Here, someone plays a throne room on a throne room. Now you have to follow up with two action cards: the two cards you want to play twice. The player passes in market and smithy, and they both get played twice.

_with :: Followup -> FollowupAction -> Dominion (PlayResult (Maybe [Followup]))Source

with and withMulti automatically extract the Followup out of the result of plays. If you have a Followup already, or you want more control, you can use this instead.

 result <- playerId `plays` throneRoom
 case result of
   Left str -> return . Left $ str
   Right followup -> followup `_with` (ThroneRoom market)

data Option Source

You can set these options if you use dominionWithOpts. Example:

 main = dominionWithOpts [Iterations 1, Log True, Cards [smithy]] ...

Constructors

Iterations Int

Number of iterations to run.

Log Bool

Enable logging

Cards [Card]

A list of cards that you definitely want in the game. Useful if you are testing a strategy that relies on a particular card.

Instances

has :: PlayerId -> Card -> Dominion BoolSource

see if a player has a card in his hand.

 hasCard <- playerId `has` chapel

handValue :: PlayerId -> Dominion IntSource

How much money this player's hand is worth (also counts any money you get from action cards, like +1 from market).

pileEmpty :: Card -> Dominion BoolSource

Check if this card's pile is empty.

getPlayer :: PlayerId -> Dominion PlayerSource

Get player from game state specified by this id. This is useful sometimes:

 import qualified Dominion.Types as T
 import Control.Lens

 player <- getPlayer playerId

 -- How many buys does this player have?
 player ^. T.buys

 -- How many actions does this player have?
 player ^. T.actions

cardsOf :: Int -> a -> [a]Source

Convenience function. 4 `cardsOf` estate is the same as take 4 . repeat $ estate

validateBuy :: PlayerId -> Card -> Dominion (PlayResult ())Source

Check that this player is able to purchase this card. Returns a Right if they can purchase the card, otherwise returns a Left with the reason why they can't purchase it.

validatePlay :: PlayerId -> Card -> Dominion (PlayResult ())Source

Check that this player is able to play this card. Returns a Right if they can play the card, otherwise returns a Left with the reason why they can't play it.

getRound :: Dominion IntSource

Get the current round number.