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
28 let wharf = makeWharf wharfLines colNames
30 -- print $ applyMove wharf (head moves)
31 putStrLn $ part1 wharf moves
32 putStrLn $ part2 wharf moves
35 getDataFileName :: IO String
38 progName <- getProgName
39 let baseDataName = if null args
42 let dataFileName = "data/" ++ baseDataName ++ ".txt"
46 part1 :: Wharf -> [Move] -> String
47 part1 wharf moves = showTops $ applyMoves1 wharf moves
49 part2 :: Wharf -> [Move] -> String
50 part2 wharf moves = showTops $ applyMoves2 wharf moves
52 showTops :: Wharf -> String
53 showTops wharf = fmap extractName $ fmap (head . snd) $ M.toAscList wharf
55 extractName :: Crate -> Char
56 extractName (Crate c) = c
58 makeWharf :: [[Maybe Crate]] -> [Int] -> Wharf
59 makeWharf wharfLines colNames = M.fromList $ zip colNames wharfCols
60 where wharfCols = fmap (fmap fromJust)
61 $ fmap (dropWhile isNothing)
62 $ transpose wharfLines
64 applyMoves1 :: Wharf -> [Move] -> Wharf
65 applyMoves1 wharf moves = foldl' applyMove1 wharf moves
67 applyMove1 :: Wharf -> Move -> Wharf
68 applyMove1 wharf m@(Move n _ _) = foldl' makeMove1 wharf (replicate n m)
70 makeMove1 :: Wharf -> Move -> Wharf
71 makeMove1 wharf (Move _ from to) = M.insert from origin
72 $ M.insert to destination wharf
73 where (c:origin) = wharf!from
74 destination = c:(fromMaybe [] $ wharf!?to)
76 applyMoves2 :: Wharf -> [Move] -> Wharf
77 applyMoves2 wharf moves = foldl' applyMove2 wharf moves
79 applyMove2 :: Wharf -> Move -> Wharf
80 applyMove2 wharf (Move n from to) = M.insert from origin'
81 $ M.insert to destination wharf
82 where origin = wharf!from
83 moving = take n origin
84 origin' = drop n origin
85 destination = moving ++ (fromMaybe [] $ wharf!?to)
88 -- Parse the input file
90 problemP :: Parser (([[Maybe Crate]], [Int]), [Move])
91 wharfP :: Parser ([[Maybe Crate]], [Int])
92 wharfLineP :: Parser [Maybe Crate]
93 wharfCellP, blankP, crateP :: Parser (Maybe Crate)
94 stackLabelsP :: Parser [Int]
95 movesP :: Parser [Move]
98 -- problemP = (,) <$> wharfP <* endOfLine <* endOfLine <*> movesP
99 problemP = (,) <$> wharfP <*> movesP
101 wharfP = (,) <$> (wharfLineP `sepBy` endOfLine) <*> stackLabelsP
103 wharfLineP = wharfCellP `sepBy1` (char ' ')
105 wharfCellP = crateP <|> blankP
106 blankP = Nothing <$ (count 3 space)
107 crateP = (Just . Crate) <$> ("[" *> letter) <* "]"
109 -- stackLabelsP = ((many1 space) *> (decimal `sepBy` (many1 space))) <* (takeWhile1 isHorizontalSpace)
110 stackLabelsP = (many1 space)
111 *> (decimal `sepBy` (many1 space))
114 movesP = moveP `sepBy` endOfLine
115 moveP = Move <$> ("move " *> decimal)
116 <*> (" from " *> decimal)
117 <*> (" to " *> decimal)
120 successfulParse :: Text -> (([[Maybe Crate]], [Int]), [Move])
121 successfulParse input =
122 case parseOnly problemP input of
123 Left _err -> (([], []), []) -- TIO.putStr $ T.pack $ parseErrorPretty err
124 Right problem -> problem