module Solutions.GuildsOfRavnica3 where

import Control.Monad
import Control.Monad.Except (catchError)

import Dovin.V1

-- This solution re-uses the "Treasure" card to avoid having to track a counter
-- for each new one created. This has the downside of requiring explicit
-- state-based action calls - a new one can't be created until the old one has
-- been removed. In hindsight, probably would be easier to follow by keeping a
-- running counter of treasures and refering to them separately.
solution :: GameMonad ()
solution :: GameMonad ()
solution = do
  let menace :: [Char]
menace = [Char]
"menace"
  let sacrificeToNecrolisk :: [Char] -> GameMonad ()
sacrificeToNecrolisk =
        \[Char]
name -> do
          GameMonad ()
validateCanCastSorcery
          [Char] -> [Char] -> GameMonad ()
activate [Char]
"1" [Char]
"Undercity Necrolisk"
          [Char] -> CardMatcher -> GameMonad ()
validate [Char]
name (CardMatcher -> GameMonad ()) -> CardMatcher -> GameMonad ()
forall a b. (a -> b) -> a -> b
$
               CardMatcher
matchInPlay
            CardMatcher -> CardMatcher -> CardMatcher
forall a. Semigroup a => a -> a -> a
<> Player -> CardMatcher
matchController Player
Active
            CardMatcher -> CardMatcher -> CardMatcher
forall a. Semigroup a => a -> a -> a
<> [Char] -> CardMatcher
matchAttribute [Char]
"creature"
          [Char] -> GameMonad ()
sacrifice [Char]
name
          [Char] -> [Char] -> GameMonad ()
gainAttribute [Char]
menace [Char]
"Undercity Necrolisk"
          (Int, Int) -> [Char] -> GameMonad ()
modifyStrength (Int
1, Int
1) [Char]
"Undercity Necrolisk"
          [Char] -> CardMatcher -> GameMonad () -> GameMonad ()
whenMatch [Char]
"Pitiless Plunderer" CardMatcher
matchInPlay (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
            [Char] -> GameMonad ()
trigger [Char]
"Pitiless Plunderer"
            CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Play)
              (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [Char] -> GameMonad () -> GameMonad ()
withAttribute [Char]
token
              (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [Char] -> GameMonad ()
addArtifact [Char]
"Treasure"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Initial state" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    Player -> GameMonad () -> GameMonad ()
as Player
Opponent (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ Int -> GameMonad ()
setLife Int
9

    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Hand) (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> GameMonad () -> GameMonad ()
withAttribute [Char]
lifelink (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
1, Int
1) [Char]
"Hunted Witness"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
8, Int
5) [Char]
"Silverclad Ferocidons"
      [Char] -> GameMonad ()
addInstant [Char]
"Justice Strike"

    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Play) (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> GameMonad () -> GameMonad ()
withAttribute [Char]
menace (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
9, Int
3) [Char]
"Roc Charger"
      [Char] -> GameMonad ()
addArtifact [Char]
"Desecrated Tomb"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
3, Int
3) [Char]
"Undercity Necrolisk"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
1, Int
4) [Char]
"Pitiless Plunderer"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
2, Int
2) [Char]
"Oathsworn Vampire"
      [Int] -> (Int -> GameMonad ()) -> GameMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
1..Int
4] ((Int -> GameMonad ()) -> GameMonad ())
-> (Int -> GameMonad ()) -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ \Int
n -> do
        [Char] -> GameMonad ()
addLand (Int -> [Char] -> [Char]
numbered Int
n [Char]
"Boros Guildgate")
        [Char] -> GameMonad ()
addLand (Int -> [Char] -> [Char]
numbered Int
n [Char]
"Gateway Plaza")

    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Opponent, Location
Play) (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
4, Int
3) [Char]
"Rekindling Phoenix 1"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
4, Int
3) [Char]
"Rekindling Phoenix 2"
      (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
4, Int
3) [Char]
"Aurelia, Exemplar of Justice"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Cast Hunted Witness and sac it" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"W" [Char]
"Boros Guildgate 1"
    [Char] -> [Char] -> GameMonad ()
cast [Char]
"W" [Char]
"Hunted Witness"
    [Char] -> GameMonad ()
resolve [Char]
"Hunted Witness"

    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"W" [Char]
"Boros Guildgate 2"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Hunted Witness"
    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Play)
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [[Char]] -> GameMonad () -> GameMonad ()
withAttributes [[Char]
lifelink, [Char]
token]
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
1, Int
1) [Char]
"Soldier"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Sac Oathsworn Vampire" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    GameMonad () -> GameMonad ()
forall a. GameMonad a -> GameMonad a
withStateBasedActions (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"1" [Char]
"Treasure"
      [Char] -> GameMonad ()
sacrifice [Char]
"Treasure"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Oathsworn Vampire"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Justice Strike soldier to trigger life gain" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"W" [Char]
"Treasure"
    [Char] -> GameMonad ()
sacrifice [Char]
"Treasure"
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"R" [Char]
"Boros Guildgate 3"

    [Char] -> [Char] -> GameMonad ()
cast [Char]
"RW" [Char]
"Justice Strike"
    [Char] -> GameMonad ()
resolve [Char]
"Justice Strike"
    [Char] -> GameMonad ()
target [Char]
"Soldier"
    [Char] -> [Char] -> GameMonad ()
fight [Char]
"Soldier" [Char]
"Soldier"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Cast Oathsworn Vampire from Graveyard, triggering Desecrated Tomb" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"R" [Char]
"Boros Guildgate 4"
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"B" [Char]
"Gateway Plaza 1"
    CardLocation -> [Char] -> [Char] -> GameMonad ()
castFromLocation (Player
Active, Location
Graveyard) [Char]
"1B" [Char]
"Oathsworn Vampire"
    [Char] -> GameMonad ()
resolve [Char]
"Oathsworn Vampire"

    [Char] -> GameMonad ()
trigger [Char]
"Desecrated Tomb"
    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Play)
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [[Char]] -> GameMonad () -> GameMonad ()
withAttributes [[Char]
flying, [Char]
token]
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
1, Int
1) [Char]
"Bat"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Sac vampire, bat, and plunderer" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"B" [Char]
"Gateway Plaza 2"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Oathsworn Vampire"

    GameMonad () -> GameMonad ()
forall a. GameMonad a -> GameMonad a
withStateBasedActions (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"1" [Char]
"Treasure"
      [Char] -> GameMonad ()
sacrifice [Char]
"Treasure"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Bat"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Repeat vampire/bat cycle" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    GameMonad () -> GameMonad ()
forall a. GameMonad a -> GameMonad a
withStateBasedActions (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"B" [Char]
"Gateway Plaza 3"
      [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"1" [Char]
"Treasure"
      [Char] -> GameMonad ()
sacrifice [Char]
"Treasure"

    CardLocation -> [Char] -> [Char] -> GameMonad ()
castFromLocation (Player
Active, Location
Graveyard) [Char]
"1B" [Char]
"Oathsworn Vampire"
    [Char] -> GameMonad ()
resolve [Char]
"Oathsworn Vampire"

    [Char] -> GameMonad ()
trigger [Char]
"Desecrated Tomb"
    CardLocation -> GameMonad () -> GameMonad ()
withLocation (Player
Active, Location
Play)
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [[Char]] -> GameMonad () -> GameMonad ()
withAttributes [[Char]
flying, [Char]
token]
      (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> [Char] -> GameMonad ()
addCreature (Int
1, Int
1) [Char]
"Bat"

    [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"B" [Char]
"Gateway Plaza 4"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Oathsworn Vampire"

    GameMonad () -> GameMonad ()
forall a. GameMonad a -> GameMonad a
withStateBasedActions (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
      [Char] -> [Char] -> GameMonad ()
tapForMana [Char]
"1" [Char]
"Treasure"
      [Char] -> GameMonad ()
sacrifice [Char]
"Treasure"
    [Char] -> GameMonad ()
sacrificeToNecrolisk [Char]
"Bat"

  [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Attack with Roc and Necrolisk" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
    [Char] -> CardMatcher -> GameMonad ()
validate [Char]
"Roc Charger" (CardMatcher -> GameMonad ()) -> CardMatcher -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [Char] -> CardMatcher
matchAttribute [Char]
"menace"
    [Char] -> CardMatcher -> GameMonad ()
validate [Char]
"Undercity Necrolisk" (CardMatcher -> GameMonad ()) -> CardMatcher -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ [Char] -> CardMatcher
matchAttribute [Char]
"menace"

    [[Char]] -> GameMonad ()
attackWith [[Char]
"Roc Charger", [Char]
"Undercity Necrolisk"]

  let blockers :: [[Char]]
blockers = [[Char]
"Rekindling Phoenix 1", [Char]
"Rekindling Phoenix 2"]

  [GameMonad ()] -> GameMonad ()
fork ([GameMonad ()] -> GameMonad ()) -> [GameMonad ()] -> GameMonad ()
forall a b. (a -> b) -> a -> b
$
    [ [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Roc is blocked" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
        [[Char]] -> [Char] -> GameMonad ()
combatDamage [[Char]]
blockers [Char]
"Roc Charger"
        [[Char]] -> [Char] -> GameMonad ()
combatDamage [] [Char]
"Undercity Necrolisk"
        Player -> Int -> GameMonad ()
validateLife Player
Opponent Int
0
    , [Char] -> GameMonad () -> GameMonad ()
forall a. [Char] -> GameMonad a -> GameMonad a
step [Char]
"Undercity Necrolisk is blocked" (GameMonad () -> GameMonad ()) -> GameMonad () -> GameMonad ()
forall a b. (a -> b) -> a -> b
$ do
        [[Char]] -> [Char] -> GameMonad ()
combatDamage [] [Char]
"Roc Charger"
        [[Char]] -> [Char] -> GameMonad ()
combatDamage [[Char]]
blockers [Char]
"Undercity Necrolisk"
        Player -> Int -> GameMonad ()
validateLife Player
Opponent Int
0
    ]

whenMatch :: CardName -> CardMatcher -> GameMonad () -> GameMonad ()
whenMatch :: [Char] -> CardMatcher -> GameMonad () -> GameMonad ()
whenMatch [Char]
name CardMatcher
f GameMonad ()
action = do
  Bool
match <- [Char] -> CardMatcher -> GameMonad Card
requireCard [Char]
name CardMatcher
f GameMonad Card
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True ExceptT
  [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
-> ([Char]
    -> ExceptT
         [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool)
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
forall e (m :: * -> *) a.
MonadError e m =>
m a -> (e -> m a) -> m a
`catchError` ExceptT
  [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
-> [Char]
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
forall a b. a -> b -> a
const (Bool
-> ExceptT
     [Char] (ReaderT Env (StateT Board (WriterT [Step] Identity))) Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False)

  Bool -> GameMonad () -> GameMonad ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
match GameMonad ()
action

formatter :: p -> Formatter
formatter p
_ = Formatter
boardFormatter