import Text.Parsec.String (Parser) import Text.Parsec import System.Environment import Control.Monad import Debug.Trace import qualified Data.Map as M num :: Parser Int num = read <$> many1 digit seeds :: Parser [Int] seeds = string "seeds: " *> many1 (read <$> many1 digit <* space) <* newline almanacTitle = (,) <$> many1 (noneOf "-") <* string "-to-" <*> many1 (noneOf " ") <* string " map:" mapLine = (,,) <$> num <* space <*> num <* space <*> num almanacMap :: Parser ([(Int,Int,Int)]) almanacMap = almanacTitle *> newline *> sepEndBy mapLine newline almanac = (,) <$> seeds <*> sepEndBy1 almanacMap newline buildRange :: (Int,Int,Int) -> M.Map Int Int buildRange (dst,src,len) = M.fromList $ zip [src..src+len-1] [dst..dst+len-1] sectionMap :: [(Int,Int,Int)] -> M.Map Int Int sectionMap xs = M.unionsWith (const id) $ (M.fromList $ zip [0..99] [0..99]):map buildRange xs locations :: ([Int], [[(Int,Int,Int)]]) -> [Int] locations (seeds,sections) = do let maps = map sectionMap sections seed <- seeds let location = foldr (M.!) seed (reverse maps) return location solution = minimum . locations main = (>>=) <$> readFile <*> ((print . solution . either (error.show) id) .) . parse almanac =<< head <$> getArgs