diff options
Diffstat (limited to 'aoc2023/src/day3/solve.gleam')
-rw-r--r-- | aoc2023/src/day3/solve.gleam | 180 |
1 files changed, 0 insertions, 180 deletions
diff --git a/aoc2023/src/day3/solve.gleam b/aoc2023/src/day3/solve.gleam deleted file mode 100644 index ad975aa..0000000 --- a/aoc2023/src/day3/solve.gleam +++ /dev/null @@ -1,180 +0,0 @@ -import adglent.{First, Second} -import gleam/io -import gleam/dict.{type Dict} -import gleam/string -import gleam/list -import gleam/int -import gleam/order.{type Order, Eq} - -type Coord { - Coord(x: Int, y: Int) -} - -type SymbolKind { - Gear - SomethingElse -} - -type Symbol { - Number(Int) - Symbol(SymbolKind) - Empty -} - -type Board = - Dict(Coord, Symbol) - -type Cell { - Cell(coord: Coord, symbol: Symbol) -} - -type Part { - Part(coords: List(Coord), part_number: Int) -} - -fn to_symbol(c: String) -> Symbol { - case int.parse(c), c { - Ok(n), _ -> Number(n) - _, "." -> Empty - _, "*" -> Symbol(Gear) - _, _ -> Symbol(SomethingElse) - } -} - -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 cell_compare(a: Cell, b: Cell) -> Order { - case int.compare(a.coord.y, b.coord.y) { - Eq -> int.compare(a.coord.x, b.coord.x) - other -> other - } -} - -fn find_all_part_digits(b: Board) -> List(Cell) { - b - |> dict.filter(fn(_, v) { - case v { - Number(_) -> True - _ -> False - } - }) - |> dict.to_list() - |> list.map(fn(tup) { Cell(tup.0, tup.1) }) - |> list.sort(cell_compare) -} - -fn to_parts(cells: List(Cell)) -> List(Part) { - do_parts(cells, []) -} - -fn do_parts(cells: List(Cell), parts: List(Part)) -> List(Part) { - case cells { - [] -> parts - [Cell(next, Number(n)), ..t] -> { - case parts { - [] -> do_parts(t, [Part([next], n), ..parts]) - [Part([prev, ..] as coords, n0), ..rest_parts] -> - case { next.x - prev.x }, { next.y - prev.y } { - 1, 0 -> - do_parts(t, [Part([next, ..coords], n0 * 10 + n), ..rest_parts]) - _, _ -> do_parts(t, [Part([next], n), ..parts]) - } - _ -> panic - } - } - _ -> panic - } -} - -fn all_neighbors(c: Coord) -> List(Coord) { - 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(c.x + dx, c.y + dy)) - } -} - -fn sum_valid_parts(acc: Int, part: Part, board: Board) -> Int { - let neighbors = - part.coords - |> list.flat_map(all_neighbors) - |> list.unique() - - let sym = [Ok(Symbol(Gear)), Ok(Symbol(SomethingElse))] - case list.any(neighbors, fn(c) { list.contains(sym, dict.get(board, c)) }) { - True -> acc + part.part_number - False -> acc - } -} - -pub fn part1(input: String) -> Int { - let board = to_board(input) - - board - |> find_all_part_digits - |> to_parts - |> list.fold(0, fn(acc, p) { sum_valid_parts(acc, p, board) }) -} - -fn to_part_with_neighbors(part: Part) -> Part { - part.coords - |> list.flat_map(all_neighbors) - |> list.unique - |> Part(part.part_number) -} - -fn find_part_numbers_near_gear(gear: Coord, parts: List(Part)) -> List(Int) { - use part <- list.filter_map(parts) - case list.contains(part.coords, gear) { - True -> Ok(part.part_number) - False -> Error(Nil) - } -} - -fn to_sum_of_gear_ratios(adjacent_parts: List(List(Int))) -> Int { - use acc, ps <- list.fold(adjacent_parts, 0) - case ps { - [p1, p2] -> acc + p1 * p2 - _ -> acc - } -} - -pub fn part2(input: String) -> Int { - let board = to_board(input) - - let parts = - board - |> find_all_part_digits - |> to_parts - |> list.map(to_part_with_neighbors) - - board - |> dict.filter(fn(_, v) { v == Symbol(Gear) }) - |> dict.keys - |> list.map(find_part_numbers_near_gear(_, parts)) - |> to_sum_of_gear_ratios -} - -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 - } -} |