diff options
Diffstat (limited to 'aoc2023')
-rw-r--r-- | aoc2023/src/day14/.gitignore | 1 | ||||
-rw-r--r-- | aoc2023/src/day14/solve.gleam | 90 | ||||
-rw-r--r-- | aoc2023/src/utilities/memo.gleam | 8 | ||||
-rw-r--r-- | aoc2023/test/day14/day14_test.gleam | 66 |
4 files changed, 161 insertions, 4 deletions
diff --git a/aoc2023/src/day14/.gitignore b/aoc2023/src/day14/.gitignore new file mode 100644 index 0000000..ae40cea --- /dev/null +++ b/aoc2023/src/day14/.gitignore @@ -0,0 +1 @@ +input.txt
\ No newline at end of file diff --git a/aoc2023/src/day14/solve.gleam b/aoc2023/src/day14/solve.gleam new file mode 100644 index 0000000..3113d91 --- /dev/null +++ b/aoc2023/src/day14/solve.gleam @@ -0,0 +1,90 @@ +import adglent.{First, Second} +import gleam/io +import gleam/string +import gleam/list +import gleam/order +import gleam/int +import gleam/iterator +import gleam/result +import utilities/memo.{type Cache} + +fn parse(input) { + input + |> string.split("\n") + |> list.map(string.to_graphemes) + |> list.transpose() +} + +fn roll_boulders(strs: List(String)) { + { + use chunks <- list.map(list.chunk(strs, fn(c) { c == "O" || c == "." })) + list.sort(chunks, order.reverse(string.compare)) + } + |> list.flatten +} + +fn score(matrix, cache) { + use <- memo.memoize(cache, matrix) + { + use col <- list.map(matrix) + list.index_map(list.reverse(col), fn(i, c) { #(i + 1, c) }) + |> list.fold( + 0, + fn(acc, tup) { + case tup { + #(n, "O") -> acc + n + _ -> acc + } + }, + ) + } + |> int.sum +} + +pub fn part1(input: String) { + use cache: Cache(List(List(String)), Int) <- memo.create() + input + |> parse + |> list.map(roll_boulders) + |> score(cache) + |> string.inspect +} + +fn rotate(matrix) { + matrix + |> list.map(list.reverse) + |> list.transpose +} + +fn spin_the_board(matrix, cache) { + use <- memo.memoize(cache, matrix) + matrix + |> list.map(roll_boulders) + |> rotate +} + +pub fn part2(input: String) { + use cache: Cache(List(List(String)), List(List(String))) <- memo.create() + use score_cache: Cache(List(List(String)), Int) <- memo.create() + input + |> parse + |> iterator.iterate(spin_the_board(_, cache)) + |> iterator.map(score(_, score_cache)) + |> iterator.at(10000) + |> string.inspect +} + +pub fn main() { + let assert Ok(part) = adglent.get_part() + let assert Ok(input) = adglent.get_input("14") + case part { + First -> + part1(input) + |> adglent.inspect + |> io.println + Second -> + part2(input) + |> adglent.inspect + |> io.println + } +} diff --git a/aoc2023/src/utilities/memo.gleam b/aoc2023/src/utilities/memo.gleam index 87ee475..b06d8fd 100644 --- a/aoc2023/src/utilities/memo.gleam +++ b/aoc2023/src/utilities/memo.gleam @@ -14,6 +14,10 @@ type Message(k, v) { type Server(k, v) = Subject(Message(k, v)) +pub opaque type Cache(k, v) { + Cache(server: Server(k, v)) +} + fn handle_message( message: Message(k, v), dict: Dict(k, v), @@ -28,10 +32,6 @@ fn handle_message( } } -pub opaque type Cache(k, v) { - Cache(server: Server(k, v)) -} - pub fn create(apply fun: fn(Cache(k, v)) -> t) -> t { let assert Ok(server) = actor.start(dict.new(), handle_message) let result = fun(Cache(server)) diff --git a/aoc2023/test/day14/day14_test.gleam b/aoc2023/test/day14/day14_test.gleam new file mode 100644 index 0000000..8efa74e --- /dev/null +++ b/aoc2023/test/day14/day14_test.gleam @@ -0,0 +1,66 @@ +import gleam/list +import showtime/tests/should +import adglent.{type Example, Example} +import day14/solve + +type Problem1AnswerType = + String + +type Problem2AnswerType = + String + +/// Add examples for part 1 here: +/// ```gleam +///const part1_examples: List(Example(Problem1AnswerType)) = [Example("some input", "")] +/// ``` +const part1_examples: List(Example(Problem1AnswerType)) = [ + Example( + "O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#....", + "136", + ), +] + +/// Add examples for part 2 here: +/// ```gleam +///const part2_examples: List(Example(Problem2AnswerType)) = [Example("some input", "")] +/// ``` +const part2_examples: List(Example(Problem2AnswerType)) = [ + Example( + "O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#....", + "64", + ), +] + +pub fn part1_test() { + part1_examples + |> should.not_equal([]) + use example <- list.map(part1_examples) + solve.part1(example.input) + |> should.equal(example.answer) +} + +pub fn part2_test() { + part2_examples + |> should.not_equal([]) + use example <- list.map(part2_examples) + solve.part2(example.input) + |> should.equal(example.answer) +} |