Day 5: Fuck you, depends your types
This commit is contained in:
parent
93e7ffc42f
commit
27d37e64b3
|
@ -0,0 +1,112 @@
|
|||
import System.File.ReadWrite
|
||||
import Data.Vect
|
||||
import Data.String
|
||||
import Data.Fin
|
||||
|
||||
data Crate = C Char
|
||||
|
||||
Show Crate where
|
||||
show (C c) = pack ['[', c, ']']
|
||||
|
||||
parseCrate : String -> Maybe Crate
|
||||
parseCrate str = let str = unpack str in
|
||||
case str of
|
||||
('[' :: x :: ']' :: _) => Just (C x)
|
||||
_ => Nothing
|
||||
|
||||
data Stacks : Nat -> Type where
|
||||
Stks : { n : Nat } -> Vect n (List Crate) -> Stacks n
|
||||
|
||||
Show (Stacks n) where
|
||||
show (Stks {n} stacks) =
|
||||
let longestStack = foldl max 0 . map length $ stacks
|
||||
stringStacks = map (extendFront longestStack " ") . map (map show) $ stacks
|
||||
lastLine = joinBy " " . map (\x => " " ++ (show x) ++ " ") $ rangeFromTo 1 n
|
||||
stackLines = map (joinBy " " . toList) . transpose $ stringStacks
|
||||
in joinBy "\n" . toList $ (snoc stackLines lastLine)
|
||||
where extendFront : (m : Nat) -> a -> List a -> Vect m a
|
||||
extendFront m x xs =
|
||||
let extended = if length xs < m
|
||||
then replicate (minus m (length xs)) x ++ xs
|
||||
else take m xs
|
||||
in case toVect m extended of
|
||||
Just vect => vect
|
||||
Nothing => replicate m x
|
||||
transpose : { a : _ } -> Vect b (Vect a e) -> Vect a (Vect b e)
|
||||
transpose [] = replicate _ []
|
||||
transpose (x :: xs) = let xsTrans = transpose xs in
|
||||
zipWith (::) x xsTrans
|
||||
|
||||
parseStacks : {n : Nat} -> List String -> Stacks n
|
||||
parseStacks [] = Stks $ replicate _ []
|
||||
-- Special logic for skipping the last line, since that's just the stack numbers
|
||||
parseStacks (x :: []) = Stks $ replicate _ []
|
||||
parseStacks {n} (x :: xs) =
|
||||
let (Stks bottom) = parseStacks xs
|
||||
row : Vect n (Maybe Crate)
|
||||
row = map parseCrate . map pack . chunk 4 [] . unpack $ x
|
||||
in Stks $ zipWith parseStacksHelper row bottom
|
||||
where chunk : {n : Nat} -> (m: Nat) -> List a -> List a -> Vect n (List a)
|
||||
chunk {n = 0} m defaultValue xs = []
|
||||
chunk {n = (S k)} m defaultValue [] = replicate _ defaultValue
|
||||
chunk {n = (S k)} m defaultValue xs =
|
||||
let (head, tail) = splitAt m xs in
|
||||
head :: chunk {n = k} m defaultValue tail
|
||||
parseStacksHelper : Maybe Crate -> List Crate -> List Crate
|
||||
parseStacksHelper (Just crate) xs = crate :: xs
|
||||
parseStacksHelper Nothing xs = xs
|
||||
|
||||
-- Get the tops of each stack
|
||||
tops : Stacks n -> String
|
||||
tops (Stks xss) = pack . map (\(C c) => c) . catMaybes . toList . map head' $ xss
|
||||
|
||||
data Command : Nat -> Type where
|
||||
Cmd : {n : Nat} -> Nat -> Fin n -> Fin n -> Command n
|
||||
|
||||
Show (Command n) where
|
||||
show (Cmd x y z) = (show x) ++ " " ++ (show ((finToNat y) + 1)) ++ "->" ++ (show ((finToNat z) + 1))
|
||||
|
||||
parseCommand : {n : Nat} -> String -> Maybe (Command n)
|
||||
parseCommand str =
|
||||
let nums = toVect 3 . catMaybes . map parsePositive . words $ str
|
||||
in do [x, y, z] <- nums
|
||||
from <- natToFin (minus y 1) n
|
||||
to <- natToFin (minus z 1) n
|
||||
Just (Cmd x from to)
|
||||
|
||||
-- Apply a command to a collection of stacks
|
||||
applyCommand : {n : Nat} -> Bool -> Command n -> Stacks n -> Stacks n
|
||||
applyCommand multiple (Cmd count from to) stacks =
|
||||
let (crates, removed) = extractCrates count from stacks
|
||||
in addCrates (if multiple then crates else reverse crates) to removed
|
||||
where extractCrates : Nat -> Fin n -> Stacks n -> ((List Crate), Stacks n)
|
||||
extractCrates count from (Stks stacks) =
|
||||
let stack = index from stacks
|
||||
(head, tail) = splitAt count stack
|
||||
in (head, Stks $ replaceAt from tail stacks)
|
||||
addCrates : List Crate -> Fin n -> Stacks n -> Stacks n
|
||||
addCrates crates to (Stks stacks) =
|
||||
let stack = index to stacks
|
||||
in Stks $ replaceAt to (crates ++ stack) stacks
|
||||
|
||||
-- Apply a list of commands to a stacks
|
||||
applyCommands : {n : Nat} -> Bool -> List (Command n) -> Stacks n -> Stacks n
|
||||
applyCommands multiple commands stacks = foldl (\stack, command => applyCommand multiple command stack) stacks commands
|
||||
|
||||
main : IO ()
|
||||
main =
|
||||
do file <- readFile "input"
|
||||
case file of
|
||||
Right content =>
|
||||
let stacks = parseStacks {n = 9} . takeWhile (/= "") . lines $ content
|
||||
commands = catMaybes . map (parseCommand {n = 9}) . drop 1 . dropWhile (/= "") . lines $ content
|
||||
part1 = tops $ applyCommands False commands stacks
|
||||
part2 = tops $ applyCommands True commands stacks
|
||||
in do putStrLn "Input:"
|
||||
printLn stacks
|
||||
putStrLn ""
|
||||
putStr "Part 1: "
|
||||
putStrLn part1
|
||||
putStr "Part 2: "
|
||||
putStrLn part2
|
||||
Left err => printLn err
|
Loading…
Reference in New Issue