module Wordify.Rules.Dictionary (Dictionary, makeDictionary, dictionaryFromWords, isValidWord, invalidWords ) 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