From 5108ae09e37ff6c71a9d791ef70897c4b6791c42 Mon Sep 17 00:00:00 2001 From: HJ Date: Sun, 3 Dec 2023 01:59:44 -0500 Subject: day 3 complete --- aoc2023/src/day3/solve.gleam | 192 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 aoc2023/src/day3/solve.gleam (limited to 'aoc2023/src/day3/solve.gleam') diff --git a/aoc2023/src/day3/solve.gleam b/aoc2023/src/day3/solve.gleam new file mode 100644 index 0000000..5df337d --- /dev/null +++ b/aoc2023/src/day3/solve.gleam @@ -0,0 +1,192 @@ +import adglent.{First, Second} +import gleam/io +import gleam/dict.{type Dict} +import gleam/string +import gleam/list +import gleam/int +import gleam/order.{Eq} +import gleam/result + +type Coord { + Coord(x: Int, y: Int) +} + +type Symbol { + Number(Int) + Gear + OtherSymbol + Empty +} + +type Board = + Dict(Coord, Symbol) + +fn to_symbol(c: String) -> Symbol { + case int.parse(c), c { + Ok(n), _ -> Number(n) + Error(Nil), "." -> Empty + Error(Nil), "*" -> Gear + _, _ -> OtherSymbol + } +} + +fn to_board(input: String) -> Board { + { + use y, r <- list.index_map(string.split(input, "\n")) + use x, c <- list.index_map(string.to_graphemes(r)) + #(Coord(x, y), to_symbol(c)) + } + |> list.flatten() + |> dict.from_list() +} + +fn find_all_numbers(b: Board) { + b + |> dict.filter(fn(_, v) { + case v { + Number(_) -> True + _ -> False + } + }) + |> dict.to_list() + |> list.sort(fn(a, b) { + let #(Coord(x_a, y_a), _) = a + let #(Coord(x_b, y_b), _) = b + case int.compare(y_a, y_b) { + Eq -> int.compare(x_a, x_b) + other -> other + } + }) +} + +fn group_parts(ns, acc) { + case ns, acc { + [], _ -> acc + [#(Coord(x, y) as c, Number(n)), ..t], [ + #([Coord(x0, y0), ..] as cs, n0), + ..acc_rest + ] if y == y0 -> + case { x - 1 == x0 } { + True -> group_parts(t, [#([c, ..cs], n0 * 10 + n), ..acc_rest]) + False -> group_parts(t, [#([c], n), ..acc]) + } + [#(coord, Number(n)), ..t], _ -> group_parts(t, [#([coord], n), ..acc]) + } +} + +fn all_neighbors(c: Coord) -> List(Coord) { + let Coord(x, y) = c + use dx <- list.flat_map([-1, 0, 1]) + use dy <- list.filter_map([-1, 0, 1]) + case dx, dy { + 0, 0 -> Error(Nil) + _, _ -> Ok(Coord(x + dx, y + dy)) + } +} + +fn check_part_neighbors( + part: #(List(Coord), Int), + board: Board, +) -> Result(Int, Nil) { + let #(coords, n) = part + + let neighbors = + coords + |> list.flat_map(all_neighbors) + |> list.unique() + + case + list.any( + neighbors, + fn(c) { + let content = dict.get(board, c) + content == Ok(OtherSymbol) || content == Ok(Gear) + }, + ) + { + True -> Ok(n) + False -> Error(Nil) + } +} + +pub fn part1(input: String) { + let board = to_board(input) + + board + |> find_all_numbers + |> group_parts([]) + |> list.map(check_part_neighbors(_, board)) + |> result.values + |> int.sum +} + +fn find_gears(b: Board) { + dict.filter(b, fn(_, v) { v == Gear }) + |> dict.keys +} + +fn to_part_with_neighbors(part: #(List(Coord), Int)) { + let #(coords, n) = part + + let neighbors = + coords + |> list.flat_map(all_neighbors) + |> list.unique + |> list.filter(fn(c) { !list.contains(coords, c) }) + + #(neighbors, n) +} + +fn find_parts_near_gear(gear: Coord, parts: List(#(List(Coord), Int))) { + parts + |> list.filter_map(fn(part) { + let #(neighbors, n) = part + case list.contains(neighbors, gear) { + True -> Ok(n) + False -> Error(Nil) + } + }) +} + +fn keep_gears_near_two_parts(sets_of_parts: List(List(Int))) { + list.filter_map( + sets_of_parts, + fn(ps) { + case ps { + [p1, p2] -> Ok(p1 * p2) + _ -> Error(Nil) + } + }, + ) +} + +pub fn part2(input: String) { + let board = to_board(input) + + let parts = + board + |> find_all_numbers + |> group_parts([]) + |> list.map(to_part_with_neighbors) + + board + |> find_gears + |> list.map(find_parts_near_gear(_, parts)) + |> keep_gears_near_two_parts + |> int.sum +} + +pub fn main() { + let assert Ok(part) = adglent.get_part() + let assert Ok(input) = adglent.get_input("3") + case part { + First -> + part1(input) + |> adglent.inspect + |> io.println + Second -> + part2(input) + |> adglent.inspect + |> io.println + } +} -- cgit v1.2.3