packages feed

haverer 0.2.0.0 → 0.3.0.0

raw patch · 12 files changed

+190/−31 lines, 12 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Haverer.Player: DuplicatePlayers :: [a] -> Error a
- Haverer.Player: InvalidNumPlayers :: Int -> Error a
- Haverer.Player: data Error a
- Haverer.Player: data PlayerSet a
- Haverer.Player: instance GHC.Classes.Eq a => GHC.Classes.Eq (Haverer.Player.Error a)
- Haverer.Player: instance GHC.Classes.Eq a => GHC.Classes.Eq (Haverer.Player.PlayerSet a)
- Haverer.Player: instance GHC.Show.Show a => GHC.Show.Show (Haverer.Player.Error a)
- Haverer.Player: instance GHC.Show.Show a => GHC.Show.Show (Haverer.Player.PlayerSet a)
- Haverer.Player: toPlayerSet :: Ord a => [a] -> Either (Error a) (PlayerSet a)
- Haverer.Player: toPlayers :: PlayerSet a -> [a]
- Haverer.Testing: instance Test.QuickCheck.Arbitrary.Arbitrary (Haverer.Player.PlayerSet Haverer.Testing.PlayerId)
+ Haverer: DuplicatePlayers :: [a] -> PlayerSetError a
+ Haverer: InvalidNumPlayers :: Int -> PlayerSetError a
+ Haverer: data PlayerSet a
+ Haverer: data PlayerSetError a
+ Haverer.PlayerSet: DuplicatePlayers :: [a] -> PlayerSetError a
+ Haverer.PlayerSet: InvalidNumPlayers :: Int -> PlayerSetError a
+ Haverer.PlayerSet: data PlayerSet a
+ Haverer.PlayerSet: data PlayerSetError a
+ Haverer.PlayerSet: instance Data.Foldable.Foldable Haverer.PlayerSet.PlayerSet
+ Haverer.PlayerSet: instance Data.Traversable.Traversable Haverer.PlayerSet.PlayerSet
+ Haverer.PlayerSet: instance GHC.Base.Functor Haverer.PlayerSet.PlayerSet
+ Haverer.PlayerSet: instance GHC.Classes.Eq a => GHC.Classes.Eq (Haverer.PlayerSet.PlayerSet a)
+ Haverer.PlayerSet: instance GHC.Classes.Eq a => GHC.Classes.Eq (Haverer.PlayerSet.PlayerSetError a)
+ Haverer.PlayerSet: instance GHC.Show.Show a => GHC.Show.Show (Haverer.PlayerSet.PlayerSet a)
+ Haverer.PlayerSet: instance GHC.Show.Show a => GHC.Show.Show (Haverer.PlayerSet.PlayerSetError a)
+ Haverer.PlayerSet: randomize :: MonadRandom m => PlayerSet a -> m (PlayerSet a)
+ Haverer.PlayerSet: rotate :: PlayerSet a -> PlayerSet a
+ Haverer.PlayerSet: toPlayerSet :: Ord a => [a] -> Either (PlayerSetError a) (PlayerSet a)
+ Haverer.PlayerSet: toPlayers :: PlayerSet a -> [a]
+ Haverer.Testing: instance Test.QuickCheck.Arbitrary.Arbitrary (Haverer.PlayerSet.PlayerSet Haverer.Testing.PlayerId)
- Haverer: toPlayerSet :: Ord a => [a] -> Either (Error a) (PlayerSet a)
+ Haverer: toPlayerSet :: Ord a => [a] -> Either (PlayerSetError a) (PlayerSet a)

Files

+ Changelog.md view
@@ -0,0 +1,19 @@+# 0.3.0.0 - 2015-06-08++* `PlayerSet` moved to new module, `Haverer.PlayerSet`+* `PlayerSet` now implements `Foldable` and `Traversable`+* New `rotate` and `randomize` methods for `PlayerSet`++# 0.2.0.0 - 2015-06-08++* `Deck` uses associated types for whether or not it is complete+* New `FullType` alias for `Deck 'Complete`+* Burn card is the *first* card from the deck, rather than the first card+  after players have been dealt.+* Burn card is now available for finished rounds (`Haverer.Round.getBurnCard`)+* A list of survivors of each round can be obtained, once the round is over+  (`Haverer.Round.survivors`)++# 0.1.0.0 - 2015-06-07++Initial release.
+ README.md view
@@ -0,0 +1,74 @@+# Haverer++Haverer is a simple implementation of the excellent card game,+[Love Letter](http://boardgamegeek.com/boardgame/129622/love-letter).++It follows the original Japanese rules, rather than the newer American ones.++## Running++At the moment, you'll need to compile from source, which means you'll need to+get set up with `cabal`. The easiest way to do this is to install the+[Haskell Platform](https://www.haskell.org/platform/).++Once you've done that, run the following commands:++```+$ git clone https://github.com/jml/haverer.git+$ cd haverer+$ cabal sandbox init+$ cabal configure+$ cabal install --dependencies-only+$ cabal run+```++That last command, `cabal run`, will run a command-line version of the game.++## License++This code is copyright Jonathan M. Lange, 2014-2015, and is made available+under the Apache License, version 2.0. See LICENSE for details.++## Roadmap++0. Procrastinate endlessly learning new Haskell tricks+1. Wrap this whole thing in an API server+2. Make that server available to the public+3. Put a nice-ish web frontend in front++## Bugs++Please file issues on the+[Github issue tracker](https://github.com/jml/haverer/issues)++## Patches++Are most welcome.++## History++The original implementation of this game is called+[loveletter](https://github.com/jml/loveletter) and is written in+[Rust](http://www.rust-lang.org/).++## Thanks++Thanks to the following people, who have helped with advice, kindness, or by patiently+smiling and nodding while I've rambled on about this project:++* metagnome+* RAOF+* @mithrandi+* pjdelport+* tomprince+* radix+* teh+* simpson+* joliette++Any infelicities are my own.++If you are one of these people and would like to be referred to in another way+(perhaps you'd like me to link to your Github page?), please contact me. You+know how.+
haverer.cabal view
@@ -16,7 +16,7 @@ -- see http://haskell.org/cabal/users-guide/  name:                haverer-version:             0.2.0.0+version:             0.3.0.0 synopsis:            Implementation of the rules of Love Letter description:         Implementation of the rules of Love Letter license:             Apache-2.0@@ -27,6 +27,8 @@ category:            Game build-type:          Simple cabal-version:       >=1.10+extra-source-files:  README.md+                   , Changelog.md  source-repository head   type: git@@ -56,6 +58,7 @@                  , Haverer.Internal.Error                  , Haverer.Internal.Ring                  , Haverer.Player+                 , Haverer.PlayerSet                  , Haverer.Round                  , Haverer.Testing                  , Haverer.ValidMoves
lib/Haverer.hs view
@@ -47,6 +47,8 @@   getDiscards,   getHand,   isProtected,+  PlayerSet,+  PlayerSetError(..),   toPlayers,   toPlayerSet,   ) where@@ -68,9 +70,13 @@   Player,   getDiscards,   getHand,-  isProtected,+  isProtected)+import Haverer.PlayerSet (+  PlayerSetError(..),+  PlayerSet,   toPlayers,-  toPlayerSet)+  toPlayerSet+  ) import Haverer.Round (   BadAction,   Result(..),
lib/Haverer/CLI/CommandLine.hs view
@@ -33,7 +33,8 @@  import Haverer.Action (Play(..), viewAction) import Haverer.Deck (Card(..))-import Haverer.Player (PlayerSet, getDiscards, isProtected, toPlayers)+import Haverer.Player (getDiscards, isProtected)+import Haverer.PlayerSet (PlayerSet, toPlayers) import Haverer.Round (   Event(..),   Result(..),
lib/Haverer/Engine.hs view
@@ -31,7 +31,7 @@ import Haverer.Deck (Card) import qualified Haverer.Game as Game import qualified Haverer.Round as Round-import Haverer.Player (PlayerSet)+import Haverer.PlayerSet (PlayerSet)   class Monad m => MonadEngine m playerId where
lib/Haverer/Game.hs view
@@ -33,8 +33,9 @@ import Control.Monad.Random (MonadRandom)  import Haverer.Deck (FullDeck, newDeck)-import Haverer.Player (+import Haverer.PlayerSet (   PlayerSet,+  rotate,   toPlayers,   ) import Haverer.Round (Round)@@ -75,11 +76,15 @@ newRound game = newRound' game <$> newDeck  -- | Indicate that the specified players won.+--+-- Since 0.3, will also rotate the order of play, so the person to the left of+-- the previous first person is now the first. playersWon :: Ord playerId => Game playerId -> [playerId] -> Either (Outcome playerId) (Game playerId) playersWon game ps =-  bumpRoundsPlayed <$> onCounter game (`Counter.incrementMany` ps)+  rotatePlayers . bumpRoundsPlayed <$> onCounter game (`Counter.incrementMany` ps)   where     bumpRoundsPlayed g = g { _roundsPlayed = _roundsPlayed g + 1 }+    rotatePlayers g = g { _playerSet = rotate (_playerSet g) }  -- | Return the number of rounds played. roundsPlayed :: Game playerId -> Int
lib/Haverer/Player.hs view
@@ -17,7 +17,6 @@  module Haverer.Player (   bust,-  Error(..),   discardAndDraw,   eliminate,   getDiscards,@@ -25,35 +24,17 @@   isProtected,   makePlayer,   Player,-  PlayerSet,   playCard,   protect,   swapHands,-  toPlayers,-  toPlayerSet,   unprotect   ) where  import BasicPrelude import Control.Lens hiding (chosen)-import Control.Monad.Except  import Haverer.Deck (Card) --data Error a = InvalidNumPlayers Int | DuplicatePlayers [a] deriving (Show, Eq)---newtype PlayerSet a = PlayerSet { toPlayers :: [a] } deriving (Show, Eq)---toPlayerSet :: Ord a => [a] -> Either (Error a) (PlayerSet a)-toPlayerSet playerIds-  | numPlayers /= numDistinctPlayers = throwError (DuplicatePlayers playerIds)-  | numPlayers < 2 || numPlayers > 4 = throwError (InvalidNumPlayers numPlayers)-  | otherwise = (return . PlayerSet) playerIds-  where numPlayers = length playerIds-        numDistinctPlayers = (length . nub . sort) playerIds   data Player = Active {
+ lib/Haverer/PlayerSet.hs view
@@ -0,0 +1,67 @@+-- Copyright (c) 2014-2015 Jonathan M. Lange <jml@mumak.net>+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+--     http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Haverer.PlayerSet (+  PlayerSet+  , PlayerSetError(..)+  , toPlayerSet+  , toPlayers+  , randomize+  , rotate+  ) where+++import BasicPrelude+import Control.Monad.Except+import Control.Monad.Random+import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+import System.Random.Shuffle+++data PlayerSetError a = InvalidNumPlayers Int | DuplicatePlayers [a] deriving (Show, Eq)+++newtype PlayerSet a = PlayerSet { toPlayers :: [a] } deriving (Show, Eq, Functor, Traversable, Foldable)+++toPlayerSet :: Ord a => [a] -> Either (PlayerSetError a) (PlayerSet a)+toPlayerSet playerIds+  | numPlayers /= numDistinctPlayers = throwError (DuplicatePlayers playerIds)+  | numPlayers < 2 || numPlayers > 4 = throwError (InvalidNumPlayers numPlayers)+  | otherwise = (return . PlayerSet) playerIds+  where numPlayers = length playerIds+        numDistinctPlayers = (length . nub . sort) playerIds+++-- | Rotate the order of the PlayerSet+--+-- The player who was first is now last, whoever was second is now third,+-- whoever was third is now second, etc.+--+-- Since 0.3+rotate :: PlayerSet a -> PlayerSet a+rotate (PlayerSet (x:xs)) = PlayerSet (xs ++ [x])+rotate _ = error "Empty PlayerSet is impossible"+++-- | Randomize the order of the PlayerSet+--+-- Since 0.3+randomize :: MonadRandom m => PlayerSet a -> m (PlayerSet a)+randomize = map PlayerSet . shuffleM . toPlayers+
lib/Haverer/Round.hs view
@@ -84,12 +84,15 @@   makePlayer,   playCard,   Player,-  PlayerSet,   protect,   swapHands,-  toPlayers,   unprotect   )+import Haverer.PlayerSet (+  PlayerSet,+  toPlayers+  )+  import Haverer.Internal.Error (assertRight) import Haverer.Internal.Ring (Ring, advance1, currentItem, dropItem1, makeRing, nextItem)
lib/Haverer/Testing.hs view
@@ -34,7 +34,7 @@  import Haverer.Action (Play(..)) import Haverer.Deck (baseCards, Card(..), FullDeck, makeDeck)-import Haverer.Player (PlayerSet, toPlayerSet)+import Haverer.PlayerSet (PlayerSet, toPlayerSet) import Haverer.Round (   Round   , Result(..)
tests/test.hs view
@@ -19,7 +19,7 @@ import Test.Tasty  import qualified CLI-import qualified Player+import qualified PlayerSet import qualified Ring import qualified Round @@ -28,7 +28,7 @@ suite =   testGroup "Test Suite" [     CLI.suite-    , Player.suite+    , PlayerSet.suite     , Ring.suite     , Round.suite     ]