packages feed

battleships-1.0.0: Handler/PlaceShips.hs

----------------------------------------------------------------------------
-- |
-- Module      :  Handler.PlaceShips
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Handler for a UI for placing the player's ships. The user configures the
-- fleet placement in a javascript client side UI, which then posts the fleet
-- JSON encoded to the handler.
--
-- Random completion of a fleet is implemented using a POST request
-- to the 'PlaceShipsRndR' route by the javascript code, which uses 'completeFleet'
-- to try and complete the player's ship placement.

module Handler.PlaceShips
  ( getPlaceShipsR
  , postPlaceShipsR
  , postPlaceShipsRndR
  ) where

import           Import
import           Data.Aeson (encode, decode)
import           Data.Maybe
import qualified Data.Text.Encoding as TE
import           Handler.Util
import           Handler.Play
import           Logic.AIUtil
import           Logic.Game
import           Logic.DefaultAI
import           Logic.Binary (fromStrict)
import           Logic.Types

-------------------------------------------------------------------------------
-- * Handler
-------------------------------------------------------------------------------

-- | Displays a client side UI for placing the player's fleet.
getPlaceShipsR :: Options -> Handler Html
getPlaceShipsR options = defaultLayout $ do
  setNormalTitle
  messageRender <- getMessageRender
  addScript $ StaticR js_jquery_js
  addScript $ StaticR js_json2_js
  addScript $ StaticR js_map_js
  $(widgetFile "board")
  $(widgetFile "placeships")

-- | Validates the player's fleet; if it's correct, the game is started.
postPlaceShipsR :: Options -> Handler Html
postPlaceShipsR options = do
  ships <- getPostedFleet
  case ships of
    Nothing             -> redirect $ PlaceShipsR options
    Just fleetPlacement -> startGame options fleetPlacement

-- | Starts a game, given the placement of the player's fleet.
startGame :: Options -> FleetPlacement -> Handler Html
startGame Options{..} fleetPlacement = do
  extra <- getExtra
  let
    rules = Rules
      { rulesAgainWhenHit   = againWhenHit
      , rulesMove           = move
      , rulesDifficulty     = difficulty
      , rulesMaximumTurns   = extraMaxTurns extra
      , rulesCountdownTurns = extraCountdownTurns extra
      }
  game  <- liftIO (newGame rules noviceMode (development && devMode) fleetPlacement HumanPlayer :: IO (GameState DefaultAI))
  expGameH game >>= playView True game -- redirect . PlayR True

-------------------------------------------------------------------------------
-- * Random Completion
-------------------------------------------------------------------------------

-- | POST handler for completing a player's fleet.
--
-- Accepts a posted fleet and tries to complete it; if there is a valid
-- completion, that one is sent back to the UI. Otherwise an empty fleet is
-- returned in order to indicate that no such completion exists.
postPlaceShipsRndR :: Handler TypedContent
postPlaceShipsRndR = do
  fleet  <- fmap (fromMaybe []) getPostedFleet
  fleet' <- liftIO $ completeFleet fleet
  return $ jsonFleet $ fromMaybe [] fleet'

-------------------------------------------------------------------------------
-- * JSON Fleet Import/Export
-------------------------------------------------------------------------------

-- | Parses fleet submitted by POST in a field named "fleetData".
getPostedFleet :: Handler (Maybe FleetPlacement)
getPostedFleet = do
  jsonStr <- runInputPost $ ireq textField "fleetData"
  return $ decode (fromStrict $ TE.encodeUtf8 jsonStr)

-- | Converts a FleetPlacement to JSON data
jsonFleet :: FleetPlacement -> TypedContent
jsonFleet
  = TypedContent typeJson
  . toContent
  . encode