Skip to content

Commit

Permalink
day 08: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
sreedevk committed Dec 8, 2024
1 parent 8b05f58 commit b8bf6d5
Showing 1 changed file with 39 additions and 85 deletions.
124 changes: 39 additions & 85 deletions src/resonant_collinearity.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import gleam/result
import gleam/string

type Point =
#(Int, Int)
#(Float, Float)

type Grid =
Dict(Point, String)
Expand All @@ -18,7 +18,7 @@ type Direction {

fn parse_column(line, y) {
use grid, char, x <- list.index_fold(line, dict.new())
dict.insert(grid, #(x, y), char)
dict.insert(grid, #(int.to_float(x), int.to_float(y)), char)
}

fn square(input: Float) -> Float {
Expand All @@ -35,110 +35,76 @@ fn find_collinear_vector(
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.add(square(float.subtract(x2, x1)), square(float.subtract(y2, y1)))
|> 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 assert Ok(dx) = float.divide(float.subtract(x2, x1), distance)
let assert Ok(dy) = float.divide(float.subtract(y2, y1), distance)

#(distance, #(dx, dy))
}

fn find_collinear_in_direction(
point_a: Point,
point_b: Point,
points: List(Point),
direction: Direction,
) -> Point {
let assert [point_a, point_b] = points
let #(distance, #(dx, dy)) = find_collinear_vector(point_a, point_b)
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)

case direction {
Forward -> #(
float.round(float.add(x2f, float.multiply(dx, distance))),
float.round(float.add(y2f, float.multiply(dy, distance))),
float.ceiling(float.add(x2, float.multiply(dx, distance))),
float.ceiling(float.add(y2, float.multiply(dy, distance))),
)
Reverse -> #(
float.round(float.subtract(x1f, float.multiply(dx, distance))),
float.round(float.subtract(y1f, float.multiply(dy, distance))),
float.ceiling(float.subtract(x1, float.multiply(dx, distance))),
float.ceiling(float.subtract(y1, float.multiply(dy, distance))),
)
}
}

fn find_forward_harmonic_collinears(
found: List(Point),
grid: Grid,
) -> List(Point) {
let #(head, rest) = list.split(found, 2)
let assert [p1, p2] = head
let collinear_in_direction = find_collinear_in_direction(p1, p2, Forward)

case point_within_map(collinear_in_direction, grid) {
True ->
find_forward_harmonic_collinears(
list.append([p2, collinear_in_direction], list.append(rest, [p1])),
grid,
)
False -> found
}
}

fn find_reverse_harmonic_collinears(
fn find_harmonic_collinear_in_direction(
found: List(Point),
grid: Grid,
direction: Direction,
) -> List(Point) {
let #(head, rest) = list.split(found, 2)
let assert [p1, p2] = head
let collinear_in_direction = find_collinear_in_direction(p1, p2, Reverse)
let collinear_in_direction = find_collinear_in_direction(head, direction)

case point_within_map(collinear_in_direction, grid) {
True ->
find_reverse_harmonic_collinears(
list.append([collinear_in_direction, p1], list.append(rest, [p2])),
grid,
)
case direction {
Forward ->
find_harmonic_collinear_in_direction(
list.append([p2, collinear_in_direction], list.append(rest, [p1])),
grid,
direction,
)
Reverse ->
find_harmonic_collinear_in_direction(
list.append([collinear_in_direction, p1], list.append(rest, [p2])),
grid,
direction,
)
}
False -> found
}
}

fn find_all_harmonic_collinears(
point_a: Point,
point_b: Point,
grid: Grid,
) -> List(Point) {
fn find_all_harmonic_collinears(points: List(Point), grid: Grid) -> List(Point) {
list.append(
find_forward_harmonic_collinears([point_a, point_b], grid),
find_reverse_harmonic_collinears([point_a, point_b], grid),
find_harmonic_collinear_in_direction(points, grid, Forward),
find_harmonic_collinear_in_direction(points, grid, Reverse),
)
}

fn find_all_collinears(point_a: Point, point_b: Point) -> List(Point) {
[
find_collinear_in_direction(point_a, point_b, Forward),
find_collinear_in_direction(point_a, point_b, Reverse),
]
}

fn is_not_empty(cell: String) -> Bool {
case cell {
"." -> False
_ -> True
}
fn find_all_collinears(points: List(Point)) -> List(Point) {
list.wrap(find_collinear_in_direction(points, Forward))
|> list.append(list.wrap(find_collinear_in_direction(points, Reverse)))
}

fn find_antenna_locations(antenna: String, grid: Grid) -> List(Point) {
Expand All @@ -152,27 +118,16 @@ fn point_within_map(point: Point, g: Grid) -> Bool {
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_all_collinears(l1, l2)
_ -> []
}
})
|> list.flat_map(find_all_collinears)
|> list.filter(point_within_map(_, g))
|> list.unique
}

fn harmonic_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_all_harmonic_collinears(l1, l2, g)
_ -> []
}
})
|> list.flat_map(find_all_harmonic_collinears(_, g))
|> list.filter(point_within_map(_, g))
|> list.unique
}

fn parse_input(input: String) -> Grid {
Expand All @@ -181,14 +136,13 @@ fn parse_input(input: String) -> Grid {
|> string.split("\n")
|> list.map(string.to_graphemes)
|> list.index_map(parse_column)
|> list.reduce(dict.merge)
|> result.unwrap(dict.new())
|> list.fold(dict.new(), dict.merge)
}

pub fn solve_a(input: String) -> Int {
let grid = parse_input(input)

list.filter(list.unique(dict.values(grid)), is_not_empty)
list.filter(list.unique(dict.values(grid)), fn(x) { x != "." })
|> list.map(collinears_for_antenna(_, grid))
|> list.flatten
|> list.unique
Expand All @@ -198,7 +152,7 @@ pub fn solve_a(input: String) -> Int {
pub fn solve_b(input: String) -> Int {
let grid = parse_input(input)

list.filter(list.unique(dict.values(grid)), is_not_empty)
list.filter(list.unique(dict.values(grid)), fn(x) { x != "." })
|> list.map(harmonic_collinears_for_antenna(_, grid))
|> list.flatten
|> list.unique
Expand Down

0 comments on commit b8bf6d5

Please sign in to comment.