aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/src/day10
diff options
context:
space:
mode:
authorHJ <thechairman@thechairman.info>2023-12-10 10:30:01 -0500
committerHJ <thechairman@thechairman.info>2023-12-10 10:30:01 -0500
commit0223d8e8e374e6f1e3af2e0be93229b549489fcc (patch)
treeccf1535af18347ae98e2a13248cd59ed4763cb05 /aoc2023/src/day10
parentb7817b4c9680ec2fdc021b17a8d3f4fbee2929d5 (diff)
downloadgleam_aoc-0223d8e8e374e6f1e3af2e0be93229b549489fcc.tar.gz
gleam_aoc-0223d8e8e374e6f1e3af2e0be93229b549489fcc.zip
day 10 gleam complete
Diffstat (limited to 'aoc2023/src/day10')
-rw-r--r--aoc2023/src/day10/solve.gleam156
1 files changed, 154 insertions, 2 deletions
diff --git a/aoc2023/src/day10/solve.gleam b/aoc2023/src/day10/solve.gleam
index 43dba6d..c33634d 100644
--- a/aoc2023/src/day10/solve.gleam
+++ b/aoc2023/src/day10/solve.gleam
@@ -1,12 +1,164 @@
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) {
- todo as "Implement solution to part 1"
+ 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) {
- todo as "Implement solution to part 2"
+ 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() {