module Wordify.Rules.Dictionary (Dictionary, isValidWord, makeDictionary, invalidWords, dictionaryFromWords) where import qualified Data.HashSet as HashSet import Wordify.Rules.ScrabbleError import qualified Control.Exception as Exc import Text.ParserCombinators.Parsec import Text.Parsec.Prim import Data.Char import Control.Monad import Control.Arrow data Dictionary = Dictionary (HashSet.HashSet String) deriving Show {- | Returns the list of words which are not present in the given dictionary from a list of input words. -} invalidWords :: Dictionary -> [String] -> [String] invalidWords dictionary = filter $ not . isValidWord dictionary {- Returns true if the given word is in the given dictionary. -} isValidWord :: Dictionary -> String -> Bool isValidWord (Dictionary dictionaryWords) = flip HashSet.member dictionaryWords dictionaryFromWords :: [String] -> Dictionary dictionaryFromWords = Dictionary . HashSet.fromList . upperCaseWords {- | Creates a dictionary from a file containing a list of valid words, each word being seperated by a newline. -} makeDictionary :: FilePath -> IO (Either ScrabbleError Dictionary) makeDictionary filePath = join . fmap parseDictionary <$> readDictionaryFile filePath readDictionaryFile :: FilePath -> IO (Either ScrabbleError String) readDictionaryFile filePath = convertFileError <$> (Exc.try (readFile filePath) :: (IO (Either Exc.IOException String))) where convertFileError = left (\_ -> DictionaryFileNotFound filePath) parseDictionary :: String -> Either ScrabbleError Dictionary parseDictionary = either (Left . MalformedDictionaryFile . show) (Right . dictionaryFromWords) . parseFile where parseFile = parse dictionaryFile "" dictionaryFile = do dictWords <- many word _ <- eof return dictWords word = do entry <- many letter :: Parser String _ <- newline return entry upperCaseWords :: [String] -> [String] upperCaseWords = (map . map) toUpper