packages feed

unscramble-0.2: Unscramble/Input.hs

module Unscramble.Input (
    readGrid,
    readMult
) where

import Control.Applicative
import Control.Arrow
import Control.Lens
import Data.Char
import qualified Data.HashMap as H
import Data.List
import Data.Maybe
import System.IO
import Text.Printf
import Unscramble.Types

readMult :: IO Multiplier
readMult = do
    dls <- putStrLn "Enter coordinates for double letters, in\
           \ the form 'x y'. The lower left corner is '1 1'\
           \ and the top right is '4 4'. Press enter after each\
           \ set of coordinates. If there are no double\
           \ letters, press enter." >> getCoords
    dws <- putStrLn "Enter coordinates for double words. If there\
           \ are no double words, press enter." >> getCoords
    tls <- putStrLn "Enter coordinates for triple letters. If there\
           \ are no triple letters, press enter." >> getCoords
    tws <- putStrLn "Enter coordinates for triple words. If there\
           \ are no triple words, press enter." >> getCoords
    return $ Multiplier dls (listToMaybe dws) tls (listToMaybe tws)
    where
        getCoords = do
            eo <- isEOF
            if eo
                then return []
                else do
                    r <- getLine
                    case words r of
                        [a,b] -> do
                            l <- getCoords
                            return $ (4 - read b, read a - 1):l
                        [] -> return []
                        _ -> putStrLn "Invalid coordinates." >> return []

readGrid :: Int -> IO Grid
readGrid n = do
    _ <- printf "Enter a %dx%d grid. Remember:\n\
        \- Input only letters and press enter after each line.\n\
        \- You may enter a 'qu' tile as 'qu'.\n" n n
    lines' <- sequence $ replicate n (filter isLetter <$> getLine)
    putStrLn "Received grid."
    return $ parseGrid lines'

parseGrid :: [String] -> Grid
parseGrid input = uncurry Grid
                . (letterMap &&& coordMap)
                . itoListOf (ifolded <.> ifolded)
                $ map tokenize input
    where
        letterMap [] = H.empty
        letterMap (((x,y),str):xs) = H.insertWith (++) str [(x,y)] $! letterMap xs
        coordMap = foldr (uncurry H.insert) H.empty
        tokenize = groupBy (\x y -> [x,y] == "qu")