diff options
author | J.J <thechairman@thechairman.info> | 2024-05-30 21:49:58 -0400 |
---|---|---|
committer | J.J <thechairman@thechairman.info> | 2024-05-30 21:49:58 -0400 |
commit | 231c2b688d1e6cf0846d46e883da30e042a9c6cf (patch) | |
tree | 98a6d3a461fe190b38b2cf33a708a1d01703fa70 /aoc2023-gleam/src/day10 | |
parent | fe088aa5778dcdbaab4dd8d4a7395a91c444b45c (diff) | |
parent | a2c2b728ec6051323ed937f54816089cd2ae9d20 (diff) | |
download | gleam_aoc-231c2b688d1e6cf0846d46e883da30e042a9c6cf.tar.gz gleam_aoc-231c2b688d1e6cf0846d46e883da30e042a9c6cf.zip |
Merge branch 'main' of https://github.com/hunkyjimpjorps/AdventOfCode
Diffstat (limited to 'aoc2023-gleam/src/day10')
-rw-r--r-- | aoc2023-gleam/src/day10/.gitignore | 1 | ||||
-rw-r--r-- | aoc2023-gleam/src/day10/solve.gleam | 177 |
2 files changed, 178 insertions, 0 deletions
diff --git a/aoc2023-gleam/src/day10/.gitignore b/aoc2023-gleam/src/day10/.gitignore new file mode 100644 index 0000000..ae40cea --- /dev/null +++ b/aoc2023-gleam/src/day10/.gitignore @@ -0,0 +1 @@ +input.txt
\ No newline at end of file diff --git a/aoc2023-gleam/src/day10/solve.gleam b/aoc2023-gleam/src/day10/solve.gleam new file mode 100644 index 0000000..c33634d --- /dev/null +++ b/aoc2023-gleam/src/day10/solve.gleam @@ -0,0 +1,177 @@ +import adglent.{First, Second} +import gleam/bool +import gleam/dict.{type Dict} +import gleam/list +import gleam/int +import gleam/io +import gleam/set.{type Set} +import gleam/string + +type Posn { + Posn(row: Int, col: Int) +} + +fn add_posns(p1: Posn, p2: Posn) -> Posn { + Posn(p1.row + p2.row, p1.col + p2.col) +} + +type PipeGrid = + Dict(Posn, String) + +const north = Posn(-1, 0) + +const south = Posn(1, 0) + +const east = Posn(0, 1) + +const west = Posn(0, -1) + +const initial_directions = [ + #(north, ["|", "7", "F"]), + #(south, ["|", "J", "L"]), + #(east, ["-", "J", "7"]), + #(west, ["-", "F", "L"]), +] + +fn pipe_neighbors(pipe: String) -> List(Posn) { + case pipe { + "|" -> [north, south] + "-" -> [east, west] + "L" -> [north, east] + "F" -> [south, east] + "7" -> [south, west] + "J" -> [north, west] + _ -> panic as "bad pipe" + } +} + +fn make_grid(input: String) -> PipeGrid { + { + use r, row <- list.index_map(string.split(input, "\n")) + use c, col <- list.index_map(string.to_graphemes(row)) + #(Posn(r, c), col) + } + |> list.flatten + |> dict.from_list +} + +fn valid_start_direction(grid: PipeGrid, s: Posn) { + let assert [dir, ..] = { + use d <- list.filter_map(initial_directions) + let #(delta, valids) = d + let neighbor = add_posns(s, delta) + case dict.get(grid, neighbor) { + Ok(pipe) -> + case list.contains(valids, pipe) { + True -> Ok(neighbor) + False -> Error(Nil) + } + Error(_) -> Error(Nil) + } + } + dir +} + +fn to_next_pipe(current: Posn, grid: PipeGrid, acc: List(Posn)) { + let assert [prev, ..] = acc + let assert Ok(pipe) = dict.get(grid, current) + use <- bool.guard(pipe == "S", [current, ..acc]) + let assert [next] = { + pipe + |> pipe_neighbors + |> list.filter_map(fn(p) { + case add_posns(p, current) { + neighbor if neighbor == prev -> Error(Nil) + neighbor -> Ok(neighbor) + } + }) + } + to_next_pipe(next, grid, [current, ..acc]) +} + +pub fn part1(input: String) { + let grid = + input + |> make_grid + + let assert Ok(s) = + grid + |> dict.filter(fn(_, v) { v == "S" }) + |> dict.keys + |> list.first + + grid + |> valid_start_direction(s) + |> to_next_pipe(grid, [s]) + |> list.length + |> fn(i) { { { i - 1 } / 2 } } + |> string.inspect +} + +fn trace_ray(p: Posn, loop: Set(Posn), grid: PipeGrid) -> Bool { + use <- bool.guard(set.contains(loop, p), False) + int.is_odd(count_crossings(p, loop, grid, 0, "")) +} + +fn count_crossings( + p: Posn, + loop: Set(Posn), + grid: PipeGrid, + acc: Int, + corner: String, +) { + let maybe_cell = dict.get(grid, p) + use <- bool.guard(maybe_cell == Error(Nil), acc) + let assert Ok(cell) = maybe_cell + let next = add_posns(p, east) + case set.contains(loop, p) { + False -> count_crossings(next, loop, grid, acc, corner) + True -> + case corner, cell { + _, "|" -> count_crossings(next, loop, grid, acc + 1, corner) + _, "F" | _, "L" -> count_crossings(next, loop, grid, acc, cell) + "F", "J" | "L", "7" -> count_crossings(next, loop, grid, acc + 1, "") + "F", "7" | "L", "J" -> count_crossings(next, loop, grid, acc, "") + _, _ -> count_crossings(next, loop, grid, acc, corner) + } + } +} + +pub fn part2(input: String) { + let grid = + input + |> make_grid + + let assert Ok(s) = + grid + |> dict.filter(fn(_, v) { v == "S" }) + |> dict.keys + |> list.first + + let loop_pipes = + grid + |> valid_start_direction(s) + |> to_next_pipe(grid, [s]) + |> set.from_list + + grid + |> dict.keys + |> list.filter(trace_ray(_, loop_pipes, grid)) + |> list.length() + |> string.inspect +} + +pub fn main() { + let assert Ok(part) = adglent.get_part() + let assert Ok(input) = adglent.get_input("10") + case part { + First -> + part1(input) + |> adglent.inspect + |> io.println + Second -> + part2(input) + |> adglent.inspect + |> io.println + } +} |