1 -- Writeup at https://work.njae.me.uk/2022/12/04/advent-of-code-2022-day-4/
3 import System.Environment
4 import Data.Text (Text)
5 import qualified Data.Text.IO as TIO
6 import Data.Attoparsec.Text hiding (take)
7 import Control.Applicative
10 import qualified Data.IntMap.Strict as M
11 import Data.IntMap.Strict ((!), (!?))
13 data Crate = Crate Char deriving (Show, Eq)
14 type Wharf = M.IntMap [Crate]
16 data Move = Move Int Int Int -- quantity, from, to
22 do dataFileName <- getDataFileName
23 text <- TIO.readFile dataFileName
24 let ((wharfLines, colNames), moves) = successfulParse text
25 let wharf = makeWharf wharfLines colNames
26 putStrLn $ part1 wharf moves
27 putStrLn $ part2 wharf moves
30 getDataFileName :: IO String
33 progName <- getProgName
34 let baseDataName = if null args
37 let dataFileName = "data/" ++ baseDataName ++ ".txt"
41 part1 :: Wharf -> [Move] -> String
42 part1 wharf moves = showTops $ applyMoves1 wharf moves
44 part2 :: Wharf -> [Move] -> String
45 part2 wharf moves = showTops $ applyMoves2 wharf moves
47 showTops :: Wharf -> String
48 showTops wharf = fmap extractName $ fmap (head . snd) $ M.toAscList wharf
50 extractName :: Crate -> Char
51 extractName (Crate c) = c
53 makeWharf :: [[Maybe Crate]] -> [Int] -> Wharf
54 makeWharf wharfLines colNames = M.fromList $ zip colNames wharfCols
55 where wharfCols = fmap catMaybes $ transpose wharfLines
57 applyMoves1 :: Wharf -> [Move] -> Wharf
58 applyMoves1 wharf moves = foldl' applyMove1 wharf moves
60 applyMove1 :: Wharf -> Move -> Wharf
61 applyMove1 wharf m@(Move n _ _) = foldl' makeMove1 wharf (replicate n m)
63 makeMove1 :: Wharf -> Move -> Wharf
64 makeMove1 wharf (Move _ from to) = M.insert from origin
65 $ M.insert to destination wharf
66 where (c:origin) = wharf!from
67 destination = c:(fromMaybe [] $ wharf!?to)
69 applyMoves2 :: Wharf -> [Move] -> Wharf
70 applyMoves2 wharf moves = foldl' applyMove2 wharf moves
72 applyMove2 :: Wharf -> Move -> Wharf
73 applyMove2 wharf (Move n from to) = M.insert from origin'
74 $ M.insert to destination wharf
75 where origin = wharf!from
76 moving = take n origin
77 origin' = drop n origin
78 destination = moving ++ (fromMaybe [] $ wharf!?to)
81 -- Parse the input file
83 problemP :: Parser (([[Maybe Crate]], [Int]), [Move])
84 wharfP :: Parser ([[Maybe Crate]], [Int])
85 wharfLineP :: Parser [Maybe Crate]
86 wharfCellP, blankP, crateP :: Parser (Maybe Crate)
87 stackLabelsP :: Parser [Int]
88 movesP :: Parser [Move]
91 -- problemP = (,) <$> wharfP <* endOfLine <* endOfLine <*> movesP
92 problemP = (,) <$> wharfP <*> movesP
94 wharfP = (,) <$> (wharfLineP `sepBy` endOfLine) <*> stackLabelsP
96 wharfLineP = wharfCellP `sepBy1` (char ' ')
98 wharfCellP = crateP <|> blankP
99 blankP = Nothing <$ (count 3 space)
100 crateP = (Just . Crate) <$> ("[" *> letter) <* "]"
102 -- stackLabelsP = ((many1 space) *> (decimal `sepBy` (many1 space))) <* (takeWhile1 isHorizontalSpace)
103 stackLabelsP = (many1 space)
104 *> (decimal `sepBy` (many1 space))
107 movesP = moveP `sepBy` endOfLine
108 moveP = Move <$> ("move " *> decimal)
109 <*> (" from " *> decimal)
110 <*> (" to " *> decimal)
113 successfulParse :: Text -> (([[Maybe Crate]], [Int]), [Move])
114 successfulParse input =
115 case parseOnly problemP input of
116 Left _err -> (([], []), []) -- TIO.putStr $ T.pack $ parseErrorPretty err
117 Right problem -> problem