diff --git a/src/advent_of_code.gleam b/src/advent_of_code.gleam index 84e7058..e63e6db 100644 --- a/src/advent_of_code.gleam +++ b/src/advent_of_code.gleam @@ -9,6 +9,7 @@ import historian_hysteria as day01 import mull_it_over as day03 import print_queue as day05 import red_nosed_reports as day02 +import resonant_collinearity as day08 import simplifile.{read} pub fn main() { @@ -110,6 +111,20 @@ pub fn main() { Nil, ) } + + ["8"] -> { + result.unwrap( + result.map(read("data/day8.txt"), fn(data) { + io.println( + "[8] Bridge Repair (Part 1): " <> int.to_string(day08.solve_a(data)), + ) + io.println( + "[8] Bridge Repair (Part 2): " <> int.to_string(day08.solve_b(data)), + ) + }), + Nil, + ) + } _ -> io.println_error("invalid arguments!") } } diff --git a/src/resonant_collinearity.gleam b/src/resonant_collinearity.gleam new file mode 100644 index 0000000..0f38d84 --- /dev/null +++ b/src/resonant_collinearity.gleam @@ -0,0 +1,110 @@ +import gleam/dict.{type Dict} +import gleam/float +import gleam/int +import gleam/io +import gleam/list +import gleam/result +import gleam/string + +type Point = + #(Int, Int) + +type Grid = + Dict(Point, String) + +fn parse_column(line, y) { + use grid, char, x <- list.index_fold(line, dict.new()) + dict.insert(grid, #(x, y), char) +} + +fn square(input: Float) -> Float { + case float.power(input, 2.0) { + Ok(val) -> val + _ -> 0.0 + } +} + +fn find_collinears(point_a: Point, point_b: Point) -> List(Point) { + let #(x1, y1) = point_a + let #(x2, y2) = point_b + + let x1f = int.to_float(x1) + let y1f = int.to_float(y1) + let x2f = int.to_float(x2) + let y2f = int.to_float(y2) + + let assert Ok(distance) = + float.add( + square(float.subtract(x2f, x1f)), + square(float.subtract(y2f, y1f)), + ) + |> float.square_root + + let assert Ok(dx) = float.divide(float.subtract(x2f, x1f), distance) + let assert Ok(dy) = float.divide(float.subtract(y2f, y1f), distance) + + let x3f_forward = float.add(x2f, float.multiply(dx, distance)) + let y3f_forward = float.add(y2f, float.multiply(dy, distance)) + let x3f_reverse = float.subtract(x1f, float.multiply(dx, distance)) + let y3f_reverse = float.subtract(y1f, float.multiply(dy, distance)) + + let x3_forward = float.round(x3f_forward) + let y3_forward = float.round(y3f_forward) + + let x3_reverse = float.round(x3f_reverse) + let y3_reverse = float.round(y3f_reverse) + + [#(x3_forward, y3_forward), #(x3_reverse, y3_reverse)] +} + +fn is_not_empty(cell: String) -> Bool { + case cell { + "." -> False + _ -> True + } +} + +fn find_antenna_locations(antenna: String, grid: Grid) -> List(Point) { + dict.keys(dict.filter(grid, fn(_, ant) { ant == antenna })) +} + +fn point_within_map(point: Point, g: Grid) -> Bool { + result.is_ok(list.find(dict.keys(g), fn(x) { x == point })) +} + +fn collinears_for_antenna(antenna: String, g: Grid) -> List(Point) { + find_antenna_locations(antenna, g) + |> list.combinations(2) + |> list.flat_map(fn(points) { + case points { + [l1, l2] -> find_collinears(l1, l2) + _ -> [] + } + }) + |> list.filter(point_within_map(_, g)) + |> list.unique +} + +fn parse_input(input: String) -> Grid { + input + |> string.trim() + |> string.split("\n") + |> list.map(string.to_graphemes) + |> list.index_map(parse_column) + |> list.reduce(dict.merge) + |> result.unwrap(dict.new()) +} + +pub fn solve_a(input: String) -> Int { + let grid = parse_input(input) + + list.filter(list.unique(dict.values(grid)), is_not_empty) + |> list.map(collinears_for_antenna(_, grid)) + |> list.flatten + |> list.unique + |> list.length +} + +pub fn solve_b(_inp: String) -> Int { + 0 +} diff --git a/test/resonant_collinearity_test.gleam b/test/resonant_collinearity_test.gleam new file mode 100644 index 0000000..9c73c27 --- /dev/null +++ b/test/resonant_collinearity_test.gleam @@ -0,0 +1,22 @@ +import gleam/string +import gleeunit/should +import resonant_collinearity as day08 + +fn test_data() -> String { + string.join( + [ + "............", "........0...", ".....0......", ".......0....", + "....0.......", "......A.....", "............", "............", + "........A...", ".........A..", "............", "............", + ], + "\n", + ) +} + +pub fn solve_a_test() { + should.equal(day08.solve_a(test_data()), 14) +} + +pub fn solve_b_test() { + should.equal(day08.solve_b(test_data()), 0) +}