packages feed

starter-snake-haskell 1.0.0 → 1.1.0

raw patch · 16 files changed

+296/−80 lines, 16 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Battlesnake.API.InfoResponse: APIVersion1 :: APIVersion
+ Battlesnake.API.InfoResponse: data APIVersion
+ Battlesnake.API.InfoResponse: instance Data.Aeson.Types.ToJSON.ToJSON Battlesnake.API.InfoResponse.APIVersion
+ Battlesnake.API.InfoResponse: instance GHC.Show.Show Battlesnake.API.InfoResponse.APIVersion
+ Battlesnake.Core.Battlesnake: [customizations] :: Battlesnake -> Customizations
+ Battlesnake.Core.Customizations: Customizations :: Text -> Text -> Text -> Customizations
+ Battlesnake.Core.Customizations: [color] :: Customizations -> Text
+ Battlesnake.Core.Customizations: [head] :: Customizations -> Text
+ Battlesnake.Core.Customizations: [tail] :: Customizations -> Text
+ Battlesnake.Core.Customizations: data Customizations
+ Battlesnake.Core.Customizations: instance Data.Aeson.Types.FromJSON.FromJSON Battlesnake.Core.Customizations.Customizations
+ Battlesnake.Core.Customizations: instance Data.Aeson.Types.ToJSON.ToJSON Battlesnake.Core.Customizations.Customizations
+ Battlesnake.Core.Customizations: instance GHC.Generics.Generic Battlesnake.Core.Customizations.Customizations
+ Battlesnake.Core.Customizations: instance GHC.Show.Show Battlesnake.Core.Customizations.Customizations
+ Battlesnake.Core.Game: [map] :: Game -> Text
+ Battlesnake.Core.Game: [source] :: Game -> Text
+ Battlesnake.Core.Ruleset: [settings] :: Ruleset -> RulesetSettings
+ Battlesnake.Core.RulesetSettings: RoyaleModeSettings :: Int -> RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: RulesetSettings :: Int -> Int -> Int -> RoyaleModeSettings -> SquadModeSettings -> RulesetSettings
+ Battlesnake.Core.RulesetSettings: SquadModeSettings :: Bool -> Bool -> Bool -> Bool -> SquadModeSettings
+ Battlesnake.Core.RulesetSettings: [allowBodyCollisions] :: SquadModeSettings -> Bool
+ Battlesnake.Core.RulesetSettings: [foodSpawnChance] :: RulesetSettings -> Int
+ Battlesnake.Core.RulesetSettings: [hazardDamagePerTurn] :: RulesetSettings -> Int
+ Battlesnake.Core.RulesetSettings: [minimumFood] :: RulesetSettings -> Int
+ Battlesnake.Core.RulesetSettings: [royale] :: RulesetSettings -> RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: [sharedElimination] :: SquadModeSettings -> Bool
+ Battlesnake.Core.RulesetSettings: [sharedHealth] :: SquadModeSettings -> Bool
+ Battlesnake.Core.RulesetSettings: [sharedLength] :: SquadModeSettings -> Bool
+ Battlesnake.Core.RulesetSettings: [shrinkEveryNTurns] :: RoyaleModeSettings -> Int
+ Battlesnake.Core.RulesetSettings: [squad] :: RulesetSettings -> SquadModeSettings
+ Battlesnake.Core.RulesetSettings: data RulesetSettings
+ Battlesnake.Core.RulesetSettings: data SquadModeSettings
+ Battlesnake.Core.RulesetSettings: instance Data.Aeson.Types.FromJSON.FromJSON Battlesnake.Core.RulesetSettings.RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: instance Data.Aeson.Types.FromJSON.FromJSON Battlesnake.Core.RulesetSettings.RulesetSettings
+ Battlesnake.Core.RulesetSettings: instance Data.Aeson.Types.FromJSON.FromJSON Battlesnake.Core.RulesetSettings.SquadModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Classes.Eq Battlesnake.Core.RulesetSettings.RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Classes.Eq Battlesnake.Core.RulesetSettings.RulesetSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Classes.Eq Battlesnake.Core.RulesetSettings.SquadModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Generics.Generic Battlesnake.Core.RulesetSettings.RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Generics.Generic Battlesnake.Core.RulesetSettings.RulesetSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Generics.Generic Battlesnake.Core.RulesetSettings.SquadModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Show.Show Battlesnake.Core.RulesetSettings.RoyaleModeSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Show.Show Battlesnake.Core.RulesetSettings.RulesetSettings
+ Battlesnake.Core.RulesetSettings: instance GHC.Show.Show Battlesnake.Core.RulesetSettings.SquadModeSettings
+ Battlesnake.Core.RulesetSettings: newtype RoyaleModeSettings
- Battlesnake.API.InfoResponse: InfoResponse :: Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> InfoResponse
+ Battlesnake.API.InfoResponse: InfoResponse :: APIVersion -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> InfoResponse
- Battlesnake.API.InfoResponse: [apiversion] :: InfoResponse -> Text
+ Battlesnake.API.InfoResponse: [apiversion] :: InfoResponse -> APIVersion
- Battlesnake.Core.Battlesnake: Battlesnake :: Text -> Text -> Integer -> [Coordinate] -> Text -> Coordinate -> Integer -> Text -> Maybe Text -> Battlesnake
+ Battlesnake.Core.Battlesnake: Battlesnake :: Text -> Text -> Integer -> [Coordinate] -> Text -> Coordinate -> Integer -> Text -> Maybe Text -> Customizations -> Battlesnake
- Battlesnake.Core.Game: Game :: Text -> Ruleset -> Integer -> Game
+ Battlesnake.Core.Game: Game :: Text -> Ruleset -> Text -> Integer -> Text -> Game
- Battlesnake.Core.Ruleset: Ruleset :: Text -> Text -> Ruleset
+ Battlesnake.Core.Ruleset: Ruleset :: Text -> Text -> RulesetSettings -> Ruleset
- Battlesnake.Server: runBattlesnakeServer :: InfoResponse -> GameRequestHandler () -> GameRequestHandler MoveResponse -> GameRequestHandler () -> IO ()
+ Battlesnake.Server: runBattlesnakeServer :: IO InfoResponse -> GameRequestHandler () -> GameRequestHandler MoveResponse -> GameRequestHandler () -> IO ()

Files

CHANGELOG.md view
@@ -5,6 +5,22 @@  This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## 1.1.0 (2023-08-26)++Synced with latest Battlesnake API spec and improved documentation.++### Added++- `map` and `source` fields added to `Game`+- `rulesetSettings` field added to `Ruleset`+- `customizations` field added to `Battlesnake`++### Changed++- the `info` handler passed to `runBattlesnakeServer` must be an IO action now+- `InfoResponse.apiversion` was changed from `Text` to the new `APIVersion` type+  to prevent invalid api version+ ## 1.0.0 (2023-08-22)  ### Added
README.md view
@@ -7,13 +7,78 @@  This starter repo can be used in two different ways -1. Installed as a hackage library in your haskell project 1. As a fork that is subsequently modified to your needs+1. Installed as a hackage library in your haskell project -# Deployment+## As a fork -To deploy on Heroku you can use the provided `Procfile` when using the template-as a fork. Otherwise you will need to define your own `Procfile`.-Addtionally the-[heroku-buildpack-stack](https://github.com/mfine/heroku-buildpack-stack)-buildpack is required for the application to run on heroku+First clone this repo or create a fork by pushing the fork button and clone your+fork.++You can then start implementing your game logic in `app/Main.hs`.++This template uses [Stack](https://docs.haskellstack.org/en/stable/) to build+and run the project.++To start the server locally run `stack run` which will start a development+webserver on port 3000. (The port can be changed by setting the `PORT`+environment variable)++## As hackage dependency++### With cabal++Add the dependency to `your-app.cabal`++```+executable myfirstapp+    main-is: Main.hs+    build-depends:+        ...+        starter-snake-haskell ^>=1.1.0+```++### With stack++Add the dependency as `extra-dep` in your `stack.yaml`++```+resolver: lts-20.26+packages:+  - .++extra-deps:+- starter-snake-haskell-1.1.0+```++### Implementation++You can now start implementing your battlesnake logic in your project. You can+use the [Main](app/Main.hs) from this repo as a starting point.++# Deploy to Heroku++When using the repo as a fork you can use the provided [`Procfile`](Procfile) to+deploy it to heroku. Otherwise you will need to provide your own.++Afterwards you can use the [Heroku+CLI](https://devcenter.heroku.com/articles/heroku-cli#install-the-heroku-cli) to+deploy your project.++First, login to your account:++```+heroku login -i+```++Afterwards you can create a new deployment in heroku using the [heroku-buildpack-stack](https://github.com/mfine/heroku-buildpack-stack).++```+heroku create your-battlesnake-name --buildpack https://github.com/mfine/heroku-buildpack-stack+```++You can then push your code to heroku with git where it will be build and deployed:++```+git push heroku master+```
app/Main.hs view
@@ -14,17 +14,18 @@     moveHandler     endHandler -snakeInfo :: Info.InfoResponse+snakeInfo :: IO Info.InfoResponse snakeInfo =-  Info.InfoResponse-    { Info.apiversion = "1",-      -- Optional Customization:-      Info.author = Nothing, -- TODO: Your Battlsnake username here-      Info.color = Nothing, -- TODO: pesonalize-      Info.head = Nothing, -- TODO: pesonalize-      Info.tail = Nothing, -- TODO: pesonalize-      Info.version = Nothing -- TODO: Version number or tag for your battlesnake-    }+  return+    Info.InfoResponse+      { Info.apiversion = Info.APIVersion1+      , -- Optional Customization:+        Info.author = Nothing -- TODO: Your Battlsnake username here+      , Info.color = Nothing -- TODO: pesonalize+      , Info.head = Nothing -- TODO: pesonalize+      , Info.tail = Nothing -- TODO: pesonalize+      , Info.version = Nothing -- TODO: Version number or tag for your battlesnake+      }  -- TODO: -- implement start handler if you need to allocate ressources or data at the
src/Battlesnake/API/GameRequest.hs view
@@ -13,10 +13,14 @@   This contains all the information you need to determine your snakes next move.} -} data GameRequest = GameRequest-  { game :: Game, -- ^ Information about the current game. (See "Battlesnake.Core.Game")-    turn :: Integer, -- ^ The turn beeing played.-    board :: Board, -- ^ The game board. (See "Battlesnake.Core.Board")-    you :: Battlesnake -- ^ Your snake. (See "Battlesnake.Core.Battlesnake"")+  { game :: Game+  -- ^ Information about the current game. (See "Battlesnake.Core.Game")+  , turn :: Integer+  -- ^ The turn beeing played.+  , board :: Board+  -- ^ The game board. (See "Battlesnake.Core.Board")+  , you :: Battlesnake+  -- ^ Your snake. (See "Battlesnake.Core.Battlesnake"")   }   deriving (Show, Generic) 
src/Battlesnake/API/InfoResponse.hs view
@@ -1,22 +1,35 @@ {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}  module Battlesnake.API.InfoResponse where -import Data.Aeson (ToJSON)+import Data.Aeson (ToJSON, Value (String), toJSON) import Data.Text import GHC.Generics +-- | Supported versions of the Battlesnake API+data APIVersion = APIVersion1 deriving (Show)++instance ToJSON APIVersion where+  toJSON APIVersion1 = String "1"+ {-|   The response to an info request.   This can be used to modify the appearance of your snake on the game board. -} data InfoResponse = InfoResponse-  { apiversion :: Text, -- ^ The API version supported by the battlesnake server (currently 1).-    author :: Maybe Text, -- ^ The username of the author of the snake.-    color :: Maybe Text, -- ^ A color code used to set the color of the snake.-    head :: Maybe Text, -- ^ A custom head to use for the snake. (See https://play.battlesnake.com/customizations for options.)-    tail :: Maybe Text, -- ^ A custom tail to use for the snake. (See https://play.battlesnake.com/customizations for options.)-    version :: Maybe Text -- ^ The version of the snake.+  { apiversion :: APIVersion+  -- ^ The API version supported by the battlesnake server (currently 1).+  , author :: Maybe Text+  -- ^ The username of the author of the snake.+  , color :: Maybe Text+  -- ^ A color code used to set the color of the snake.+  , head :: Maybe Text+  -- ^ A custom head to use for the snake. (See https://play.battlesnake.com/customizations for options.)+  , tail :: Maybe Text+  -- ^ A custom tail to use for the snake. (See https://play.battlesnake.com/customizations for options.)+  , version :: Maybe Text+  -- ^ The version of the snake.   }   deriving (Show, Generic) 
src/Battlesnake/API/MoveResponse.hs view
@@ -9,8 +9,10 @@  -- | The response to a move request. data MoveResponse = MoveResponse-  { move :: Direction, -- ^ The direction for the next move.-    shout :: Maybe Text -- ^ An optional shout to be displayed with the move.+  { move :: Direction+  -- ^ The direction for the next move.+  , shout :: Maybe Text+  -- ^ An optional shout to be displayed with the move.   }   deriving (Show, Generic) 
src/Battlesnake/Core/Battlesnake.hs view
@@ -3,25 +3,36 @@ module Battlesnake.Core.Battlesnake where  import Battlesnake.Core.Coordinate (Coordinate)+import Battlesnake.Core.Customizations (Customizations) import Data.Aeson (FromJSON, ToJSON) import Data.Text import GHC.Generics - {-|   A snake in the game.   See: https://docs.battlesnake.com/api/objects/battlesnake -} data Battlesnake = Battlesnake-  { id :: Text, -- ^ The ID of the snake.-    name :: Text, -- ^ The name of the snake.-    health :: Integer, -- ^ Current health of the snake (0-100).-    body :: [Coordinate], -- ^ A list of coordinates representing the snake's body.-    latency :: Text, -- ^ The snake's latency.-    head :: Coordinate, -- ^ The position of the snakes head-    length :: Integer, -- ^ The length of the snake.-    shout :: Text, -- ^ The snake's last moves shout.-    squad :: Maybe Text -- ^ The squad the snake is a part of (In squad mode).+  { id :: Text+  -- ^ The ID of the snake.+  , name :: Text+  -- ^ The name of the snake.+  , health :: Integer+  -- ^ Current health of the snake (0-100).+  , body :: [Coordinate]+  -- ^ A list of coordinates representing the snake's body.+  , latency :: Text+  -- ^ The snake's latency.+  , head :: Coordinate+  -- ^ The position of the snakes head+  , length :: Integer+  -- ^ The length of the snake.+  , shout :: Text+  -- ^ The snake's last moves shout.+  , squad :: Maybe Text+  -- ^ The squad the snake is a part of (In squad mode).+  , customizations :: Customizations+  -- ^ The customizations of the snake   }   deriving (Show, Generic) 
src/Battlesnake/Core/Board.hs view
@@ -12,11 +12,16 @@   See: https://docs.battlesnake.com/api/objects/board -} data Board = Board-  { height :: Integer, -- ^ The height of the board-    width :: Integer, -- ^ The width of the board-    food :: [Coordinate], -- ^ A list of coordinates representing food locations-    hazards :: [Coordinate], -- ^ A list of coordinates representing hazard locations-    snakes :: [Battlesnake] -- ^ A list of all snakes on the board+  { height :: Integer+  -- ^ The height of the board+  , width :: Integer+  -- ^ The width of the board+  , food :: [Coordinate]+  -- ^ A list of coordinates representing food locations+  , hazards :: [Coordinate]+  -- ^ A list of coordinates representing hazard locations+  , snakes :: [Battlesnake]+  -- ^ A list of all snakes on the board   }   deriving (Show, Generic) 
src/Battlesnake/Core/Coordinate.hs view
@@ -3,19 +3,21 @@ module Battlesnake.Core.Coordinate where  import Data.Aeson-  ( FromJSON (parseJSON),-    KeyValue ((.=)),-    ToJSON (toEncoding),-    pairs,-    withObject,-    (.:),+  ( FromJSON (parseJSON)+  , KeyValue ((.=))+  , ToJSON (toEncoding)+  , pairs+  , withObject+  , (.:)   ) import GHC.Generics  -- | Represents a coordinate on the game board. data Coordinate = Coordinate-  { coordX :: Integer, -- ^ The X coordinate (0 indexed, from left to right)-    coordY :: Integer -- ^ The Y coordinate (0 indexed, from bottom to top)+  { coordX :: Integer+  -- ^ The X coordinate (0 indexed, from left to right)+  , coordY :: Integer+  -- ^ The Y coordinate (0 indexed, from bottom to top)   }   deriving (Show, Eq, Generic) 
+ src/Battlesnake/Core/Customizations.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DeriveGeneric #-}+module Battlesnake.Core.Customizations where++import Data.Aeson (FromJSON, ToJSON)+import Data.Text+import GHC.Generics++{-|+  Battlesnake customizations object+  See: https://docs.battlesnake.com/api/objects/battlesnake+-}+data Customizations = Customizations+  { color :: Text+  -- ^ A hex color code used to display the snake+  , head :: Text+  -- ^ Displayed head of the battlesnake. See+  -- https://docs.battlesnake.com/guides/customizations for available options+  , tail :: Text+  -- ^ Displayed tail of the battlesnake. See+  -- https://docs.battlesnake.com/guides/customizations for available options+  }+  deriving (Show, Generic)++instance ToJSON Customizations++instance FromJSON Customizations
src/Battlesnake/Core/Direction.hs view
@@ -3,10 +3,10 @@ import Data.Aeson (ToJSON, Value (String), toJSON) import Data.Text -{- |+{-|   The possible directions your snake can move in.   See: https://docs.battlesnake.com/api/requests/move- -}+-} data Direction = UP | DOWN | LEFT | RIGHT deriving (Ord, Eq, Show)  instance ToJSON Direction where
src/Battlesnake/Core/Game.hs view
@@ -12,9 +12,18 @@   See: https://docs.battlesnake.com/api/objects/game -} data Game = Game-  { id :: Text, -- ^ The ID of the game.-    ruleset :: Ruleset, -- ^ The ruleset used in the game.-    timeout :: Integer -- ^ The maximum time in milliseconds the server will wait for a response from your server.+  { id :: Text+  -- ^ The ID of the game.+  , ruleset :: Ruleset+  -- ^ The ruleset used in the game.+  , map :: Text+  -- ^ The name of the map used to create the game. (See+  -- https://docs.battlesnake.com/api/objects/game-maps for possible values.)+  , timeout :: Integer+  -- ^ The maximum time in milliseconds the server will wait for a response from+  -- your server.+  , source :: Text+  -- ^ The source of the game.   }   deriving (Show, Eq, Generic) 
src/Battlesnake/Core/Ruleset.hs view
@@ -2,17 +2,21 @@  module Battlesnake.Core.Ruleset where +import Battlesnake.Core.RulesetSettings (RulesetSettings) import Data.Aeson (FromJSON) import Data.Text import GHC.Generics  {-|   Information about the ruleset used in the game.-  See: https://docs.battlesnake.com/api/objects/game+  See: https://docs.battlesnake.com/api/objects/ruleset -} data Ruleset = Ruleset-  { name :: Text, -- ^ The name of the ruleset.-    version :: Text -- ^ The version of the ruleset.+  { name :: Text+  -- ^ The name of the ruleset.+  , version :: Text+  -- ^ The version of the ruleset.+  , settings :: RulesetSettings   }   deriving (Show, Eq, Generic) 
+ src/Battlesnake/Core/RulesetSettings.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE DeriveGeneric #-}++module Battlesnake.Core.RulesetSettings where++import Data.Aeson (FromJSON)+import GHC.Generics++{-|+  Information about the ruleset settings used in the game.+  See: https://docs.battlesnake.com/api/objects/ruleset-settings+-}+data RulesetSettings = RulesetSettings+  { foodSpawnChance :: Int+  -- ^ The chance of a food spawning on a new round (0-100).+  , minimumFood :: Int+  -- ^ The minimum number of food that must be kept on the board+  , hazardDamagePerTurn :: Int+  -- ^ The amount of damage snakes take each turn they are in contact with a+  -- hazard. This stacks on top of the base damage of 1 that each snake takes+  -- per turn+  , royale :: RoyaleModeSettings+  -- ^ Settings uses in 'royale' mode+  , squad :: SquadModeSettings+  -- ^ Settings used in 'squad' mode+  }+  deriving (Show, Eq, Generic)++instance FromJSON RulesetSettings++-- | Settings used in `royale` mode+newtype RoyaleModeSettings = RoyaleModeSettings+  { shrinkEveryNTurns :: Int+  -- ^ The number of turns between shrinking the safe board area+  }+  deriving (Show, Eq, Generic)++instance FromJSON RoyaleModeSettings++-- | Settings used in 'squad' mode+data SquadModeSettings = SquadModeSettings+  { allowBodyCollisions :: Bool+  -- ^ Whether or not snakes on the same squad can collide with each other+  -- without diyng+  , sharedElimination :: Bool+  -- ^ Whether or not snakes on the same squad  are eliminated together+  , sharedHealth :: Bool+  -- ^ Whether or not snakes on the same squad share health+  , sharedLength :: Bool+  -- ^ Whether or not snakes on the same squad share length+  }+  deriving (Show, Eq, Generic)++instance FromJSON SquadModeSettings
src/Battlesnake/Server.hs view
@@ -7,27 +7,30 @@ import Data.Functor ((<&>)) import Data.Maybe (fromMaybe) import System.Environment (lookupEnv)-import System.IO (BufferMode(LineBuffering), hSetBuffering, stdout)+import System.IO (BufferMode (LineBuffering), hSetBuffering, stdout) import Text.Read (readMaybe) import Web.Scotty - -- | A handler for a battlesnake server request. type GameRequestHandler a = GameRequest -> IO a -{- |+{-|   Run a battlesnake server. Runs the server on the port specified by the environment variable "PORT" or port 3000 if the variable is not set.-  * A "Battlesnake.API.InfoResponse" to be returned when the server receives an info request.++  * An IO action that returns a "Battlesnake.API.InfoResponse" which is run on info requests.+   * A 'GameRequestHandler' to be called when the server receives a start request.+   * A 'GameRequestHandler' to be called when the server receives a move request.+   * A 'GameRequestHandler' to be called when the server receives an end request. -}-runBattlesnakeServer ::-  Info.InfoResponse ->-  GameRequestHandler () ->-  GameRequestHandler MoveResponse ->-  GameRequestHandler () ->-  IO ()+runBattlesnakeServer+  :: IO Info.InfoResponse+  -> GameRequestHandler ()+  -> GameRequestHandler MoveResponse+  -> GameRequestHandler ()+  -> IO () runBattlesnakeServer info startHandler moveHandler endHandler = do   hSetBuffering stdout LineBuffering   envPort <- lookupEnv "PORT" <&> (readMaybe =<<)@@ -38,20 +41,20 @@       moveHandler       endHandler -routes ::-  Info.InfoResponse ->-  GameRequestHandler () ->-  GameRequestHandler MoveResponse ->-  GameRequestHandler () ->-  ScottyM ()+routes+  :: IO Info.InfoResponse+  -> GameRequestHandler ()+  -> GameRequestHandler MoveResponse+  -> GameRequestHandler ()+  -> ScottyM () routes info startHandler moveHandler endHandler = do   get "/" $ handleInfoRequest info   post "/start" $ handleStartRequest startHandler   post "/move" $ handleMoveRequest moveHandler   post "/end" $ handleEndRequest endHandler -handleInfoRequest :: Info.InfoResponse -> ActionM ()-handleInfoRequest = json+handleInfoRequest :: IO Info.InfoResponse -> ActionM ()+handleInfoRequest info = liftIO info >>= json  handleStartRequest :: GameRequestHandler () -> ActionM () handleStartRequest handler = do
starter-snake-haskell.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           starter-snake-haskell-version:        1.0.0+version:        1.1.0 synopsis:       A Haskell Battlesnake starter description:    See README at <https://github.com/ccntrq/starter-snake-haskell> category:       Game, Web@@ -34,9 +34,11 @@       Battlesnake.Core.Battlesnake       Battlesnake.Core.Board       Battlesnake.Core.Coordinate+      Battlesnake.Core.Customizations       Battlesnake.Core.Direction       Battlesnake.Core.Game       Battlesnake.Core.Ruleset+      Battlesnake.Core.RulesetSettings       Battlesnake.Server   other-modules:       Paths_starter_snake_haskell