10 | import Control.MonadRec
14 | data Block : Type where
16 | File : (id : Nat) -> Block
17 | %name Block
block, block1, block2
20 | (==) Empty Empty = True
21 | (==) Empty (File id) = False
22 | (==) (File id) Empty = False
23 | (==) (File id) (File id') = id == id'
26 | compare Empty Empty = EQ
27 | compare Empty (File id) = LT
28 | compare (File id) Empty = GT
29 | compare (File id) (File id') = compare id id'
31 | showBlock : (largest_id : Nat) -> Block -> String
32 | showBlock largest_id block =
33 | let pad_len : Nat = cast . strLength . show $
largest_id
37 | (File id) => show id
38 | in padRight pad_len ' ' block_str
43 | block_map : Vect (S len) Block
46 | largestId : Input -> Nat
47 | largestId (MkInput len block_map) =
48 | case foldl max Empty block_map of
54 | let largest_id = largestId input
55 | in joinBy "" . toList . map (showBlock largest_id) $
input.block_map
57 | parseInput : String -> Maybe Input
59 | xs <- traverse (parsePositive . singleton) . unpack . trim $
str
60 | let (
len ** block_map)
= listToVect $
parseHead xs 0 [<]
63 | (S len) => Just $
MkInput len block_map
65 | addRepeat : (count : Nat) -> (val : Block) -> (acc : SnocList Block) -> SnocList Block
66 | addRepeat 0 val acc = acc
67 | addRepeat (S k) val acc = addRepeat k val (acc :< val)
68 | parseHead : (input : List Nat) -> (idx : Nat) -> (acc : SnocList Block) -> List Block
69 | parseHead [] idx acc = toList acc
70 | parseHead (x :: []) idx acc =
71 | let acc = addRepeat x (File idx) acc
72 | in parseHead [] idx acc
73 | parseHead (x :: (y :: xs)) idx acc =
74 | let acc = addRepeat x (File idx) acc
75 | acc = addRepeat y Empty acc
76 | in parseHead xs (S idx) acc
78 | compact : Input -> IO Input
79 | compact (MkInput len block_map) = do
80 | arr <- fromList . map Just . toList $
block_map
81 | trSized forever (arr, 0, (max arr) - 1) stepFn
83 | Just xs <- pure $
traverse id xs
85 | Just xs <- pure $
toVect (S len) xs
87 | pure $
MkInput len xs
89 | nextEmpty : IOArray Block -> Int -> IO Int
94 | Just x <- readArray xs i
98 | File id => nextEmpty xs (i + 1)
100 | prevFile : IOArray Block -> Int -> IO Int
105 | Just x <- readArray xs i
108 | Empty => prevFile xs (i - 1)
111 | swap : IOArray Block -> (i, j : Int) -> IO ()
113 | Just i_val <- readArray xs i
115 | Just j_val <- readArray xs j
117 | _ <- writeArray xs i j_val
118 | _ <- writeArray xs j i_val
122 | CState = (IOArray Block, Int, Int)
124 | stepFn : (seed2 : Fuel) -> CState -> IO (Step Smaller seed2 CState ())
125 | stepFn Dry x = pure $
Done ()
126 | stepFn (More y) (xs, empty, file) = do
127 | next_empty <- nextEmpty xs empty
128 | prev_file <- prevFile xs file
129 | if next_empty >= prev_file
130 | then pure $
Done ()
132 | swap xs next_empty prev_file
134 | pure $
Cont y (believe_me ()) (xs, next_empty, prev_file)
136 | checksum : Input -> Nat
137 | checksum (MkInput len block_map) = checksum' 0 block_map 0
139 | checksum' : (idx : Nat) -> (input : Vect n Block) -> (acc : Nat) -> Nat
140 | checksum' idx [] acc = acc
141 | checksum' idx (Empty :: xs) acc = checksum' (S idx) xs acc
142 | checksum' idx ((File id) :: xs) acc =
143 | checksum' (S idx) xs (id * idx + acc)
146 | part1 : String -> IO (String, Input)
148 | Just input <- pure $
parseInput str
150 | putStrLn "Failed to parse input"
152 | compacted <- compact input
153 | pure (show $
checksum compacted, input)
156 | part2 : Input -> String -> IO String