puzzle-draw-0.2.0.0: src/tools/checkpuzzle.hs
{-# LANGUAGE FlexibleContexts #-}
module Main where
import Text.Puzzles.Puzzle
import Data.Puzzles.PuzzleTypes (typeNames, PuzzleType(..))
import Data.Puzzles.CmdLine (exitErr, readPuzzle, checkType)
import Data.Puzzles.Elements (digitList)
import qualified Text.Puzzles.PuzzleTypes as T
import Options.Applicative
import Control.Monad
import Data.Maybe
import Data.List (intercalate, sort)
import System.Exit
import System.Environment (getProgName)
import qualified Data.Yaml as Y
optListTypes :: Parser (a -> a)
optListTypes =
infoOption
(unlines' . sort . map snd $ typeNames)
(long "list-types"
<> help "List supported puzzle types")
where
unlines' = intercalate "\n"
data PuzzleOpts = PuzzleOpts
{ _type :: Maybe String
, _input :: FilePath
}
puzzleOpts :: Parser PuzzleOpts
puzzleOpts = PuzzleOpts
<$> (optional . strOption $
(long "type" <> short 't'
<> metavar "TYPE"
<> help "Puzzle type, overriding type in input file"))
<*> argument str
(metavar "INPUT"
<> help "Puzzle file in .pzl format")
defaultOpts :: Parser a -> IO a
defaultOpts optsParser = do
prog <- getProgName
let p = info (helper <*> optListTypes <*> optsParser)
(fullDesc
<> progDesc "Command-line puzzle checking."
<> header prog)
execParser p
main :: IO ()
main = do
opts <- defaultOpts puzzleOpts
mp <- readPuzzle (_input opts)
TP mt pv msv _ <- case mp of Left e -> exitErr $
"parse failure: " ++ show e
Right p -> return p
t <- checkType $ _type opts `mplus` mt
sv <- maybe (exitErr $ "need solution") return msv
let es = Y.parseEither (check t) (pv, sv)
case es of Left err -> exitErr $ "parse failure: " ++ err
Right [] -> exitSuccess
Right es' -> mapM_ putStrLn es' >> exitFailure
check :: PuzzleType -> (Y.Value, Y.Value) -> Y.Parser [String]
check t (pv, sv) =
case t of
ABCtje -> checkABCtje (pv, sv)
_ -> return []
checkABCtje :: (Y.Value, Y.Value) -> Y.Parser [String]
checkABCtje (pv, sv) = do
p <- fst T.abctje $ pv
s <- snd T.abctje $ sv
return . catMaybes . map (\c -> c p s) $
[ solutionKeys, values ]
where
solutionKeys (ds, _) s = let have = sort (digitList ds)
want = sort (map fst (s))
in if have /= want then Just "unequal digit lists" else Nothing
values (_, ws) vs = (\es -> case es of [] -> Nothing
_ -> Just $ intercalate ", " es)
. catMaybes
. map (\(w, v) -> if val w == v
then Nothing
else Just (w ++ " should be " ++ show (val w)))
$ ws
where
l c = fromMaybe 0 . lookup c . map (\(x, y) -> (y, x)) $ vs
val = sum . map l