DOPKLXQZP3TDISHODQNI6GZ57EYE42NG225WHSZMQ3L355YVYPNAC FCKXFNKSGWZEQ5P4MPTJQM55EZC7J7R7UOP7SV3XXYSLJPC55ELAC XBFPOITOZLMUZROJCW2YAUHFTVKPZMRO5GQL36BACBS2ELIU4R4QC SNYOEZI7JMTLJNLM2YTAHBPJEKK2BJZJDOHRIX5676JCF2VNET3QC FMGVXDGYAU36I3WXAAM77IITTMQ3IF3J66FQKOD6IULF5VYXMB7AC XAMFHYIWLYWVS52I3PNB7QB2YUBJQI3ORGFRTJOKW55GOFTYWRYQC U3PXWO2PKW4XI4NXYMEQT44SXBQDVFZBDBW6YYOFSMANGI53V4ZQC FUOJJ2E7WNHF2NNKBI7MF254TU5Z5VOEKMO2XAJMY7RDOUQTMG6QC C3BUGSBWBKOXFFB6TIHDLQVFV65OKKW6KEUVMP4O2XP3RYMPJ5QAC {-# LANGUAGE DeriveFunctor #-}{-# LANGUAGE FlexibleInstances #-}{-# LANGUAGE GeneralisedNewtypeDeriving #-}{-# LANGUAGE TypeFamilies #-}module StateRep (RDefault,CardMap,R,eval,evalMany,) whereimport Control.Monad.Stateimport Data.Foldableimport Data.Map (Map)import qualified Data.Map as Mapimport Data.Text (Text)import Refinedimport Deckimport Difftype CardMap = Map Text Cardtype RDefault = R (State CardMap)newtype R m a = R {unR :: m a} deriving (Functor, Applicative, Monad)instance DeckSYM (R (State CardMap)) whereadd x = R $ dodeck <- getput $ Map.insert (unrefine . runText $ name x) x deckremove cardName = R $ dodeck <- getput $ Map.delete (unrefine . runText $ cardName) deckinstance HunkSYM (R (State CardMap)) wherelookup x = R $ dodeck <- getcardName <- unR xreturn $ Map.lookup cardName deckchunk oldCardName f = R $ docardFunction <- unR . sequence $ fdecklist <- getcase Map.lookup (unrefine . runText $ oldCardName) decklist ofNothing -> return ()Just oldCard ->let newCard = foldl' (\acc cardUpd -> cardUpd acc) oldCard cardFunctionin put $Map.update (const $ Just newCard) (unrefine . runText $ oldCardName) decklistmodifyCopies newCopies = doreturn $ \oldCard -> dolet newQuantity = newCopies . quantity $ oldCardoldCard {quantity = newQuantity}modifyCategory categoryF = doreturn $ \oldCard -> dolet newCategory = categoryF . Deck.category $ oldCardoldCard {Deck.category = newCategory}move x = const <$> xeval :: R (State CardMap) a -> CardMapeval = flip execState mempty . unRevalMany :: (Traversable t) => t (RDefault ()) -> CardMapevalMany x = flip execState mempty $ mapM unR x
{-# LANGUAGE LambdaCase #-}{-# LANGUAGE OverloadedStrings #-}{-# LANGUAGE TemplateHaskell #-}{-# LANGUAGE TypeApplications #-}module Parser (ReadError (..),readCard,readDeckList,) whereimport Control.Arrowimport Data.Bifunctorimport Data.Either.Extraimport Data.List.Extraimport Data.Text (Text)import qualified Data.Text as Timport qualified Data.Text.IO as TIOimport Text.Read (readMaybe)import GHC.Naturalimport Refined hiding (validate)import Deckimport Diffdata ReadError = IllegalFormat | RefineError !RefineException deriving (Show)readCard :: Category -> Text -> Either [ReadError] CardreadCard c n =let toError (l, r) = case l ofNothing -> Left $ singleton IllegalFormatJust x -> Right (x, r)refined :: (Predicate p a) => a -> Either ReadError (Refined p a)refined = mapLeft RefineError . refinevalidate =arr (fmap PositiveNumber . refined) *** arr (fmap NonEmptyText . refined)>>> arr( \case(Right x, Right y) -> Right (x, y)(Left x, Left y) -> Left [x, y](Left x, _) -> Left $ singleton x(_, Left x) -> Left $ singleton x)toCard tup = (\(x, y) -> Card y x c) <$> validate tupin (toError . bimap (readMaybe @Natural) T.pack . word1 . T.unpack $ n)>>= toCardreadDeckList :: (DeckSYM repr) => FilePath -> IO (Either [ReadError] [repr ()])readDeckList p = docontent <- windowsToLinuxNewLine <$> TIO.readFile plet (mb, sb) = T.breakOn "\n\n" contentmb' = mapM (readCard mainboard) (T.lines mb)sb' = mapM (readCard sideboard) (T.lines . T.stripStart $ sb)return $ fmap add <$> liftA2 (++) mb' sb'wherewindowsToLinuxNewLine = T.replace "\r\n" "\n"
{-# LANGUAGE TypeApplications #-}{-# LANGUAGE TypeFamilies #-}module Diff (HunkSYM (..),DeckSYM (..),diff,) whereimport Data.Map (Map)import qualified Data.Map as Mapimport Data.Text (Text)import Refinedimport Deckclass DeckSYM repr where-- | Add a card to the deckadd :: Card -> repr ()-- | Remove a card from the deckremove :: CardName -> repr ()class HunkSYM repr where-- | A diff chunk for a cardchunk :: (Traversable t) => CardName -> t (repr (Card -> Card)) -> repr ()modifyCopies :: (PositiveNumber -> PositiveNumber) -> repr (Card -> Card)modifyCategory :: (Category -> Category) -> repr (Card -> Card)-- | Lookup a card in the decklookup :: repr Text -> repr (Maybe Card)-- | Move a card to another categorymove :: repr Category -> repr (Category -> Category)diff :: (HunkSYM repr, DeckSYM repr) => DeckList -> DeckList -> [repr ()]diff left right =let deckSort = map snd . Map.toDescList . runDeckListin go mempty (deckSort left) (deckSort right)wherego :: (HunkSYM repr, DeckSYM repr) => [repr ()] -> [Card] -> [Card] -> [repr ()]go acc [] [] = accgo acc xs [] = acc ++ map (remove . name) xsgo acc [] ys = acc ++ map add ysgo acc lx@(x : xs) ly@(y : ys)| name x < name y = go (remove (name x) : acc) xs ly| name x > name y = go (add x : acc) lx ys| otherwise =case (partialEqCard quantity x y, partialEqCard category x y) of(True, True) -> go acc xs ys(False, False) -> go (chunk (name x) [modifyCopies (const $ quantity y), modifyCategory (const . category $ y)] : acc) xs ys(False, _) -> go (chunk (name x) [] : acc) xs ys(_, False) -> go (chunk (name x) [] : acc) xs ys
{- | Applies a diff to a decklist. If a card doesn't exist during a change in copies it is ignored.| This is ignored because we don't have a concept of default category.-}-- applyDiff :: DeckDiff -> DeckList -> DeckList-- applyDiff [] ys = ys-- applyDiff (x : xs) decklist =-- case x of-- Add a -> applyDiff xs (insert a decklist)-- Remove a -> delete a decklist-- ChangeCard name newQuan newCat ->-- let newQuantity = newQuan . quantity <$> card-- newCategory = card <$> newCat-- cardQuantity = fromIntegral . unrefine . runNumber . quantity-- card = Deck.find name decklist-- -- choice =-- -- either-- -- (const $ applyDiff (Remove name : xs) decklist)-- -- (\quantity -> update (\(x', _) -> (x', PositiveNumber quantity)) name decklist)-- -- choiceFind =-- -- maybe-- -- decklist-- -- (choice . refine . fromIntegral . newQuantity . cardQuantity)-- in choiceFind card
initDeckList :: IO DeckListinitDeckList = dogen <- createSystemRandomnid <- nanoID genreturn . DeckList . Set.fromList $ []
-- initDeckList :: IO DeckList-- initDeckList = do-- gen <- createSystemRandom-- nid <- nanoID gen-- return . DeckList . Set.fromList $ []