module Dovin.Matchers where import Dovin.Prelude import Dovin.Attributes (creature) import Dovin.Types import qualified Data.Set as S import Control.Lens (_1) -- CARD MATCHERS -- -- Matchers are used for both filtering sets of cards, and also for verifying -- attributes of cards. matchDamage :: Int -> CardMatcher matchDamage n = CardMatcher (show n <> " damage") $ (==) n . view cardDamage matchLoyalty :: Int -> CardMatcher matchLoyalty n = CardMatcher (show n <> " loyalty") $ (==) n . view cardLoyalty matchPlusOneCounters :: Int -> CardMatcher matchPlusOneCounters n = CardMatcher (show n <> " +1/+1 counters") $ (==) n . view cardPlusOneCounters matchMinusOneCounters :: Int -> CardMatcher matchMinusOneCounters n = CardMatcher (show n <> " -1/-1 counters") $ (==) n . view cardMinusOneCounters matchLocation :: CardLocation -> CardMatcher matchLocation loc = CardMatcher ("in location " <> show loc) $ (==) loc . view cardLocation matchInPlay = CardMatcher "in play" $ \c -> snd (view location c) == Play matchAttribute :: CardAttribute -> CardMatcher matchAttribute attr = CardMatcher ("has attribute " <> attr) $ S.member attr . view cardAttributes matchAttributes :: [CardAttribute] -> CardMatcher matchAttributes = foldr ((<>) . matchAttribute) mempty matchName :: CardName -> CardMatcher matchName n = CardMatcher ("has name " <> n) $ (==) n . view cardName matchOtherCreatures :: Card -> CardMatcher matchOtherCreatures = matchOther creature matchOther :: CardAttribute -> Card -> CardMatcher matchOther attribute card = matchLocation (view cardLocation card) <> matchAttribute attribute <> invert (matchName (view cardName card)) matchController player = CardMatcher ("has controller " <> show player) $ (==) player . view (location . _1) matchLesserPower n = CardMatcher ("power < " <> show n) $ (< n) . view cardPower matchNone = CardMatcher "never match" (const False) matchCard :: Card -> CardMatcher matchCard = matchName . view cardName matchToughness :: Int -> CardMatcher matchToughness n = labelMatch ("toughness = " <> show n) $ CardMatcher "" ((== n) . view cardToughness) <> matchAttribute creature matchPower :: Int -> CardMatcher matchPower n = labelMatch ("power = " <> show n) $ CardMatcher "" ((== n) . view cardPower) <> matchAttribute creature matchStrength :: (Int, Int) -> CardMatcher matchStrength (p, t) = labelMatch ("P/T = " <> show p <> "/" <> show t) $ matchPower p <> matchToughness t matchTarget :: Target -> CardMatcher matchTarget t = labelMatch ("target = " <> show t) $ CardMatcher "" ((==) t . TargetCard . view cardName) missingAttribute = invert . matchAttribute (CardMatcher d1 f) `matchOr` (CardMatcher d2 g) = CardMatcher (d1 <> " or " <> d2) $ \c -> f c || g c invert :: CardMatcher -> CardMatcher invert (CardMatcher d f) = CardMatcher ("not " <> d) $ not . f labelMatch :: String -> CardMatcher -> CardMatcher labelMatch label (CardMatcher d f) = CardMatcher label f applyMatcherWithDesc :: CardMatcher -> Card -> Either String () applyMatcherWithDesc (CardMatcher d f) c = if f c then Right () else Left d applyMatcher :: CardMatcher -> Card -> Bool applyMatcher matcher c = case applyMatcherWithDesc matcher c of Left _ -> False Right _ -> True