quoridor-hs-0.1.0.0: src/Quoridor/Cmdline/Options.hs
module Quoridor.Cmdline.Options
( Options(..)
, ExecMode(..)
, getOptions
) where
import Control.Monad (unless)
import System.Environment (getProgName)
import System.Exit (exitFailure, exitSuccess)
import System.Console.GetOpt (ArgDescr (NoArg, OptArg),
ArgDescr (ReqArg),
ArgOrder (RequireOrder), OptDescr,
OptDescr (Option), getOpt, usageInfo)
import Quoridor.Helpers (andP)
-- | Represents possible options from the cmdline
data Options = Options
{ opBoardSize :: Int
, opNumOfPlayers :: Int
, opGatesPerPlayer :: Int
, opHostListenPort :: Int
, opHttpListenPort :: Int
, opExecMode :: ExecMode
}
-- | Represents an execution mode for the program.
-- One can run quoridor at local play, server host or client join modes
data ExecMode = ExLocal | ExHost | ExJoin | ExProxy
deriving Eq
defaultOptions :: Options
defaultOptions = Options
{ opBoardSize = 9
, opNumOfPlayers = 2
, opGatesPerPlayer = 10
, opHostListenPort = 33996
, opHttpListenPort = 33997
, opExecMode = ExLocal
}
-- exported functions
-- | Given the args from the cmdline,
-- returns them parsed into an Options data value.
-- It runs in the IO monad to allow the ability to exit the program
-- if something fails in the parsing (upon which, a usageInfo will be displayed)
getOptions :: [String] -> IO Options
getOptions args = do
let (actions, _, _) = getOpt RequireOrder options args
foldl (>>=) (return defaultOptions) actions
--helpers
isInRange :: Ord a => a -> a -> a -> Bool
isInRange a b c = ((>= b) `andP` (<= c)) a
putUsageInfoLn :: IO ()
putUsageInfoLn = do
prg <- getProgName
putStrLn (usageInfo prg options)
options :: [ OptDescr (Options -> IO Options) ]
options =
[ Option "b" ["board-size"]
(ReqArg
(\arg opts -> do
argNum <- rangedOption 2 9 arg
return opts { opBoardSize = argNum })
"INTEGER")
"Board size (2-9 rows/columns). default 9"
, Option "n" ["number-of-players"]
(ReqArg
(\arg opts -> do
argNum <- rangedOption 2 4 arg
return opts { opNumOfPlayers = argNum })
"INTEGER")
"Number of players (2-4 players). default 2"
, Option "g" ["gates-per-player"]
(ReqArg
(\arg opts -> do
argNum <- rangedOption 0 100 arg
return opts { opGatesPerPlayer = argNum })
"INTEGER")
"Gates per player (1-100 gates per player). default 10"
, Option "l" ["local"]
(NoArg $
\opts -> return opts { opExecMode = ExLocal })
"Start a local game"
, Option "h" ["host"]
(portOptionArg ExHost)
"Host a game server. default port 33997"
, Option "j" ["join"]
(portOptionArg ExJoin)
"Join a game server"
, Option "p" ["client-proxy"]
(portOptionArg ExProxy)
"Client acts as proxy for a browser (used by the http server)"
, Option "t" ["http-port"]
(ReqArg
(\arg opts -> do
argNum <- rangedOption 1025 65535 arg
return opts { opHttpListenPort = argNum })
"PORT")
"A port for the http-server (port 1025-65535), relevant only if --host flag is used. default 33997"
, Option "?" ["help"]
(NoArg $
\_ -> do
putUsageInfoLn
exitSuccess)
"Show help"
]
where portOptionArg execMode =
OptArg
(\arg opts -> do
argNum <- maybe (return $ opHostListenPort opts)
(rangedOption 1025 65535) arg
return opts
{ opExecMode = execMode
, opHostListenPort = argNum
})
"PORT"
rangedOption x y arg = do
let argNum = read arg
unless (isInRange argNum x y) $ do
putUsageInfoLn
exitFailure
return argNum