aoc2024/src/day08_p2.gleam

109 lines
2.3 KiB
Gleam
Raw Normal View History

2024-12-08 11:09:44 +00:00
import gleam/dict.{type Dict}
import gleam/io
import gleam/iterator.{Done, Next}
import gleam/list.{filter, fold, map}
import gleam/pair
import gleam/result
import gleam/string
import stdin.{stdin}
pub fn main() {
stdin()
|> read_input
|> calculate_resonance
|> io.debug
}
fn calculate_resonance(chart: Map) -> Int {
let Map(w, h, antennas) = chart
antennas
|> dict.fold([], fn(acc, _, coords) {
let antinodes =
coords
|> ordered_combinations
|> map(fn(coord) {
let #(dx, dy) = resolve_antinode_frequency(coord)
// Spawn antinodes until out ot bounds
coord
|> pair.first
|> iterator.unfold(fn(pos) {
let #(x, y) = pos
let newpos = #(x + dx, y + dy)
case newpos {
#(tx, ty) if tx < 0 || tx >= w || ty < 0 || ty >= h -> Done
_ -> Next(newpos, newpos)
}
})
|> iterator.to_list
})
|> list.flatten
[coords, antinodes, acc] |> list.flatten
})
|> list.unique
|> list.length
}
fn resolve_antinode_frequency(
coords: #(#(Int, Int), #(Int, Int)),
) -> #(Int, Int) {
let #(#(ax, ay), #(bx, by)) = coords
#(ax - bx, ay - by)
}
fn ordered_combinations(items: List(a)) -> List(#(a, a)) {
items
|> list.combination_pairs
|> map(fn(x) { [x, pair.swap(x)] })
|> list.flatten
}
pub type Map {
Map(width: Int, height: Int, antennas: Dict(String, List(#(Int, Int))))
}
fn read_input(it: iterator.Iterator(String)) -> Map {
let maptxt =
it
|> iterator.to_list
|> map(string.trim)
|> filter(not(string.is_empty))
let assert Ok(width) = list.first(maptxt) |> result.map(string.length)
let height = list.length(maptxt)
let antennas =
maptxt
|> list.index_fold([], find_antennas)
|> fold(dict.new(), fn(acc, v) {
let #(group, coord) = v
let current =
acc
|> dict.get(group)
|> result.unwrap([])
dict.insert(acc, group, [coord, ..current])
})
Map(width, height, antennas)
}
fn find_antennas(
acc: List(#(String, #(Int, Int))),
line: String,
y: Int,
) -> List(#(String, #(Int, Int))) {
line
|> string.to_graphemes
|> list.index_fold(acc, fn(cur, chr, x) {
case chr {
"." -> cur
c -> [#(c, #(x, y)), ..cur]
}
})
}
fn not(a: fn(a) -> Bool) {
fn(param: a) -> Bool { !a(param) }
}