diff --git a/src/gloat.gleam b/src/gloat.gleam index cf123dd..16f1ce1 100644 --- a/src/gloat.gleam +++ b/src/gloat.gleam @@ -12,6 +12,7 @@ import solve_2025_04 import solve_2025_05 import solve_2025_06 import solve_2025_07 +import solve_2025_08 pub fn main() -> Nil { case argv.load().arguments { @@ -34,6 +35,8 @@ pub fn main() -> Nil { display(#(2025, 6), solve_2025_06.part_one, solve_2025_06.part_two) ["2025", "7"] -> display(#(2025, 7), solve_2025_07.part_one, solve_2025_07.part_two) + ["2025", "8"] -> + display(#(2025, 8), solve_2025_08.part_one, solve_2025_08.part_two) ["2025", _] -> io.print("No solutions for 2025") _ -> io.print("Please provide the following arguments: ") } diff --git a/src/solve_2025_08.gleam b/src/solve_2025_08.gleam new file mode 100644 index 0000000..b8ad517 --- /dev/null +++ b/src/solve_2025_08.gleam @@ -0,0 +1,110 @@ +import gleam/float +import gleam/int +import gleam/list +import gleam/pair +import gleam/result +import gleam/set +import gleam/string + +type Point { + Point(x: Int, y: Int, z: Int) +} + +type Connection { + Connection(a: Point, b: Point, distance: Int) +} + +fn distance(a: Point, b: Point) { + 0.0 + +. { int.power(a.x - b.x, 2.0) |> result.unwrap(0.0) } + +. { int.power(a.y - b.y, 2.0) |> result.unwrap(0.0) } + +. { int.power(a.z - b.z, 2.0) |> result.unwrap(0.0) } + |> float.power(0.5) + |> result.unwrap(-1.0) +} + +fn with_distance(pair: #(Point, Point)) { + let #(a, b) = pair + let distance = float.truncate(distance(a, b)) + Connection(a:, b:, distance:) +} + +fn compare(a: Connection, b: Connection) { + int.compare(a.distance, b.distance) +} + +pub fn part_one(input: String) -> Int { + let length = case string.length(input) < 300 { + True -> 10 + False -> 1000 + } + + input + |> parse + |> list.combination_pairs + |> list.map(with_distance) + |> list.sort(compare) + |> list.take(length) + |> list.fold([], fn(circuits: List(set.Set(Point)), connection) { + let Connection(a:, b:, ..) = connection + // echo #(a, b, triplet.2, circuits) + let #(overlapping, disjoint) = + circuits + |> list.partition(fn(set) { set.contains(set, a) || set.contains(set, b) }) + + let connection = set.new() |> set.insert(a) |> set.insert(b) + + // echo #(list.length(overlapping), list.length(disjoint)) + [ + overlapping + |> list.fold(connection, set.union), + ..disjoint + ] + }) + // |> echo + |> list.map(set.size) + |> list.sort(int.compare) + |> list.reverse + |> list.take(3) + |> int.product +} + +pub fn part_two(input: String) -> Int { + let points = + input + |> parse + + let size = list.length(points) + + input + |> parse + |> list.combination_pairs + |> list.map(with_distance) + |> list.sort(compare) + |> list.fold_until(#([], -1), fn(accumulator, connection) { + let #(circuits, _) = accumulator + let Connection(a:, b:, ..) = connection + let #(overlapping, disjoint) = + circuits + |> list.partition(fn(set) { set.contains(set, a) || set.contains(set, b) }) + + let connection = set.new() |> set.insert(a) |> set.insert(b) + let joined = + overlapping + |> list.fold(connection, set.union) + + case set.size(joined) == size { + True -> list.Stop(#([], int.multiply(a.x, b.x))) + False -> list.Continue(#([joined, ..disjoint], -1)) + } + }) + |> pair.second +} + +fn parse(input: String) -> List(Point) { + use line <- list.flat_map(string.split(input, "\n")) + case line |> string.split(",") |> list.map(int.parse) { + [Ok(x), Ok(y), Ok(z)] -> [Point(x:, y:, z:)] + _ -> [] + } +} diff --git a/test/test_2025_08.gleam b/test/test_2025_08.gleam new file mode 100644 index 0000000..e0d1bcb --- /dev/null +++ b/test/test_2025_08.gleam @@ -0,0 +1,41 @@ +import gleam/string +import solve_2025_08 + +const input = " +162,817,812 +57,618,57 +906,360,560 +592,479,940 +352,342,300 +466,668,158 +542,29,236 +431,825,988 +739,650,466 +52,470,668 +216,146,977 +819,987,18 +117,168,530 +805,96,715 +346,949,466 +970,615,88 +941,993,340 +862,61,35 +984,92,344 +425,690,689 +" + +pub fn part_one_test() { + let result = + input + |> string.trim + |> solve_2025_08.part_one + assert result == 40 +} + +pub fn part_two_test() { + let result = + input + |> string.trim + |> solve_2025_08.part_two + assert result == 25_272 +}