aboutsummaryrefslogtreecommitdiff
path: root/aoc2023-gleam/src/day10
diff options
context:
space:
mode:
authorJ.J <thechairman@thechairman.info>2024-05-30 21:49:58 -0400
committerJ.J <thechairman@thechairman.info>2024-05-30 21:49:58 -0400
commit231c2b688d1e6cf0846d46e883da30e042a9c6cf (patch)
tree98a6d3a461fe190b38b2cf33a708a1d01703fa70 /aoc2023-gleam/src/day10
parentfe088aa5778dcdbaab4dd8d4a7395a91c444b45c (diff)
parenta2c2b728ec6051323ed937f54816089cd2ae9d20 (diff)
downloadgleam_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/.gitignore1
-rw-r--r--aoc2023-gleam/src/day10/solve.gleam177
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
+ }
+}