packages feed

dovin-3.0.1: README.md

# Dovin

A proof assistant for [Possibility
Storm](http://www.possibilitystorm.com/)-style Magic: The Gathering puzzles.

> He has an innate talent, heightened by magic, that allows him to clearly see
> the flaws in any system or machine. After mere moments of scrutiny, Dovin can
> provide a complete analysis, noting a particular machine's weaknesses,
> highlighting its shortcomings, and predicting with startling accuracy exactly
> how and when it will fail. --- [Dovin Baan, Planeswalker](https://magic.wizards.com/en/story/planeswalkers/dovin-baan)

It provides a haskell DSL for expressing Magic actions, with tracking of life
and other counters and validation of pre- and post- conditions. For example, if
you try to tap a permanent that is already tapped, it will error. Or if you try
to target a creature with hexproof. It can also track state-based effects, such
as "all creatures get +1/+1" or "other creatures gain hexproof".

It does not try to provide a full ruleset implementation, instead it's more
akin to letting you lay out cards and counters in front of you and manipulate
them as you would in a real game of paper magic.

I've only added actions "as needed" to solve problems, so the built-in
functions are rather incomplete right now. It is straightforward to add more
though. See `src/Dovin/V3.hs` in conjuction with `src/Dovin/Actions.hs`.

## Example

``` haskell
module Solutions.Example where

import Dovin

solution :: GameMonad ()
solution = do
  step "Initial state" $ do
    as Opponent $ setLife 3

    withLocation Hand $ addInstant "Plummet"
    withLocation Play $ do
      addLands 2 "Forest"

    as Opponent $ do
      withLocation Play $ do
        withAttributes [flying, token] $ addCreature (4, 4) "Angel"
        withAttributes [flying]
          $ withEffect
              (matchOtherCreatures <$> askSelf)
              [ effectAddAbility hexproof
              ]
              "Other creatures gain hexproof"
          $ addCreature (3, 4) "Shalai, Voice of Plenty"

  step "Plummet to destroy Shalai" $ do
    tapForMana "G" (numbered 1 "Forest")
    tapForMana "G" (numbered 2 "Forest")
    cast "1G" "Plummet"
    resolve "Plummet"
    with "Shalai, Voice of Plenty" $ \enemy -> do
      target enemy
      validate (matchAttribute flying) enemy
      destroy enemy

formatter :: Step -> Formatter
formatter step = case view stepNumber step of
  1 -> manaFormatter
    <> cardFormatter "opponent creatures" (matchLocation (Opponent, Play))
  _ -> boardFormatter

manaFormatter = attributeFormatter $ do
  attribute "availble mana" $
    countCards (matchAttribute land <> missingAttribute tapped)
```

`run` uses the supplied formatter to print out the board state at each step:

    1. Initial state
          (Active,Hand):
            Plummet (instant)
          (Active,Play):
            Forest 1 (land)
            Forest 2 (land)
          (Opponent,Play):
            Angel (creature,flying,hexproof,token) (4/4, 0)
            Shalai, Voice of Plenty (creature,flying) (3/4, 0)
    2. Plummet to destroy Shalai
          availble mana: 0
          opponent creatures:
            Angel (creature,flying,token) (4/4, 0)

## Solutions Index

See `src/Solutions` for more extensive usage (spoiler alert: these are
solutions for published Possibility Storm puzzles!)

* `Dominaria5` uses a planeswalker.
* `RivalsOfIxalan7` uses `withEffect` to model `exert`
  effects, and shows how to verify multiple blocking scenarios.
* `Core19_9` has a fancy formatter to correctly track how much
  mana is available when working with `Powerstone Shard`, as well as spell
  tracking for `Aetherflux Reservoir`.
* `GuildsOfRavnicaPre2` uses `forCards` to model undergrowth
  for a `Rhizome Lurcher`.
* `GuildsOfRavnica1` uses `mentor`.
* `GuildsOfRavnica3` uses a sacrifice wrapper to repeatedly
  create treasure tokens.
* `GuildsOfRavnica8` shows using counters to correctly track
  `Muldrotha, the Gravetide` usage.
* `GuildsOfRavnica9` handles `storm`.
* `ExplorersOfIxalanContest` handles some pretty weird damage
  interactions.
* `UltimateMasters` shows how to track opponent actions.
* `ChannelFireball` automatically calculates High Tide mana.
* `WarOfTheSpark2` shows how to define effects that depend on attributes of
  other cards.

## Development

    bin/dev       # Launch an interactive REPL
    bin/test      # Runs all tests and lints
    bin/test-repl # Run tests from interactive REPL (use `main`)
    bin/run       # Runs all solutions

New actions go into `Dovin.Actions`. They must:

  * Be unit tested.
  * Be documented.
  * The primary target card of an action should be the final parameter.