diff --git a/src/day9_p1.gleam b/src/day9_p1.gleam index 5d739c1..07e0a2e 100644 --- a/src/day9_p1.gleam +++ b/src/day9_p1.gleam @@ -22,25 +22,29 @@ fn calculate_checksum(filemap: Dict(Int, Int)) -> Int { } fn compact(filemap: Dict(Int, Int)) -> Dict(Int, Int) { - filemap - |> dict.keys + let keys = + filemap + |> dict.keys + |> list.sort(int.compare) + + let to_move = keys |> list.reverse + + keys |> find_gaps - |> list.fold_until(filemap, fn(acc, gap) { - case - acc - |> dict.keys - |> list.reverse - |> list.first - { - Ok(x) if x <= gap -> Stop(acc) - Ok(x) -> - case dict.get(acc, x) { - Ok(val) -> Continue(acc |> dict.delete(x) |> dict.insert(gap, val)) + |> list.fold_until(#(filemap, to_move), fn(acc, gap) { + let #(fmap, fdata) = acc + case fdata { + [x, ..] if x <= gap -> Stop(acc) + [x, ..rest] -> + case dict.get(fmap, x) { + Ok(val) -> + Continue(#(fmap |> dict.delete(x) |> dict.insert(gap, val), rest)) _ -> Stop(acc) } _ -> Stop(acc) } }) + |> pair.first } fn find_gaps(nums: List(Int)) -> List(Int) { diff --git a/src/day9_p2.gleam b/src/day9_p2.gleam new file mode 100644 index 0000000..83c36d0 --- /dev/null +++ b/src/day9_p2.gleam @@ -0,0 +1,115 @@ +import gleam/int +import gleam/io +import gleam/iterator +import gleam/list.{fold, map} +import gleam/result +import gleam/string +import stdin.{stdin} + +pub fn main() { + stdin() + |> read_input + |> compact + |> calculate_checksum + |> io.debug +} + +fn calculate_checksum(filemap: List(Segment)) -> Int { + filemap + |> fold(0, fn(acc, next) { + case next { + File(pos, index, size) -> { + list.range(pos, pos + size - 1) + |> fold(acc, fn(total, x) { total + x * index }) + } + _ -> acc + } + }) +} + +fn compact(filemap: List(Segment)) -> List(Segment) { + filemap + |> list.reverse + |> fold(filemap, fn(acc, next) { + case next { + File(pos, index, size) -> { + let next_gap = + list.find(acc, fn(x) { + case x { + Gap(gap_pos, gap_size) if gap_pos < pos && gap_size >= size -> + True + _ -> False + } + }) + + case next_gap { + Ok(Gap(gap_pos, _)) -> fill_gap(acc, gap_pos, index, size) + _ -> acc + } + } + _ -> acc + } + }) +} + +fn fill_gap( + segments: List(Segment), + gap_pos: Int, + file_index: Int, + file_size: Int, +) -> List(Segment) { + segments + |> fold([], fn(acc, s) { + case s { + Gap(pos, size) if pos == gap_pos && size == file_size -> [ + File(pos, file_index, file_size), + ..acc + ] + Gap(pos, size) if pos == gap_pos -> [ + Gap(pos + file_size, size - file_size), + File(pos, file_index, file_size), + ..acc + ] + File(pos, index, size) if file_index == index -> [Gap(pos, size), ..acc] + _ -> [s, ..acc] + } + }) + |> list.reverse +} + +pub type Segment { + File(position: Int, index: Int, size: Int) + Gap(position: Int, size: Int) +} + +fn read_input(it: iterator.Iterator(String)) -> List(Segment) { + let assert Ok(numbers) = + it + |> iterator.to_list + |> map(fn(line) { + line + |> string.trim + |> string.to_graphemes + |> map(int.parse) + }) + |> list.flatten + |> result.all + + numbers + |> list.index_fold(#([], 0, 0), fn(acc, size, i) { + let #(segments, index, position) = acc + case i % 2 == 0 { + True -> #( + [File(position, index, size), ..segments], + index + 1, + position + size, + ) + False -> #([Gap(position, size), ..segments], index, position + size) + } + }) + |> fn(x) { + let #(segments, _, _) = x + segments + } + |> list.reverse +}