dovin- A proof assistant for Magic: The Gathering puzzles.

Safe HaskellNone




module Dovin.Dump

addMana :: ManaString -> GameMonad () Source #

Add mana to actor's mana pool.

addMana "2RG"
  • Mana specification is valid.
  • Mana pool is increased.

cast :: ManaPool -> CardName -> GameMonad () Source #

Casts a card from actor's hand. See castFromLocation for specification.

cast "R" "Shock"
  • Card exists in hand.

castFromLocation :: CardLocation -> ManaPool -> CardName -> GameMonad () Source #

Move a card to the stack, spending the specified mana. If not tracking mana, use the empty string to cast for no mana. Typically you will want to resolve after casting. For the common case of casting from hand, see cast. See spendMana for additional mana validations and effects.

castFromLocation "1B" "Oathsworn Vampire" >> resolveTop

counter :: CardName -> GameMonad () Source #

Remove a spell from the stack.

counter "Shock"
  • Card is on stack.
  • Card is not a triggered or activated ability.
  • Card is moved to graveyard. (See move for alternate effects.)

flashback :: ManaPool -> CardName -> GameMonad () Source #

Cast a card from actor's graveyard, exiling it when it leaves the stack. See castFromLocation for further specification.

flashback "R" "Shock"

Does not validate whether the card actually has a flashback cost. If important, use a wrapper function in your solution:

flashbackSnapped mana castName = do
  validate (matchAttribute "snapcastered") castName
  flashback mana castName
  • Card is in actor's graveyard.

jumpstart :: ManaPool -> CardName -> CardName -> GameMonad () Source #

Cast a card from active player's graveyard, discarding a card in addition to its mana cost, exiling it when it leaves the stack. See castFromLocation for further specification.

jumpstart "R" "Mountain" "Shock"
  • Card is in actor's graveyard.
  • Discard card is in actor's hand.

resolve :: CardName -> GameMonad () Source #

Resolves a card on the stack.

cast "R" "Shock" >> resolve "Shock"
  • Stack is not empty.
  • Card is on top of stack.

resolveTop :: GameMonad () Source #

Resolves the top card of the stack. Use this for simple cast-and-resolve scenarios. For more complicated stack states, prefer resolve with a named spell to ensure the expected one is resolving.

  • Stack is not empty.
  • If spell, move card to graveyard of owner.
  • If permanent, move card to play area of owner.
  • If trigger, remove card.
  • See move for possible alternate effects, depending on card attributes.

splice :: CardName -> ManaString -> CardName -> GameMonad () Source #

Splices a spell on to a previously cast arcane spell.

splice "Goryo's Vengeance" "2RR" "Through the Breach"
  • Target spell is arcane.
  • Target spell is on stack.
  • Spliced spell is in hand.
  • See spendMana for additional validations.

tapForMana :: ManaString -> CardName -> GameMonad () Source #

Combination of tap and addMana, see them for specification.

transitionTo :: Phase -> GameMonad () Source #

Transition to a new game phase or step.

transitionTo DeclareAttackers
  • The new phase would occur after the current phase in a normal turn.
  • Empty the mana pool.
  • Transition to new phase.

transitionToForced :: Phase -> GameMonad () Source #

Equivalent to transitionTo except it skips all validation. Useful when an effect has modified the normal order of phases, such as adding an extra combat step.

move :: CardLocation -> CardLocation -> CardName -> GameMonad () Source #

Move a card from one location to another.

move (Opponent, Play) (Active, Play) "Angel"
  • Card exists in source location.
  • Destination is not stack (use a cast variant instead).
  • Destination does not match source.
  • If card has token attribute, source is in play. (Removing token once they have left play is handled by runStateBasedActions.)
  • If card has copy attribute, source is the stack. (Removing token once they have left play is handled by runStateBasedActions.)
  • Card moved to destination location.
  • If card is leaving play, remove all damage, counters, and gained attributes.
  • If card has exileWhenLeaveStack attribute, move to exile and remove exileWhenLeaveStack instead.
  • If card has undying, is moving from play to graveyard, and has no +1/+1 counters, add a +1/+1 counter instead. (Note: undying should move card to graveyard then back to play for owner, but since neither triggers nor owner tracking are implemented, this simplification is valid.)
  • If card is entering play or changing controller, add summoned attribute.

attackWith :: [CardName] -> GameMonad () Source #

Start an attack with the given creatures.

attackWith ["Fanatical Firebrand"]

combatDamage :: [CardName] -> CardName -> GameMonad () Source #

Apply combat damage between an attacker and blockers, using a simple damage assignment algorithm. For more complex assignments, use damage directly.

combatDamage ["Spirit 1", "Spirit 2"] "Angel"

See damage for other validations and effects.

  • Attacker has attribute attacking.
  • Attacker and blockers are in play.
  • Attacker controlled by current actor.
  • Blockers have attribute creature.
  • Damage is dealt to blockers in order given, with the final blocker receiving any left over damage.
  • If no blockers, damage is dealt to opposing player.
  • If attacker has trample, any remaining damage is dealt to opposing player.

damage Source #


:: (Card -> Int)

A function that returns the amount of damage to apply, given the source card.

-> Target 
-> CardName 
-> GameMonad () 

Applies damage from a source to a target.

damage (const 2) (targetPlayer Opponent) "Shock"
  • Source exists.
  • Damage is not less than zero.
  • If targeting a card, target is in play and is either a creature or a planeswalker.
  • Adds damage to the target.
  • If target is a planeswalker, remove loyalty counters instead.
  • If source has deathtouch and target is a creature and damage is non-zero, add deathtouched attribute to target.
  • If source has lifelink, controller of source gains life equal to damage dealt.
  • Note runStateBasedActions handles actual destruction (if applicable) of creatures and planeswalkers.

discard :: CardName -> GameMonad () Source #

Discard a card from the active player's hand.

discard "Mountain"
  • Card exists in active player's hand.
  • Card moved to graveyard.

exert :: CardName -> GameMonad () Source #

Exert a card. Works best when card has an associated effect that applies when exerted attribute is present.

withAttributes [flying]
  $ withEffect
      (matchInPlay <> matchAttribute exerted)
      (    matchLocation . view cardLocation
        <> const (matchAttribute creature)
      (pure . over cardStrength (mkStrength (1, 1) <>))
  $ addCreature (2, 2) "Tah-Crop Elite"
attackWith ["Tah-Crop Elite"]
exert "Tah-Crop Elite"

moveTo :: Location -> CardName -> GameMonad () Source #

Move card to location with same controller.

moveTo Graveyard "Forest"
  • Card exists.
  • Card is moved to location.
  • See move for possible alternate effects, depending on card

spendMana :: ManaString -> GameMonad () Source #

Remove mana from the pool. Colored mana will be removed first, then extra mana of any type will be removed to match the colorless required.

spendMana "2RG"
  • Mana specification is valid.
  • Sufficient mana exists in pool.
  • Mana pool is reduced.

tap :: CardName -> GameMonad () Source #

Taps a card.

  • Card is in play.
  • Card is not tapped.
  • Card gains tapped attribute.

untap :: CardName -> GameMonad () Source #

Untaps a card.

  • Card is in play.
  • Card is tapped.
  • Card loses tapped attribute.

validateRemoved :: CardName -> GameMonad () Source #

Validates that a card is no longer present in the game. Particularly helpful for checking destruction of tokens.

validateRemoved "Angel"
  • Name does not refer to a card.

validatePhase :: Phase -> GameMonad () Source #

Validates that the game is in a particular phase.

validatePhase BeginCombat
  • Game is in the given phase.

validateCanCastSorcery :: GameMonad () Source #

Validates that a sorcery is able to be cast.

  • Stack is empty.
  • In a main phase.

withStateBasedActions :: GameMonad () -> GameMonad () Source #

Pause running of state-based actions for the duration of the action, running them at the end.

runStateBasedActions :: GameMonad () Source #

Run state-based actions. These include:

  • If a creature does not have indestructible, and has damage exceeding toughess or deathtouched attribute, destroy it.
  • If a card is a token and is not in play, remove it.
  • If a card is a copy and is not on the stack, remove it.

These are run implicitly at the end of each step, so it's not usually needed to call this explicitly. Even then, using withStateBasedActions is usually preferred.

Running state-based actions can in turn trigger more state-based actions. This method loops until no more are generated, which has the potential for non-termination for pathological game states.

step :: String -> GameMonad () -> GameMonad () Source #

Define a high-level step in the proof. A proof typically consists on multiple steps. Each step is a human-readable description, then a definition of that step using actions. If a step fails, no subsequent steps will be run. runStateBasedActions is implicitly called at the end of each step. Nested step invocations execute the nested action but have no other effects - generally they should be avoided.

as :: Player -> GameMonad () -> GameMonad () Source #

Perform action as the specified player.

withAttribute :: String -> GameMonad () -> GameMonad () Source #

Add an attribute to the created card, as identified by a string. Attributes with that special meaning to Dovin built-ins (such as flying) are defined in Dovin.Attributes.

withAttributes :: [String] -> GameMonad () -> GameMonad () Source #

Helper version of withAttribute for adding multiple attributes at a time.

withEffect Source #


:: CardMatcher

A matcher that must apply to this card for this affect to apply. matchInPlay is a typical value.

-> (Card -> CardMatcher)

Given the current card, return a matcher that matches cards that this affect applies to.

-> (Card -> GameMonad Card)

Apply an effect to the given card.

-> GameMonad () 
-> GameMonad () 

Add an effect to the created card.

withPlusOneCounters :: Int -> GameMonad () -> GameMonad () Source #

Set the number of +1/+1 counters of the created card.

validate :: CardName -> CardMatcher -> GameMonad () Source #

Validate that a card matches a matcher.

validate "Angrath's Marauders" $ matchAttribute "pirate"
  • Card matches matcher.

validateLife :: Player -> Int -> GameMonad () Source #

Validates a player has a specific life total.

validateLife Opponent 0
  • Player life equals amount.

withLocation :: CardLocation -> GameMonad () -> GameMonad () Source #

Set the location of the created card.