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/src/day23/solve.gleam | |
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/src/day23/solve.gleam')
-rw-r--r-- | aoc2023/src/day23/solve.gleam | 194 |
1 files changed, 0 insertions, 194 deletions
diff --git a/aoc2023/src/day23/solve.gleam b/aoc2023/src/day23/solve.gleam deleted file mode 100644 index e1fe638..0000000 --- a/aoc2023/src/day23/solve.gleam +++ /dev/null @@ -1,194 +0,0 @@ -import adglent.{First, Second} -import gleam/int -import gleam/io -import gleam/dict.{type Dict} -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/string -import gleam/set.{type Set} -import gleam/bool -import utilities/array2d.{type Array2D, type Posn, Posn} - -type Path { - Unknown - Straight - Junction -} - -type Route { - Route(to: Posn, distance: Int) -} - -fn append_to_key(v: Option(List(a)), new: a) -> List(a) { - case v { - None -> [new] - Some(xs) -> [new, ..xs] - } -} - -fn first_parse_path(c: String) -> Result(Path, Nil) { - case c { - "#" -> Error(Nil) - _ -> Ok(Unknown) - } -} - -fn junction_neighbors(p: Posn) -> List(Posn) { - [Posn(..p, r: p.r + 1), Posn(..p, c: p.c + 1)] -} - -fn mark_junctions(trails: Array2D(Path)) -> Array2D(Path) { - use trail, _ <- dict.map_values(trails) - - let valid_neighbors = - trail - |> array2d.ortho_neighbors - |> list.filter(dict.has_key(trails, _)) - - case list.length(valid_neighbors) { - 2 -> Straight - _ -> Junction - } -} - -fn start_walking_to_next_junction( - start: Posn, - next: Posn, - trails: Array2D(Path), -) { - let seen = - set.new() - |> set.insert(start) - |> set.insert(next) - walk_to_next_junction(start, next, 1, seen, trails) -} - -fn walk_to_next_junction( - start: Posn, - current: Posn, - length: Int, - seen: Set(Posn), - trails: Array2D(Path), -) -> #(Posn, Route) { - let assert [next] = - current - |> array2d.ortho_neighbors - |> list.filter(fn(n) { dict.has_key(trails, n) && !set.contains(seen, n) }) - - case dict.get(trails, next) { - Ok(Junction) -> #(start, Route(to: next, distance: length + 1)) - _ -> { - let seen = set.insert(seen, current) - walk_to_next_junction(start, next, { length + 1 }, seen, trails) - } - } -} - -fn find_routes(junctions, trails) { - use junction <- list.flat_map(junctions) - use neighbor <- list.filter_map(junction_neighbors(junction)) - case dict.has_key(trails, neighbor) { - True -> Ok(start_walking_to_next_junction(junction, neighbor, trails)) - False -> Error(Nil) - } -} - -fn generate_routes( - junctions: List(Posn), - trails: Array2D(Path), -) -> Dict(Posn, List(Route)) { - use acc, #(from, route) <- list.fold( - find_routes(junctions, trails), - dict.new(), - ) - dict.update(acc, from, append_to_key(_, route)) -} - -fn generate_2way_routes( - junctions: List(Posn), - trails: Array2D(Path), -) -> Dict(Posn, List(Route)) { - use acc, #(from, route) <- list.fold( - find_routes(junctions, trails), - dict.new(), - ) - acc - |> dict.update(from, append_to_key(_, route)) - |> dict.update(route.to, append_to_key(_, Route(from, route.distance))) -} - -fn dfs(routes, from, to) { - let seen = set.insert(set.new(), from) - do_dfs(routes, from, to, 0, seen) -} - -fn do_dfs( - routes: Dict(Posn, List(Route)), - from: Posn, - to: Posn, - acc: Int, - seen: Set(Posn), -) -> Int { - use <- bool.guard(to == from, acc) - - let assert Ok(all_routes) = dict.get(routes, from) - let neighbors = list.filter(all_routes, fn(r) { !set.contains(seen, r.to) }) - - case neighbors { - [] -> 0 - neighbors -> - list.fold(neighbors, acc, fn(inner_acc, n) { - let score = - do_dfs(routes, n.to, to, acc + n.distance, set.insert(seen, n.to)) - int.max(score, inner_acc) - }) - } -} - -fn solve_using( - input: String, - using: fn(List(Posn), Dict(Posn, Path)) -> Dict(Posn, List(Route)), -) -> Int { - let min_row = 0 - let max_row = list.length(string.split(input, "\n")) - 1 - - let trails = - input - |> array2d.parse_grid_using(first_parse_path) - |> mark_junctions - - let junctions = - trails - |> dict.filter(fn(_, v) { v == Junction }) - |> dict.keys - - let assert Ok(start) = list.find(junctions, fn(j) { j.r == min_row }) - let assert Ok(end) = list.find(junctions, fn(j) { j.r == max_row }) - - let routes = using(junctions, trails) - - dfs(routes, start, end) -} - -pub fn part1(input: String) { - solve_using(input, generate_routes) -} - -pub fn part2(input: String) { - solve_using(input, generate_2way_routes) -} - -pub fn main() { - let assert Ok(part) = adglent.get_part() - let assert Ok(input) = adglent.get_input("23") - case part { - First -> - part1(input) - |> adglent.inspect - |> io.println - Second -> - part2(input) - |> adglent.inspect - |> io.println - } -} |