module Solutions.ChannelFireball where

import Dovin.V2
import Dovin.Prelude

import Control.Lens

solution :: GameMonad ()
solution :: GameMonad ()
solution = do
  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Initial state" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    Int -> GameMonad ()
setLife Int
1

    Location -> GameMonad () -> GameMonad ()
withLocation Location
Play (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      Int -> String -> GameMonad ()
addLands Int
4 String
"Steam Vents"
      Int -> String -> GameMonad ()
addLands Int
4 String
"Breeding Pool"
      String -> GameMonad ()
addArtifact String
"Aetherflux Reservoir"
      (Int, Int) -> String -> GameMonad ()
addCreature (Int
2, Int
2) String
"Beamsplitter Mage"
      (Int, Int) -> String -> GameMonad ()
addCreature (Int
2, Int
2) String
"Man-o'-War"

    Location -> GameMonad () -> GameMonad ()
withLocation Location
Hand (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      String -> GameMonad ()
addInstant String
"High Tide"
      String -> GameMonad ()
addInstant String
"Snap"
      String -> GameMonad ()
addInstant String
"Rewind"
      String -> GameMonad ()
addSorcery String
"Baral's Expertise"
      String -> GameMonad ()
addSorcery String
"Channel"
      String -> GameMonad ()
addSorcery String
"Fireball"
      String -> GameMonad () -> GameMonad ()
withAttribute String
flash (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> String -> GameMonad ()
addCreature (Int
2, Int
1) String
"Snapcaster Mage"
      (Int, Int) -> String -> GameMonad ()
addCreature (Int
0, Int
0) String
"Walking Ballista"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast High Tide with a Steam Vents" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Steam Vents 1"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"U") String
"High Tide"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
1
    String -> GameMonad ()
resolve String
"High Tide"

    ASetter Board Board Int Int -> (Int -> Int) -> GameMonad ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
modifying
      ASetter Board Board Int Int
Lens' Board Int
highTideCounter
      (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Snapcaster, targeting High Tide, with second Steam Vents" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Steam Vents 2"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"

    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
2
    String -> GameMonad ()
resolve String
"Snapcaster Mage"
    CardLocation -> String -> GameMonad ()
targetInLocation (Player
Active, Location
Graveyard) String
"High Tide"
    String -> String -> GameMonad ()
gainAttribute String
snapped String
"High Tide"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Flashback High Tide with third Steam Vents" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Steam Vents 3"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
flashbackSnapped String
"U") String
"High Tide"

    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
3
    String -> GameMonad ()
resolve String
"High Tide"

    ASetter Board Board Int Int -> (Int -> Int) -> GameMonad ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
modifying
      ASetter Board Board Int Int
Lens' Board Int
highTideCounter
      (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Tap five remaining lands for 3 mana each" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 4"
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 1"
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 2"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 3"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Walking Ballista for 1, leave on stack" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"") String
"Walking Ballista"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Stack Snap, targeting Beamsplitter then copying to Snapcaster" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snap"
    String -> GameMonad ()
target String
"Beamsplitter Mage"
    String -> String -> GameMonad ()
trigger String
"Copied Snap" String
"Beamsplitter Mage" GameMonad () -> GameMonad () -> GameMonad ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> GameMonad ()
resolveTop
    String -> String -> GameMonad ()
copySpell String
"Snap Copy (Snapcaster Mage)" String
"Snap"
    String -> GameMonad ()
target String
"Snapcaster Mage"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Counter Walking Ballista with Rewind, untapping Steam Vents" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"2UU") String
"Rewind"
    String -> GameMonad ()
counter String
"Walking Ballista"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
6
    String -> GameMonad ()
resolve String
"Rewind"
    String -> GameMonad ()
untap String
"Steam Vents 1"
    String -> GameMonad ()
untap String
"Steam Vents 2"
    String -> GameMonad ()
untap String
"Steam Vents 3"
    String -> GameMonad ()
untap String
"Steam Vents 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Resolve Snap copy, returning Snapcaster, untapping Breeding Pools" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> GameMonad ()
resolve String
"Snap Copy (Snapcaster Mage)"

    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Snapcaster Mage"
    String -> GameMonad ()
untap String
"Breeding Pool 1"
    String -> GameMonad ()
untap String
"Breeding Pool 2"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Resolve Snap, returning Beamsplitter, untapping Breeding Pools" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
5
    String -> GameMonad ()
resolve String
"Snap"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Beamsplitter Mage"
    String -> GameMonad ()
untap String
"Breeding Pool 3"
    String -> GameMonad ()
untap String
"Breeding Pool 4"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
4

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Recast Beamsplitter, stacking Snapcaster targeting Snap" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"RU") String
"Beamsplitter Mage"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"

    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
8
    String -> GameMonad ()
resolve String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
7
    String -> GameMonad ()
resolve String
"Beamsplitter Mage"

    CardLocation -> String -> GameMonad ()
targetInLocation (Player
Active, Location
Graveyard) String
"Snap"
    String -> String -> GameMonad ()
gainAttribute String
snapped String
"Snap"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Tap all lands for 3 mana each" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Steam Vents 1"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Steam Vents 2"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 3"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 4"
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 1"
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 2"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 3"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Stack flashbacked Snap, targeting Beamsplitter then copy to Snapcaster" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
flashbackSnapped String
"1U") String
"Snap"
    String -> GameMonad ()
target String
"Beamsplitter Mage"
    String -> String -> GameMonad ()
trigger String
"Copied Snap" String
"Beamsplitter Mage" GameMonad () -> GameMonad () -> GameMonad ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> GameMonad ()
resolveTop
    String -> String -> GameMonad ()
copySpell String
"Snap Copy (Snapcaster Mage)" String
"Snap"
    String -> GameMonad ()
target String
"Snapcaster Mage"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Resolve Snap copy, returning Snapcaster, untap Breeding Pools" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> GameMonad ()
resolve String
"Snap Copy (Snapcaster Mage)"

    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Snapcaster Mage"
    String -> GameMonad ()
untap String
"Breeding Pool 1"
    String -> GameMonad ()
untap String
"Breeding Pool 2"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Replay Snapcaster, targeting Rewind" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
10
    String -> GameMonad ()
resolve String
"Snapcaster Mage"
    CardLocation -> String -> GameMonad ()
targetInLocation (Player
Active, Location
Graveyard) String
"Rewind"
    String -> String -> GameMonad ()
gainAttribute String
snapped String
"Rewind"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Resolve Snap on Beamsplitter, untap Steam Vents" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
9
    String -> GameMonad ()
resolve String
"Snap"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Beamsplitter Mage"
    String -> GameMonad ()
untap String
"Steam Vents 3"
    String -> GameMonad ()
untap String
"Steam Vents 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Baral's Expertise for all 3 in play, replaying Aetherflux for free" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"3UU") String
"Baral's Expertise"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
11
    String -> GameMonad ()
resolve String
"Baral's Expertise"

    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Aetherflux Reservoir"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Man-o'-War"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Snapcaster Mage"

    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"") String
"Aetherflux Reservoir"
    String -> GameMonad ()
resolve String
"Aetherflux Reservoir"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Beamsplitter Mage, stacking Snapcaster targeting Baral's" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"UR") String
"Beamsplitter Mage"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
14
    String -> GameMonad ()
resolve String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
13
    String -> GameMonad ()
resolve String
"Beamsplitter Mage"

    CardLocation -> String -> GameMonad ()
targetInLocation (Player
Active, Location
Graveyard) String
"Baral's Expertise"
    String -> String -> GameMonad ()
gainAttribute String
snapped String
"Baral's Expertise"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Flashback Baral's Expertise targeting all 3 in play, replaying Aetherflux" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
flashbackSnapped String
"3UU") String
"Baral's Expertise"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
15
    String -> GameMonad ()
resolve String
"Baral's Expertise"

    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Aetherflux Reservoir"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Beamsplitter Mage"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Snapcaster Mage"

    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"") String
"Aetherflux Reservoir"
    String -> GameMonad ()
resolve String
"Aetherflux Reservoir"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Tap remaining lands for 3 mana each" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 1"
    String -> String -> GameMonad ()
tapForManaWithTide String
"G" String
"Breeding Pool 2"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 3"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Channel and Fireball for life only" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"GG") String
"Channel"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
17
    String -> GameMonad ()
resolve String
"Channel"

    Int
l <- (-) (Int -> Int -> Int)
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> ExceptT
     String
     (ReaderT Env (StateT Board (WriterT [Step] Identity)))
     (Int -> Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countLife Player
Active ExceptT
  String
  (ReaderT Env (StateT Board (WriterT [Step] Identity)))
  (Int -> Int)
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
1

    let payment :: String
payment = Int -> String
forall a. Show a => a -> String
show Int
l String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"R"

    Int -> GameMonad ()
loseLife Int
l
    String -> GameMonad ()
addMana (String -> GameMonad ()) -> String -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show Int
l

    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
payment) String
"Fireball"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
18
    String -> GameMonad ()
resolve String
"Fireball"

    (Card -> Int) -> Target -> String -> GameMonad ()
damage (Int -> Card -> Int
forall a b. a -> b -> a
const Int
l) (Player -> Target
targetPlayer Player
Opponent) String
"Fireball"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Beamsplitter Mage, stacking Snapcaster targeting Fireball" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"UR") String
"Beamsplitter Mage"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
20
    String -> GameMonad ()
resolve String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
19
    String -> GameMonad ()
resolve String
"Beamsplitter Mage"

    CardLocation -> String -> GameMonad ()
targetInLocation (Player
Active, Location
Graveyard) String
"Fireball"
    String -> String -> GameMonad ()
gainAttribute String
snapped String
"Fireball"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Man-'o-War, returning Snapcaster Mage" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"2U") String
"Man-o'-War"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
21
    String -> GameMonad ()
resolve String
"Man-o'-War"

    String -> GameMonad ()
target String
"Snapcaster Mage"
    CardLocation -> CardLocation -> String -> GameMonad ()
move (Player
Active, Location
Play) (Player
Active, Location
Hand) String
"Snapcaster Mage"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Cast Snapcaster, counter with flashback Rewind" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
cast String
"1U") String
"Snapcaster Mage"
    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
flashbackSnapped String
"2UU") String
"Rewind"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
23
    String -> GameMonad ()
resolve String
"Rewind"
    String -> GameMonad ()
counter String
"Snapcaster Mage"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
22

    String -> GameMonad ()
untap String
"Breeding Pool 1"
    String -> GameMonad ()
untap String
"Breeding Pool 2"
    String -> GameMonad ()
untap String
"Steam Vents 3"
    String -> GameMonad ()
untap String
"Steam Vents 4"

  String -> GameMonad () -> GameMonad ()
forall a. String -> GameMonad a -> GameMonad a
step String
"Flashback Fireball with all remaining mana and life" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 1"
    String -> String -> GameMonad ()
tapForManaWithTide String
"U" String
"Breeding Pool 2"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 3"
    String -> String -> GameMonad ()
tapForManaWithTide String
"R" String
"Steam Vents 4"

    Int
life <- Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countLife Player
Active
    Int
mana <- Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countManaPool Player
Active
    let dmg :: Int
dmg = (Int
life Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
mana Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
    let payment :: String
payment = Int -> String
forall a. Show a => a -> String
show Int
dmg String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"R"

    Int -> GameMonad ()
loseLife (Int
life Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
    String -> GameMonad ()
addMana (String -> GameMonad ()) -> String -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int
life Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)

    (String -> GameMonad ()) -> String -> GameMonad ()
forall t a.
(t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers (String -> String -> GameMonad ()
flashbackSnapped String
payment) String
"Fireball"
    Integer -> GameMonad ()
forall a. Show a => a -> GameMonad ()
resolveAetherflux Integer
24
    String -> GameMonad ()
resolve String
"Fireball"

    (Card -> Int) -> Target -> String -> GameMonad ()
damage (Int -> Card -> Int
forall a b. a -> b -> a
const Int
life) (Player -> Target
targetPlayer Player
Opponent) String
"Fireball"

attributes :: Formatter
attributes = FormatMonad () -> Formatter
attributeFormatter (FormatMonad () -> Formatter) -> FormatMonad () -> Formatter
forall a b. (a -> b) -> a -> b
$ do
  String
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a. Show a => String -> GameMonad a -> FormatMonad ()
attribute String
"life" (ExceptT
   String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
 -> FormatMonad ())
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a b. (a -> b) -> a -> b
$ Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countLife Player
Active
  String
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a. Show a => String -> GameMonad a -> FormatMonad ()
attribute String
"pool" (ExceptT
   String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
 -> FormatMonad ())
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a b. (a -> b) -> a -> b
$ Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countManaPool Player
Active
  String
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a. Show a => String -> GameMonad a -> FormatMonad ()
attribute String
"spells" (ExceptT
   String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
 -> FormatMonad ())
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a b. (a -> b) -> a -> b
$ Getting Int Board Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Int Board Int
Lens' Board Int
spellCounter

playExLandFormatter :: Formatter
playExLandFormatter = String -> CardMatcher -> Formatter
cardFormatter String
"Play (ex. Land)"
  (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Play) CardMatcher -> CardMatcher -> CardMatcher
forall a. Semigroup a => a -> a -> a
<> CardMatcher -> CardMatcher
invert (String -> CardMatcher
matchAttribute String
land))
formatter :: Step -> Formatter
formatter Step
step = Formatter
attributes Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> case Getting Int Step Int -> Step -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int Step Int
Lens' Step Int
stepNumber Step
step of
  Int
1 -> Formatter
boardFormatter
  Int
3 -> String -> CardMatcher -> Formatter
cardFormatter String
"Play" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Play))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
6 -> Formatter
stackFormatter
  Int
7 -> Formatter
stackFormatter
  Int
8 -> Formatter
stackFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Play" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Play))
  Int
9 -> Formatter
stackFormatter
  Int
10 -> Formatter
stackFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
11  ->
       String -> CardMatcher -> Formatter
cardFormatter String
"Play" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Play))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
13 -> Formatter
stackFormatter
  Int
14 -> Formatter
stackFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
15 -> Formatter
stackFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
16 ->
       String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Play" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Play))
  Int
17 ->
       String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> Formatter
playExLandFormatter
  Int
18 ->
       Formatter
playExLandFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
19 ->
       String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> Formatter
playExLandFormatter
  Int
21 -> FormatMonad () -> Formatter
attributeFormatter (String
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a. Show a => String -> GameMonad a -> FormatMonad ()
attribute String
"opponent" (ExceptT
   String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
 -> FormatMonad ())
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a b. (a -> b) -> a -> b
$ Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countLife Player
Opponent)
  Int
22 ->
       String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> Formatter
playExLandFormatter
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher -> Formatter
cardFormatter String
"Graveyard" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Graveyard))
  Int
23 ->
      String -> CardMatcher -> Formatter
cardFormatter String
"Hand" (CardLocation -> CardMatcher
matchLocation (Player
Active, Location
Hand))
    Formatter -> Formatter -> Formatter
forall a. Semigroup a => a -> a -> a
<> Formatter
playExLandFormatter
  Int
25 -> FormatMonad () -> Formatter
attributeFormatter (String
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a. Show a => String -> GameMonad a -> FormatMonad ()
attribute String
"opponent" (ExceptT
   String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
 -> FormatMonad ())
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
-> FormatMonad ()
forall a b. (a -> b) -> a -> b
$ Player
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
countLife Player
Opponent)
  Int
_ -> Formatter
forall a. Monoid a => a
mempty

spellCounter :: Lens' Board Int
spellCounter :: (Int -> f Int) -> Board -> f Board
spellCounter = (HashMap String Int -> f (HashMap String Int)) -> Board -> f Board
Lens' Board (HashMap String Int)
counters ((HashMap String Int -> f (HashMap String Int))
 -> Board -> f Board)
-> ((Int -> f Int) -> HashMap String Int -> f (HashMap String Int))
-> (Int -> f Int)
-> Board
-> f Board
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (HashMap String Int)
-> Lens'
     (HashMap String Int) (Maybe (IxValue (HashMap String Int)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at String
Index (HashMap String Int)
"spell-count" ((Maybe Int -> f (Maybe Int))
 -> HashMap String Int -> f (HashMap String Int))
-> ((Int -> f Int) -> Maybe Int -> f (Maybe Int))
-> (Int -> f Int)
-> HashMap String Int
-> f (HashMap String Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Iso' (Maybe Int) Int
forall a. Eq a => a -> Iso' (Maybe a) a
non Int
0

highTideCounter :: Lens' Board Int
highTideCounter :: (Int -> f Int) -> Board -> f Board
highTideCounter = (HashMap String Int -> f (HashMap String Int)) -> Board -> f Board
Lens' Board (HashMap String Int)
counters ((HashMap String Int -> f (HashMap String Int))
 -> Board -> f Board)
-> ((Int -> f Int) -> HashMap String Int -> f (HashMap String Int))
-> (Int -> f Int)
-> Board
-> f Board
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index (HashMap String Int)
-> Lens'
     (HashMap String Int) (Maybe (IxValue (HashMap String Int)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at String
Index (HashMap String Int)
"high-tide-count" ((Maybe Int -> f (Maybe Int))
 -> HashMap String Int -> f (HashMap String Int))
-> ((Int -> f Int) -> Maybe Int -> f (Maybe Int))
-> (Int -> f Int)
-> HashMap String Int
-> f (HashMap String Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Iso' (Maybe Int) Int
forall a. Eq a => a -> Iso' (Maybe a) a
non Int
0

aetherfluxTriggerName :: a -> String
aetherfluxTriggerName a
n = String
"Aetherflux Trigger #" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> a -> String
forall a. Show a => a -> String
show a
n
snapped :: String
snapped = String
"snapped"

-- Keeps track of number of spells cast, and if Aetherflux Reservoir is in play
-- triggers it.
withTriggers :: (t
 -> ExceptT
      String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a)
-> t -> GameMonad ()
withTriggers t
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a
fn t
name = do
  t
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) a
fn t
name

  ASetter Board Board Int Int -> (Int -> Int) -> GameMonad ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
modifying
    ASetter Board Board Int Int
Lens' Board Int
spellCounter
    (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)

  CardMatcher -> (String -> GameMonad ()) -> GameMonad ()
forCards
    (CardMatcher
matchInPlay CardMatcher -> CardMatcher -> CardMatcher
forall a. Semigroup a => a -> a -> a
<> String -> CardMatcher
matchName String
"Aetherflux Reservoir")
    ((String -> GameMonad ()) -> GameMonad ())
-> (String -> GameMonad ()) -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ GameMonad () -> String -> GameMonad ()
forall a b. a -> b -> a
const (GameMonad () -> String -> GameMonad ())
-> GameMonad () -> String -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      Int
x <- Getting Int Board Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Int Board Int
Lens' Board Int
spellCounter
      String -> String -> GameMonad ()
trigger (Int -> String
forall a. Show a => a -> String
aetherfluxTriggerName Int
x) String
"Aetherflux Reservoir"

tapForManaWithTide :: String -> String -> GameMonad ()
tapForManaWithTide String
pool String
cn = do
  String -> String -> GameMonad ()
tapForMana String
pool String
cn
  Int
x <- Getting Int Board Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Int Board Int
Lens' Board Int
highTideCounter

  String -> GameMonad ()
addMana (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
x Char
'U')

resolveAetherflux :: a -> GameMonad ()
resolveAetherflux a
n = do
  String -> GameMonad ()
resolve (String -> GameMonad ()) -> String -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ a -> String
forall a. Show a => a -> String
aetherfluxTriggerName a
n

  Int
x <- Getting Int Board Int
-> ExceptT
     String (ReaderT Env (StateT Board (WriterT [Step] Identity))) Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Int Board Int
Lens' Board Int
spellCounter
  Int -> GameMonad ()
gainLife Int
x

flashbackSnapped :: String -> String -> GameMonad ()
flashbackSnapped String
mana String
castName = do
  CardMatcher -> String -> GameMonad ()
validate (String -> CardMatcher
matchAttribute String
snapped) String
castName
  String -> String -> GameMonad ()
flashback String
mana String
castName