diff --git a/.travis.yml b/.travis.yml index 56af4bf..8b91246 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,125 +1,139 @@ -# Copy these contents into the root directory of your Github project in a file -# named .travis.yml - -# Use new container infrastructure to enable caching -sudo: false - -# Choose a lightweight base image; we provide our own build tools. +# This Travis job script has been generated by a script via +# +# haskell-ci 'cabal.project' '--no-cabal-check' '--output' '.travis.yml' +# +# For more information, see https://github.com/haskell-CI/haskell-ci +# +# version: 0.3.20190521 +# language: c - -# Caching so the next build will be fast too. +dist: xenial +git: + # whether to recursively clone submodules + submodules: false cache: directories: - - $HOME/.ghc - - $HOME/.cabal - - $HOME/.stack - -# The different configurations we want to test. We have BUILD=cabal which uses -# cabal-install, and BUILD=stack which uses Stack. More documentation on each -# of those below. -# -# We set the compiler values here to tell Travis to use a different -# cache file per set of arguments. -# -# If you need to have different apt packages for each combination in the -# matrix, you can use a line such as: -# addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}} + - $HOME/.cabal/packages + - $HOME/.cabal/store +before_cache: + - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log + # remove files that are regenerated by 'cabal update' + - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.* + - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json + - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache + - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar + - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx + - rm -rfv $CABALHOME/packages/head.hackage matrix: include: - # We grab the appropriate GHC and cabal-install versions from hvr's PPA. See: - # https://github.com/hvr/multi-ghc-travis - - env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 7.8.4" - addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 7.10.3" - addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=8.0.1 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 8.0.1" - addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - # Build with the newest GHC and cabal-install. This is an accepted failure, - # see below. - - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC HEAD" - addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - # The Stack builds. We can pass in arbitrary Stack arguments via the ARGS - # variable, such as using --stack-yaml to point to a different file. - - env: BUILD=stack ARGS="" - compiler: ": #stack default" - addons: {apt: {packages: [ghc-7.10.3], sources: [hvr-ghc]}} - - - env: BUILD=stack ARGS="--resolver lts-2" - compiler: ": #stack 7.8.4" - addons: {apt: {packages: [ghc-7.8.4], sources: [hvr-ghc]}} - - - env: BUILD=stack ARGS="--resolver lts-3" - compiler: ": #stack 7.10.2" - addons: {apt: {packages: [ghc-7.10.2], sources: [hvr-ghc]}} - - - env: BUILD=stack ARGS="--resolver lts-5" - compiler: ": #stack 7.10.3" - addons: {apt: {packages: [ghc-7.10.3], sources: [hvr-ghc]}} - - # Nightly builds are allowed to fail - - env: BUILD=stack ARGS="--resolver nightly" - compiler: ": #stack nightly" - addons: {apt: {packages: [libgmp,libgmp-dev]}} - - allow_failures: - - env: BUILD=cabal GHCVER=head CABALVER=head - - env: BUILD=stack ARGS="--resolver nightly" - + - compiler: ghc-8.6.3 + addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.3","cabal-install-2.4"]}} before_install: -# Using compiler above sets CC to an invalid value, so unset it -- unset CC - -# We want to always allow newer versions of packages when building on GHC HEAD -- CABALARGS="" -- if [ "x$GHCVER" = "xhead" ]; then CABALARGS=--allow-newer; fi - -# add the corresponding paths for cabal -- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin:/opt/alex/$ALEXVER/bin:/opt/happy/$HAPPYVER/bin:$HOME/.cabal/bin:$PATH - -# create stack folder, path and populate it with the stack executable -- mkdir -p ~/.local/bin -- export PATH=$HOME/.local/bin:$PATH -- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' -- stack --version - -# this is needed so cabal can find the newest packages -- | - if [ "$BUILD" = "cabal" ] - then - cabal update - fi - + - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//') + - HCPKG="$HC-pkg" + - unset CC + - CABAL=/opt/ghc/bin/cabal + - CABALHOME=$HOME/.cabal + - export PATH="$CABALHOME/bin:$PATH" + - TOP=$(pwd) + - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') )) + - echo $HCNUMVER + - CABAL="$CABAL -vnormal+nowrap+markoutput" + - set -o pipefail + - | + echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk + echo 'BEGIN { state = "output"; }' >> .colorful.awk + echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk + echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk + echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk + echo ' if (state == "cabal") {' >> .colorful.awk + echo ' print blue($0)' >> .colorful.awk + echo ' } else {' >> .colorful.awk + echo ' print $0' >> .colorful.awk + echo ' }' >> .colorful.awk + echo '}' >> .colorful.awk + - cat .colorful.awk + - | + color_cabal_output () { + awk -f $TOP/.colorful.awk + } + - echo text | color_cabal_output install: -- echo "Installing..." -- | - case "$BUILD" in - stack) - stack clean - stack --no-terminal $ARGS --install-ghc setup - ;; - cabal) - cabal sandbox init - cabal sandbox add-source Magic - cabal sandbox add-source Magic-Cards - cabal sandbox add-source Magic-CLI - cabal sandbox add-source Magic-Web-Server - cabal install --only-dependencies --enable-tests --enable-benchmarks --force-reinstalls Magic Magic-Cards Magic-CLI Magic-Web-Server $CABALARGS - esac - + - ${CABAL} --version + - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]" + - TEST=--enable-tests + - BENCH=--enable-benchmarks + - GHCHEAD=${GHCHEAD-false} + - rm -f $CABALHOME/config + - | + echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config + echo "remote-build-reporting: anonymous" >> $CABALHOME/config + echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config + echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config + echo "world-file: $CABALHOME/world" >> $CABALHOME/config + echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config + echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config + echo "installdir: $CABALHOME/bin" >> $CABALHOME/config + echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config + echo "store-dir: $CABALHOME/store" >> $CABALHOME/config + echo "install-dirs user" >> $CABALHOME/config + echo " prefix: $CABALHOME" >> $CABALHOME/config + echo "repository hackage.haskell.org" >> $CABALHOME/config + echo " url: http://hackage.haskell.org/" >> $CABALHOME/config + - cat $CABALHOME/config + - rm -fv cabal.project cabal.project.local cabal.project.freeze + - travis_retry ${CABAL} v2-update -v + # Generate cabal.project + - rm -rf cabal.project cabal.project.local cabal.project.freeze + - touch cabal.project + - | + echo 'packages: "Magic"' >> cabal.project + echo 'packages: "Magic-Cards"' >> cabal.project + echo 'packages: "Magic-CLI"' >> cabal.project + - | + echo "write-ghc-environment-files: always" >> cabal.project + - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(Magic|Magic-CLI|Magic-Cards)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" + - cat cabal.project || true + - cat cabal.project.local || true + - if [ -f "Magic/configure.ac" ]; then (cd "Magic" && autoreconf -i); fi + - if [ -f "Magic-Cards/configure.ac" ]; then (cd "Magic-Cards" && autoreconf -i); fi + - if [ -f "Magic-CLI/configure.ac" ]; then (cd "Magic-CLI" && autoreconf -i); fi + - ${CABAL} v2-freeze -w ${HC} ${TEST} ${BENCH} | color_cabal_output + - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'" + - rm cabal.project.freeze + - ${CABAL} v2-build -w ${HC} ${TEST} ${BENCH} --dep -j2 all | color_cabal_output + - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2 all | color_cabal_output script: -- echo "Running tests..." -- | - case "$BUILD" in - stack) - stack clean - stack --no-terminal $ARGS --skip-ghc-check test - ;; - cabal) - cabal install --enable-tests --enable-benchmarks --force-reinstalls Magic Magic-Cards Magic-CLI Magic-Web-Server $CABALARGS - esac \ No newline at end of file + - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) + # Packaging... + - ${CABAL} v2-sdist all | color_cabal_output + # Unpacking... + - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/ + - cd ${DISTDIR} || false + - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \; + # Generate cabal.project + - rm -rf cabal.project cabal.project.local cabal.project.freeze + - touch cabal.project + - | + echo 'packages: "Magic-*/*.cabal"' >> cabal.project + echo 'packages: "Magic-Cards-*/*.cabal"' >> cabal.project + echo 'packages: "Magic-CLI-*/*.cabal"' >> cabal.project + - | + echo "write-ghc-environment-files: always" >> cabal.project + - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(Magic|Magic-CLI|Magic-Cards)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" + - cat cabal.project || true + - cat cabal.project.local || true + # Building... + # this builds all libraries and executables (without tests/benchmarks) + - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks all | color_cabal_output + # Building with tests and benchmarks... + # build & run tests, build benchmarks + - ${CABAL} v2-build -w ${HC} ${TEST} ${BENCH} all | color_cabal_output + # haddock... + - ${CABAL} v2-haddock -w ${HC} ${TEST} ${BENCH} all | color_cabal_output + # Building without installed constraints for packages in global-db... + - rm -f cabal.project.local + - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks all | color_cabal_output + +# REGENDATA ["cabal.project","--no-cabal-check","--output",".travis.yml"] +# EOF diff --git a/Magic-CLI/Magic-CLI.cabal b/Magic-CLI/Magic-CLI.cabal index 1121e1c..704ec24 100644 --- a/Magic-CLI/Magic-CLI.cabal +++ b/Magic-CLI/Magic-CLI.cabal @@ -12,6 +12,7 @@ maintainer: martijn@van.steenbergen.nl category: Game build-type: Simple cabal-version: >=1.8 +tested-with: GHC ==8.6.3 executable magic-cli hs-source-dirs: src diff --git a/Magic-CLI/src/Magic/Description.hs b/Magic-CLI/src/Magic/Description.hs index d3d5ef7..e01fdb7 100644 --- a/Magic-CLI/src/Magic/Description.hs +++ b/Magic-CLI/src/Magic/Description.hs @@ -38,9 +38,11 @@ newtype Description = Description { runDescription :: View Text } instance IsString Description where fromString = Description . return . pack +instance Semigroup Description where + Description x <> Description y = Description (mappend <$> x <*> y) + instance Monoid Description where mempty = Description (return mempty) - Description x `mappend` Description y = Description (mappend <$> x <*> y) text :: Text -> Description text = Description . return diff --git a/Magic-Cards/Magic-Cards.cabal b/Magic-Cards/Magic-Cards.cabal index 3834502..20bcf96 100644 --- a/Magic-Cards/Magic-Cards.cabal +++ b/Magic-Cards/Magic-Cards.cabal @@ -12,6 +12,7 @@ maintainer: martijn@van.steenbergen.nl category: Game build-type: Simple cabal-version: >=1.8 +tested-with: GHC ==8.6.3 library hs-source-dirs: src diff --git a/Magic-Web-Server/Magic-Web-Server.cabal b/Magic-Web-Server/Magic-Web-Server.cabal index 2373104..155d53d 100644 --- a/Magic-Web-Server/Magic-Web-Server.cabal +++ b/Magic-Web-Server/Magic-Web-Server.cabal @@ -29,5 +29,5 @@ executable magic-web-server safe ==0.3.*, scientific >= 0.2 && < 0.4, text >=1.1 && <1.3, - vector >=0.10 && <0.12, + vector >=0.10 && <0.13, websockets >=0.8 && <0.10 diff --git a/Magic/Magic.cabal b/Magic/Magic.cabal index c819ff7..8a05ef6 100644 --- a/Magic/Magic.cabal +++ b/Magic/Magic.cabal @@ -12,6 +12,7 @@ maintainer: martijn@van.steenbergen.nl category: Game build-type: Simple cabal-version: >=1.8 +tested-with: GHC ==8.6.3 library hs-source-dirs: src diff --git a/Magic/src/Magic/Engine.hs b/Magic/src/Magic/Engine.hs index 7316b00..97edcc3 100644 --- a/Magic/src/Magic/Engine.hs +++ b/Magic/src/Magic/Engine.hs @@ -134,11 +134,13 @@ fullGame = do -- | Moves to the next step. Returns the new step, and whether a new turn has begun. nextStep :: Engine (Step, Bool) nextStep = do - (rp, s : ss) : ts <- gets turnStructure - turnStructure =: if null ss then ts else (rp, ss) : ts - activePlayer =: rp - activeStep =: s - return (s, null ss) + structure <- gets turnStructure + case structure of + (rp, s : ss) : ts -> do + turnStructure =: if null ss then ts else (rp, ss) : ts + activePlayer =: rp + activeStep =: s + return (s, null ss) @@ -400,19 +402,21 @@ collectSBAs = view $ execWriterT $ do resolve :: ObjectRef TyStackItem -> Engine () resolve r@(Stack, i) = do - StackItem o item <- gets (object r) - let (_, Just mkEffects) = evaluateTargetList item - let eventSource = ResolutionOf r - executeMagic eventSource (mkEffects r (get controller o)) - - -- if the object is now still on the stack, move it to the appropriate zone - if (hasTypes instantType o || hasTypes sorceryType o) - then void $ executeEffect eventSource $ - WillMoveObject (Just (Some Stack, i)) (Graveyard (get controller o)) (CardObject o) - else if hasPermanentType o - then void $ executeEffect eventSource $ - WillMoveObject (Just (Some Stack, i)) Battlefield (Permanent o Untapped 0 False Nothing Nothing) - else void $ executeEffect eventSource $ Will $ CeaseToExist (Some Stack, i) + stackItem <- gets (object r) + case stackItem of + StackItem o item -> do + let (_, Just mkEffects) = evaluateTargetList item + let eventSource = ResolutionOf r + executeMagic eventSource (mkEffects r (get controller o)) + + -- if the object is now still on the stack, move it to the appropriate zone + if (hasTypes instantType o || hasTypes sorceryType o) + then void $ executeEffect eventSource $ + WillMoveObject (Just (Some Stack, i)) (Graveyard (get controller o)) (CardObject o) + else if hasPermanentType o + then void $ executeEffect eventSource $ + WillMoveObject (Just (Some Stack, i)) Battlefield (Permanent o Untapped 0 False Nothing Nothing) + else void $ executeEffect eventSource $ Will $ CeaseToExist (Some Stack, i) collectPriorityActions :: PlayerRef -> Engine [PriorityAction] collectPriorityActions p = do @@ -456,8 +460,10 @@ executePriorityAction :: PlayerRef -> PriorityAction -> Engine () executePriorityAction p a = do case a of PlayCard r -> do - Just ability <- gets (play . objectPart . object r) - activate (PriorityActionExecution a) ability (someObjectRef r) p + maybeAbility <- gets (play . objectPart . object r) + case maybeAbility of + Just ability -> + activate (PriorityActionExecution a) ability (someObjectRef r) p ActivateAbility (r, i) -> do abilities <- gets (activatedAbilities . objectBase r) let ab = abilities !! i diff --git a/Magic/src/Magic/Layers.hs b/Magic/src/Magic/Layers.hs index de77d50..9d1f9ed 100644 --- a/Magic/src/Magic/Layers.hs +++ b/Magic/src/Magic/Layers.hs @@ -73,7 +73,7 @@ affectRestOfBattlefield _ _ _ = return [] -- | Affect whatever object this object is attached to. affectAttached :: Contextual (View [SomeObjectRef]) affectAttached (Some Battlefield, i) _you = do - perm@Permanent {} <- asks (object (Battlefield, i)) + perm <- asks (object (Battlefield, i)) return (maybeToList (get attachedTo perm)) affectAttached _ _ = return [] diff --git a/Magic/src/Magic/Types.hs b/Magic/src/Magic/Types.hs index dc3b00f..0ca90c6 100644 --- a/Magic/src/Magic/Types.hs +++ b/Magic/src/Magic/Types.hs @@ -330,18 +330,20 @@ data ObjectTypes = ObjectTypes , sorcerySubtypes :: Maybe (Set SpellSubtype) } deriving (Eq, Ord, Show, Read) +instance Semigroup ObjectTypes where + x <> y = ObjectTypes + { supertypes = supertypes x <> supertypes y + , artifactSubtypes = artifactSubtypes x <> artifactSubtypes y + , creatureSubtypes = creatureSubtypes x <> creatureSubtypes y + , enchantmentSubtypes = enchantmentSubtypes x <> enchantmentSubtypes y + , instantSubtypes = instantSubtypes x <> instantSubtypes y + , landSubtypes = landSubtypes x <> landSubtypes y + , planeswalkerSubtypes = planeswalkerSubtypes x <> planeswalkerSubtypes y + , sorcerySubtypes = sorcerySubtypes x <> sorcerySubtypes y + } + instance Monoid ObjectTypes where mempty = ObjectTypes mempty mempty mempty mempty mempty mempty mempty mempty - x `mappend` y = ObjectTypes - { supertypes = supertypes x `mappend` supertypes y - , artifactSubtypes = artifactSubtypes x `mappend` artifactSubtypes y - , creatureSubtypes = creatureSubtypes x `mappend` creatureSubtypes y - , enchantmentSubtypes = enchantmentSubtypes x `mappend` enchantmentSubtypes y - , instantSubtypes = instantSubtypes x `mappend` instantSubtypes y - , landSubtypes = landSubtypes x `mappend` landSubtypes y - , planeswalkerSubtypes = planeswalkerSubtypes x `mappend` planeswalkerSubtypes y - , sorcerySubtypes = sorcerySubtypes x `mappend` sorcerySubtypes y - } data Supertype = Basic | Legendary deriving (Eq, Ord, Show, Read, Enum, Bounded) @@ -637,9 +639,11 @@ instance Applicative TargetList where test' (_, y) = test y g' (ab, y) = ab (g y) +instance Semigroup a => Semigroup (TargetList a) where + (<>) = liftA2 (<>) + instance Monoid a => Monoid (TargetList a) where mempty = pure mempty - mappend = liftA2 mappend instance Show (TargetList a) where show _ = "" @@ -652,9 +656,11 @@ instance Show (TargetList a) where newtype ViewT m a = ViewT { runViewT :: ReaderT World m a } deriving (Functor, Applicative, Monad, MonadReader World, MonadTrans) +instance (Semigroup a, Monad m) => Semigroup (ViewT m a) where + ViewT x <> ViewT y = ViewT (liftM2 (<>) x y) + instance (Monoid a, Monad m) => Monoid (ViewT m a) where mempty = return mempty - ViewT x `mappend` ViewT y = ViewT (liftM2 mappend x y) instance (Monad m, Boolean a) => Boolean (ViewT m a) where true = return true @@ -738,9 +744,11 @@ instance MonadView Magic where instance MonadInteract Magic where interact = Magic . lift . lift +instance Semigroup a => Semigroup (Magic a) where + (<>) = liftM2 (<>) + instance Monoid a => Monoid (Magic a) where mempty = return mempty - mappend = liftM2 mappend mkLabels [''World, ''Player, ''Object] diff --git a/README.md b/README.md index 8a47f47..f0dec36 100644 --- a/README.md +++ b/README.md @@ -23,28 +23,20 @@ There is also a command-line interface that allows you to play the game. To run ## Building with cabal -You need [GHC 7.8](http://www.haskell.org/ghc/download_ghc_7_8_2) or greater and [cabal-install 1.24](http://www.haskell.org/cabal/download.html) or greater to build Magic. +You need [GHC 8.6.3](https://www.haskell.org/ghc/download_ghc_8_6_3) or greater and [cabal-install 2.4.1](https://www.haskell.org/cabal/download.html) or greater to build Magic. -Clone the repository and create a Cabal sandbox: +Clone the repository: ``` $ git clone git@github.com:MedeaMelana/Magic.git $ cd Magic -$ cabal sandbox init ``` -If you want to run the command-line interface: +Run the command-line interface: ``` $ cabal new-build Magic-CLI -$ dist-newstyle/build/Magic-CLI-*/build/magic-cli/magic-cli -``` - -If you want to run the web server: - -``` -$ cabal new-build Magic-Web-Server -$ dist-newstyle/build/Magic-Web-Server-*/build/magic-web-server/magic-web-server +$ dist-newstyle/build/*/*/Magic-CLI-*/x/magic-cli/build/magic-cli/magic-cli ``` ## Building with stack diff --git a/cabal.project b/cabal.project index 15a82a9..1b81597 100644 --- a/cabal.project +++ b/cabal.project @@ -1 +1 @@ -packages: Magic/ Magic-Cards/ Magic-CLI/ Magic-Web-Server/ +packages: Magic/ Magic-Cards/ Magic-CLI/