module Code.Competition (
Solveable(..), Parseable(..), runCompetition, runSolution, runWriteSolution
) where
import System.Environment (getArgs)
import System.FilePath (replaceExtension)
import Text.ParserCombinators.Parsec (parse, ParseError, GenParser)
import Code.Competition.Parsers (probfile)
class (Show a) => Solveable p a where
solve :: p -> a
class Parseable p where
problem :: GenParser Char st p
parseProblemFile :: Parseable p => String -> Either ParseError [p]
parseProblemFile input = parse (probfile problem) "(unknown)" input
runCompetition :: (Solveable p a, Parseable p, Show p) => IO [(p, a)]
runCompetition = do
args <- getArgs
inputFn <- return $ head args
let outputFn = if length args >= 2 then (args !! 1) else (replaceExtension inputFn ".out")
(output, probans) <- runWriteSolution inputFn outputFn
putStr output
return probans
runSolution :: (Solveable p a, Parseable p, Show p) => String -> IO (String, [(p, a)])
runSolution inputFn = do
input <- readFile inputFn
problems <- case parseProblemFile input of
Left pe -> handleParseError pe
Right xs -> return xs
answers <- return $ map solve problems
output <- return $ (unlines . caseify) answers
return (output, zip problems answers)
runWriteSolution :: (Solveable p a, Parseable p, Show p) => String -> String -> IO (String, [(p, a)])
runWriteSolution inputFn outputFn = do
(output, probans) <- runSolution inputFn
writeFile outputFn output
return (output, probans)
handleParseError :: Parseable p => ParseError -> IO [p]
handleParseError err = do
putStrLn $ show err
return []
caseify :: Show a => [a] -> [String]
caseify as = map (\(i,a) -> "Case #" ++ (show i) ++ ": " ++ (show a)) (zip [1..] as)