summaryrefslogtreecommitdiffstats
path: root/day05/app/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'day05/app/Main.hs')
-rw-r--r--day05/app/Main.hs235
1 files changed, 235 insertions, 0 deletions
diff --git a/day05/app/Main.hs b/day05/app/Main.hs
new file mode 100644
index 0000000..b56e45b
--- /dev/null
+++ b/day05/app/Main.hs
@@ -0,0 +1,235 @@
+{-
+--- Day 5: Supply Stacks ---
+
+The expedition can depart as soon as the final supplies have been unloaded from the
+ships. Supplies are stored in stacks of marked crates, but because the needed supplies are
+buried under many other crates, the crates need to be rearranged.
+
+The ship has a giant cargo crane capable of moving crates between stacks. To ensure none of
+the crates get crushed or fall over, the crane operator will rearrange them in a series of
+carefully-planned steps. After the crates are rearranged, the desired crates will be at the
+top of each stack.
+
+The Elves don't want to interrupt the crane operator during this delicate procedure, but they
+forgot to ask her which crate will end up where, and they want to be ready to unload them as
+soon as possible so they can embark.
+
+They do, however, have a drawing of the starting stacks of crates and the rearrangement
+procedure (your puzzle input). For example:
+
+ [D]
+[N] [C]
+[Z] [M] [P]
+ 1 2 3
+
+move 1 from 2 to 1
+move 3 from 1 to 3
+move 2 from 2 to 1
+move 1 from 1 to 2
+
+In this example, there are three stacks of crates. Stack 1 contains two crates: crate Z is on
+the bottom, and crate N is on top. Stack 2 contains three crates; from bottom to top, they are
+crates M, C, and D. Finally, stack 3 contains a single crate, P.
+
+Then, the rearrangement procedure is given. In each step of the procedure, a quantity of
+crates is moved from one stack to a different stack. In the first step of the above
+rearrangement procedure, one crate is moved from stack 2 to stack 1, resulting in this
+configuration:
+
+[D]
+[N] [C]
+[Z] [M] [P]
+ 1 2 3
+
+In the second step, three crates are moved from stack 1 to stack 3. Crates are moved one at a
+time, so the first crate to be moved (D) ends up below the second and third crates:
+
+ [Z]
+ [N]
+ [C] [D]
+ [M] [P]
+ 1 2 3
+
+Then, both crates are moved from stack 2 to stack 1. Again, because crates are moved one at a
+time, crate C ends up below crate M:
+
+ [Z]
+ [N]
+[M] [D]
+[C] [P]
+ 1 2 3
+
+Finally, one crate is moved from stack 1 to stack 2:
+
+ [Z]
+ [N]
+ [D]
+[C] [M] [P]
+ 1 2 3
+
+The Elves just need to know which crate will end up on top of each stack; in this example, the
+top crates are C in stack 1, M in stack 2, and Z in stack 3, so you should combine these
+together and give the Elves the message CMZ.
+
+After the rearrangement procedure completes, what crate ends up on top of each stack?
+
+--- Part Two ---
+
+As you watch the crane operator expertly rearrange the crates, you notice the process isn't
+following your prediction.
+
+Some mud was covering the writing on the side of the crane, and you quickly wipe it away. The
+crane isn't a CrateMover 9000 - it's a CrateMover 9001.
+
+The CrateMover 9001 is notable for many new and exciting features: air conditioning, leather
+seats, an extra cup holder, and the ability to pick up and move multiple crates at once.
+
+Again considering the example above, the crates begin in the same configuration:
+
+```
+ [D]
+[N] [C]
+[Z] [M] [P]
+ 1 2 3
+```
+
+Moving a single crate from stack 2 to stack 1 behaves the same as before:
+
+```
+[D]
+[N] [C]
+[Z] [M] [P]
+ 1 2 3
+```
+
+However, the action of moving three crates from stack 1 to stack 3 means that those three moved
+crates stay in the same order, resulting in this new configuration:
+
+```
+ [D]
+ [N]
+ [C] [Z]
+ [M] [P]
+ 1 2 3
+```
+
+Next, as both crates are moved from stack 2 to stack 1, they retain their order as well:
+
+```
+ [D]
+ [N]
+[C] [Z]
+[M] [P]
+ 1 2 3
+```
+
+Finally, a single crate is still moved from stack 1 to stack 2, but now it's crate C that gets moved:
+
+```
+ [D]
+ [N]
+ [Z]
+[M] [C] [P]
+ 1 2 3
+```
+
+In this example, the CrateMover 9001 has put the crates in a totally different order: MCD.
+
+Before the rearrangement process finishes, update your simulation so that the Elves know where
+they should stand to be ready to unload the final supplies. After the rearrangement procedure
+completes, what crate ends up on top of each stack?
+-}
+{-# LANGUAGE DerivingStrategies #-}
+
+module Main (main) where
+
+import Data.ByteString.Lazy (ByteString)
+import Data.Char (digitToInt)
+import Options.Applicative (Parser, ParserInfo, argument, execParser, fullDesc, help, helper, info, metavar, str)
+import Relude hiding (ByteString, elem, empty, filter, fromList, length, null, optional, readFile, splitAt)
+import Text.Parsec (ParseError, parse, (<?>))
+import Text.Parsec.ByteString.Lazy (GenParser)
+import Text.Parsec.Char (char, digit, string, upper)
+import Text.Parsec.Combinator (eof, many1, sepBy1, sepEndBy1)
+import Text.Parsec.Prim (parsecMap, try)
+
+type Opts :: Type
+newtype Opts = Opts {_filename :: Text} deriving stock (Show)
+
+type Supplies :: Type
+newtype Supplies = Supplies {_i :: [[Char]]} deriving stock (Show)
+
+type Order :: Type
+data Order = Order {_amount :: Int, _from :: Int, _to :: Int} deriving stock (Show)
+
+parseInput :: FilePath -> ByteString -> Either ParseError (Supplies, [Order])
+parseInput = parse $ (,) <$> (supplies <* eol) <*> orders
+ where
+ supplies :: GenParser t st Supplies
+ supplies = Supplies <$> many1 (lineBlock <* eol) <* axis
+
+ lineBlock :: GenParser t st [Char]
+ lineBlock = block `sepBy1` space
+
+ block :: GenParser t st Char
+ block = (char '[' *> upper <* char ']') <|> (' ' <$ try (string " "))
+
+ axis :: GenParser t st [()]
+ axis = void space *> (void int `sepEndBy1` spaces) <* eol
+
+ orders :: GenParser t st [Order]
+ orders = many1 order
+
+ order :: GenParser t st Order
+ order =
+ Order
+ <$> (string "move " *> int)
+ <*> (string " from " *> int)
+ <*> (string " to " *> int <* (eol <|> eof))
+
+ space :: GenParser t st Char
+ space = char ' '
+
+ spaces :: GenParser t st [Char]
+ spaces = many1 space
+
+ int :: GenParser t st Int
+ int = foldl' (\a i -> a * 10 + digitToInt i) 0 <$> many1 digit
+
+ eol :: GenParser t st ()
+ eol =
+ parsecMap
+ (const ())
+ ( try (string "\n\r")
+ <|> try (string "\r\n")
+ <|> string "\n"
+ <|> string "\r"
+ <?> "end of line"
+ )
+
+runPart1 :: (Supplies, [Order]) -> (Supplies, [Order])
+runPart1 x = x
+
+runPart2 :: (Supplies, [Order]) -> Int
+runPart2 = undefined
+
+main :: IO ()
+main = do
+ fileName <- toString . _filename <$> execParser opts
+ rawInput <- readFileLBS fileName
+ case parseInput fileName rawInput of
+ Left e -> do
+ putTextLn "Error parsing input:"
+ print e
+ Right r -> do
+ print $ runPart1 r
+ print $ runPart2 r
+ where
+ opts :: ParserInfo Opts
+ opts = info (helper <*> options) fullDesc
+
+ options :: Parser Opts
+ options = Opts <$> filename
+
+ filename :: Parser Text
+ filename = argument str $ metavar "filename" <> help "Input file"