packages feed

quoridor-hs-0.1.1.0: src/Quoridor/Cmdline/Parse.hs

module Quoridor.Cmdline.Parse
  ( parseTurn,
    parseMessage
  ) where

import           Control.Applicative             (pure)
import           Data.Char                       (toUpper)
import           Data.Functor                    ((<$>))
import           Data.List                       (elemIndex)
import           Data.Maybe                      (fromJust)

import           Text.Parsec                     (Parsec, anyChar, char, digit,
                                                  eof, many1, manyTill, oneOf,
                                                  parse, spaces, (<|>))

import           Quoridor
import           Quoridor.Cmdline.Messages       (validMovesChars)
import           Quoridor.Cmdline.Network.Common (Message (TurnMsg, ChatMsg))

type Parse = Parsec String ()

-- helper functions

pMessage :: Color -> Parse Message
pMessage col =
  (TurnMsg <$> pTurn) <|> (ChatMsg col <$> pChat)

-- t STRING
pChat :: Parse String
pChat = do
  char 't'
  asToken $ manyTill anyChar eof

pTurn :: Parse Turn
pTurn = do
  res <- pMove <|> pShortCutMove <|> pPutGate
  eof
  return res

-- m y x
pMove :: Parse Turn
pMove = do
  char 'm'
  Move <$> pCell

-- one of 'validMovesChars', translated
-- into their index.
pShortCutMove :: Parse Turn
pShortCutMove = do
    c <- oneOf validMovesChars
    return $ ShortCutMove $ translate c
  where translate c = fromJust $ elemIndex c validMovesChars

-- g y x h|v
pPutGate :: Parse Turn
pPutGate = do
  char 'g'
  c <- pCell
  PutGate . gateUpperLeft c <$> pDirection

pCell :: Parse Cell
pCell = do
  y <- pInt
  x <- pInt
  return (y,x)

pDirection :: Parse Direction
pDirection = cToDirection <$> asToken (oneOf "hv")
  where cToDirection = (read :: String -> Direction) . pure . toUpper

pInt :: Parse Int
pInt = (read :: String -> Int) <$> asToken (many1 digit)

asToken :: Parse a -> Parse a
asToken p = spaces >> p

parseShowErrMsgs :: Parse a -> String -> Either String a
parseShowErrMsgs p str = func $ parse p "" str
  where func (Left errMsgs) = Left $ show errMsgs
        func (Right x) = Right x


-- exported functions

-- | Given a string representing a turn,
-- Parses it and returns the Turn.
-- This is used by the local client, which doesn't use
-- the Message type
--
-- Note: This is not the same string as show turn, it is
-- a more concise, for example: "m y x" to move
-- to (y,x)
parseTurn :: String -> Either String Turn
parseTurn = parseShowErrMsgs pTurn

-- | Aggregates the turn parser with a chat parser to
-- make a Message parser
parseMessage :: Color -> String -> Either String Message
parseMessage col = parseShowErrMsgs $ pMessage col