deterministic-game-engine 0.1.0.0 → 0.2.0
raw patch · 6 files changed
+137/−42 lines, 6 filesdep +mtldep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: mtl
Dependency ranges changed: base
API changes (from Hackage documentation)
- GameEngine: gameActions :: GameEngine a b -> GameActions a b
- GameEngine: getMoves :: GameActions a b -> GameState a -> [Move b]
+ GameEngine: actions :: GameEngine a b -> GameActions a b
+ GameEngine: getMove :: GameActions a b -> GameState a -> Move b
+ GameEngine: playIO :: (GameState a -> IO ()) -> GameEngine a b -> IO Int
+ GameEngine: playSimple :: GameEngine a b -> Int
- GameEngine: GameActions :: (GameState a -> Player) -> (GameState a -> [Move b]) -> (GameState a -> Move b -> GameState a) -> (GameState a -> Bool) -> (GameState a -> Player -> Int) -> GameActions a b
+ GameEngine: GameActions :: (GameState a -> Player) -> (GameState a -> Move b) -> (GameState a -> Move b -> GameState a) -> (GameState a -> Bool) -> (GameState a -> Player -> Int) -> GameActions a b
- GameEngine: Player :: Char -> Player
+ GameEngine: Player :: Symbol -> Player
- GameEngine: play :: GameEngine a b -> Int
+ GameEngine: play :: Monad m => (GameState a -> m (GameState a)) -> GameEngine a b -> m Int
Files
- Src/GameEngine.hs +65/−25
- Src/GameEngine/GameActions.hs +27/−0
- Src/GameEngine/GameState.hs +6/−0
- Src/GameEngine/Move.hs +6/−0
- Src/GameEngine/Player.hs +10/−0
- deterministic-game-engine.cabal +23/−17
Src/GameEngine.hs view
@@ -1,3 +1,37 @@+{- |++Haskell library for creating simple deterministic games,+such as tic-tac-toe. The engine requires a minimal set of+actions related to the game, and then will run the game+until a terminal state is reached.++Simple generic example below. See the specs for a more detailed example.++> import GameEngine+>+> game :: GameEngine Int Int+> game = GameEngine gameActions initialState+>+> gameActions :: GameActions Int Int+> gameActions = GameActions {+> getPlayer = -- find the next player from a game state,+> getMove = -- find a move from the game state,+> getResult = -- transitions from a state to another state,+> isTerminal = -- determines if the game is terminal,+> getScore = -- get score from a terminal state+> }+>+> initialState :: GameState Int+> initialState = GameState 0+>+> -- run the game engine until a terminal state is reached+> playSimple game++-}++{-# LANGUAGE RankNTypes #-}++ module GameEngine ( Symbol, GameState(..),@@ -5,46 +39,52 @@ Move(..), GameActions(..), GameEngine(..),- play+ play,+ playSimple,+ playIO ) where -type Symbol = Char---data GameState a = GameState a+import Control.Monad.Identity+import GameEngine.GameState+import GameEngine.GameActions+import GameEngine.Move+import GameEngine.Player -data Player = Player Char-+data GameEngine a b = GameEngine {+ actions :: GameActions a b,+ -- ^ Defines how the game will be played -data Move a = Move a+ state :: GameState a+ -- ^ The current state of the game+ }+-- ^ Holds information about how the game is played, and the current state of the game. -data GameActions a b = GameActions {- getPlayer :: GameState a -> Player,- getMoves :: GameState a -> [Move b],- getResult :: GameState a -> Move b -> GameState a,- isTerminal :: GameState a -> Bool,- getScore :: GameState a -> Player -> Int- }+-- TODO: provided function should be forced to be an identity only function+-- forall a. a -> m a+play :: Monad m => (GameState a -> m (GameState a)) -> GameEngine a b -> m Int+-- ^ Run the provided game engine under a monadic context until a terminal state is reached.+-- Note: provided function should act as an identity only, and should not modify the game state.+play f engine+ | performWithState isTerminal engine = return . performWithState getScore engine $ performWithState getPlayer engine+ | otherwise = f (getNextState engine) >>= play f . GameEngine (actions engine) -data GameEngine a b = GameEngine {- gameActions :: GameActions a b,- state :: GameState a- }+playSimple :: GameEngine a b -> Int+-- ^ Run the provided game engine without a context until a terminal state is reached.+playSimple = runIdentity . play Identity -play :: GameEngine a b -> Int-play engine- | performWithState isTerminal engine = performWithState getScore engine $ performWithState getPlayer engine- | otherwise = play $ GameEngine (gameActions engine) (getNextState engine)+playIO :: (GameState a -> IO ()) -> GameEngine a b -> IO Int+-- ^ Run the provided game engine within an IO context until a terminal state is reached.+playIO f = play (f >> return) getNextState :: GameEngine a b -> GameState a-getNextState engine = performWithState getResult engine . head $ performWithState getMoves engine+getNextState engine = performWithState getResult engine $ performWithState getMove engine performWithState :: (GameActions a b -> GameState a -> c) -> GameEngine a b -> c-performWithState f engine = f (gameActions engine) $ state engine+performWithState f engine = f (actions engine) $ state engine
+ Src/GameEngine/GameActions.hs view
@@ -0,0 +1,27 @@+module GameEngine.GameActions (+ GameActions(..)+ ) where+++import GameEngine.Player+import GameEngine.Move+import GameEngine.GameState+++data GameActions a b = GameActions {+ getPlayer :: GameState a -> Player,+ -- ^ Specifies which player has the move in the state++ getMove :: GameState a -> Move b,+ -- ^ Returns a legal move in the state++ getResult :: GameState a -> Move b -> GameState a,+ -- ^ The transition model, which determines the result of a move++ isTerminal :: GameState a -> Bool,+ -- ^ True if game is over, False otherwise++ getScore :: GameState a -> Player -> Int+ -- ^ A utility function to determine the numeric value for a game that ends in a terminal state+ }+-- ^ Set of actions that defines how the game will be played
+ Src/GameEngine/GameState.hs view
@@ -0,0 +1,6 @@+module GameEngine.GameState (+ GameState(..)+ ) where+++data GameState a = GameState a deriving (Eq, Show)
+ Src/GameEngine/Move.hs view
@@ -0,0 +1,6 @@+module GameEngine.Move (+ Move(..)+ ) where+++data Move a = Move a deriving (Eq, Show)
+ Src/GameEngine/Player.hs view
@@ -0,0 +1,10 @@+module GameEngine.Player (+ Symbol,+ Player(..)+ ) where+++type Symbol = Char+++data Player = Player Symbol deriving (Eq, Show)
deterministic-game-engine.cabal view
@@ -1,22 +1,21 @@--- Initial deterministic-game-engine.cabal generated by cabal init. For--- further documentation, see http://haskell.org/cabal/users-guide/- name: deterministic-game-engine-version: 0.1.0.0+version: 0.2.0 synopsis: Simple deterministic game engine-description: Game engine for creating deterministic games.+description: Haskell library for creating simple deterministic games,+ such as tic-tac-toe. The engine requires a minimal set of+ actions related to the game, and then will run the game+ until a terminal state is reached. license: MIT license-file: LICENSE author: Tyler Olson maintainer: tydotg@gmail.com homepage: https://github.com/TGOlson/deterministic-game-engine bug-reports: https://github.com/TGOlson/deterministic-game-engine/issues--- copyright: category: Game Engine build-type: Simple--- extra-source-files: cabal-version: >=1.10 + Source-repository head Type: git Location: https://github.com/TGOlson/deterministic-game-engine@@ -25,17 +24,24 @@ library hs-source-dirs: Src exposed-modules: GameEngine+ other-modules: GameEngine.GameActions,+ GameEngine.GameState,+ GameEngine.Move,+ GameEngine.Player - -- other-modules:- -- other-extensions:- build-depends: base >=4.0 && <5.0+ build-depends: base <5.0,+ mtl+ default-language: Haskell2010 + test-suite test- hs-source-dirs: Spec- main-is: Spec.hs- ghc-options: -Wall- type: exitcode-stdio-1.0- build-depends: base >=4.0 && <5.0,- hspec >=2.1 && <2.2,- deterministic-game-engine+ hs-source-dirs: Spec+ main-is: Spec.hs+ ghc-options: -Wall+ type: exitcode-stdio-1.0+ build-depends: base <5.0,+ hspec >=2.1 && <2.2,+ deterministic-game-engine++ default-language: Haskell2010