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

Safe HaskellNone
LanguageHaskell98

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 Bool Source #

see if a player has a card in his hand.

hasCard <- playerId `has` chapel

handValue :: PlayerId -> Dominion Int Source #

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 Bool Source #

Check if this card's pile is empty. Returns True is the card is not in play.

getPlayer :: PlayerId -> Dominion Player Source #

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 Int Source #

Get the current round number.

countNum :: PlayerId -> Card -> Dominion Int Source #

see how many of this card a player has.

numMarkets <- countNum playerId market