packages feed

PlayHangmanGame-0.2: src/WordsOp.hs

module WordsOp
  ( defaultWords
  , buildMapByLength
  , buildListLetterFrequency
  , buildMapWordsFrequency
  ) where

import Control.Monad (liftM)
import Data.Function (on)
import Data.List (groupBy, sortBy, sort)
import Data.Tuple (swap)
import System.IO
import qualified Data.Map as Map
import System.Directory (doesFileExist)

import Types

defaultWordsFile :: FilePath
defaultWordsFile = "../data/words.txt"

-- | read the default words file.
defaultWords :: IO WordDataSet
defaultWords = readFileToWords defaultWordsFile

readFileToWords :: FilePath -> IO WordDataSet
readFileToWords fp = liftM wrapWordDataSet (readfile' fp)

-- | Readfile if exists otherwise return empty.
readfile' :: FilePath -> IO String
readfile' fp = do
               e <- doesFileExist fp
               if e then readFile fp else return []

wrapWordDataSet :: String -- ^ File Content
                -> WordDataSet -- ^ Wrapped data set
wrapWordDataSet [] = ([], Map.empty)
wrapWordDataSet xs = let ws = lines xs in
                     (ws, buildMapByLength ws)
                         
-- | FIXME: a little annoying that loop the groupBy result in order to get key for map.
buildMapByLength :: [EnglishWord] -- ^ a alphabet sorted words list
                 -> Map.Map Int [EnglishWord]
buildMapByLength xs = Map.fromList [ (length $ head ys, ys) | ys <- group' $ sort' xs ]
                      where sort' = sortBy (compare `on` length)
                            group' = groupBy ((==) `on` length)

englishAlp :: [Letter]
englishAlp = "abcdefghijklmnopqrstuvwxyz"

{-
 Splitted Word List by alphabet sequency.
 @param@ a sorted list that has words with same length.
 @return@ {"a": [...], "b":[...], ... }
-}
buildMapWordsFrequency :: [EnglishWord] -> MapPerAlphabet
buildMapWordsFrequency ws = Map.mapWithKey f init
                       where init = Map.fromList [ (x, []) | x <- englishAlp ]
                             f k _ = [ b | b <- ws, k `elem` b]

{-
  @param@ wordsObj :: {"a":[...], "b":[...], ...}
  @return@ list which elements are order by word frequency.
          e.g. ["c","a","b"]
-}

buildListLetterFrequency :: Map.Map Char [EnglishWord] -> [Letter]
buildListLetterFrequency v = reverse $ map fst $ sortBy (compare `on` swap) $ Map.toList (Map.map length v)