diff --git a/src/day10_p1.gleam b/src/day10_p1.gleam new file mode 100644 index 0000000..f5131be --- /dev/null +++ b/src/day10_p1.gleam @@ -0,0 +1,70 @@ +import gleam/bool +import gleam/dict.{type Dict} +import gleam/int +import gleam/io +import gleam/iterator +import gleam/list.{filter, filter_map, fold, map, reverse} +import gleam/option.{type Option, None, Some} +import gleam/result +import gleam/string +import stdin.{stdin} + +pub fn main() { + stdin() + |> read_input + |> calculate_trails + |> io.debug +} + +fn calculate_trails(topomap: Dict(#(Int, Int), Int)) -> Int { + topomap + |> find_trailheads + |> map(fn(x) { count_trails_loop(topomap, x, 0) }) + |> map(list.length) + |> fold(0, int.add) +} + +fn count_trails_loop( + topomap: Dict(#(Int, Int), Int), + pos: #(Int, Int), + offset: Int, +) -> List(#(Int, Int)) { + let #(x, y) = pos + case dict.get(topomap, pos) { + Ok(9) if offset == 9 -> { + [pos] + } + Ok(n) if n == offset -> + [ + count_trails_loop(topomap, #(x, y - 1), offset + 1), + count_trails_loop(topomap, #(x, y + 1), offset + 1), + count_trails_loop(topomap, #(x - 1, y), offset + 1), + count_trails_loop(topomap, #(x + 1, y), offset + 1), + ] + |> filter(fn(x) { x |> list.is_empty |> bool.negate }) + |> list.flatten + |> list.unique + _ -> [] + } +} + +fn find_trailheads(topomap: Dict(#(Int, Int), Int)) -> List(#(Int, Int)) { + topomap |> dict.filter(fn(_, v) { v == 0 }) |> dict.keys +} + +fn read_input(it: iterator.Iterator(String)) -> Dict(#(Int, Int), Int) { + it + |> iterator.fold([], fn(acc, line) { + case string.trim(line) { + "" -> acc + str -> { + [str |> string.to_graphemes |> filter_map(int.parse), ..acc] + } + } + }) + |> reverse + |> list.index_fold(dict.new(), fn(acc, line, y) { + line + |> list.index_fold(acc, fn(dic, num, x) { dict.insert(dic, #(x, y), num) }) + }) +} diff --git a/src/day10_p2.gleam b/src/day10_p2.gleam new file mode 100644 index 0000000..a23e89b --- /dev/null +++ b/src/day10_p2.gleam @@ -0,0 +1,69 @@ +import gleam/bool +import gleam/dict.{type Dict} +import gleam/int +import gleam/io +import gleam/iterator +import gleam/list.{filter, filter_map, fold, map, reverse} +import gleam/option.{type Option, None, Some} +import gleam/result +import gleam/string +import stdin.{stdin} + +pub fn main() { + stdin() + |> read_input + |> calculate_trails + |> io.debug +} + +fn calculate_trails(topomap: Dict(#(Int, Int), Int)) -> Int { + topomap + |> find_trailheads + |> map(fn(x) { count_trails_loop(topomap, x, 0) }) + |> map(list.length) + |> fold(0, int.add) +} + +fn count_trails_loop( + topomap: Dict(#(Int, Int), Int), + pos: #(Int, Int), + offset: Int, +) -> List(#(Int, Int)) { + let #(x, y) = pos + case dict.get(topomap, pos) { + Ok(9) if offset == 9 -> { + [pos] + } + Ok(n) if n == offset -> + [ + count_trails_loop(topomap, #(x, y - 1), offset + 1), + count_trails_loop(topomap, #(x, y + 1), offset + 1), + count_trails_loop(topomap, #(x - 1, y), offset + 1), + count_trails_loop(topomap, #(x + 1, y), offset + 1), + ] + |> filter(fn(x) { x |> list.is_empty |> bool.negate }) + |> list.flatten + _ -> [] + } +} + +fn find_trailheads(topomap: Dict(#(Int, Int), Int)) -> List(#(Int, Int)) { + topomap |> dict.filter(fn(_, v) { v == 0 }) |> dict.keys +} + +fn read_input(it: iterator.Iterator(String)) -> Dict(#(Int, Int), Int) { + it + |> iterator.fold([], fn(acc, line) { + case string.trim(line) { + "" -> acc + str -> { + [str |> string.to_graphemes |> filter_map(int.parse), ..acc] + } + } + }) + |> reverse + |> list.index_fold(dict.new(), fn(acc, line, y) { + line + |> list.index_fold(acc, fn(dic, num, x) { dict.insert(dic, #(x, y), num) }) + }) +}