diff --git a/sample/day8-sample.txt b/sample/day8-sample.txt new file mode 100644 index 0000000..78a1e91 --- /dev/null +++ b/sample/day8-sample.txt @@ -0,0 +1,12 @@ +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ diff --git a/sample/day8-sample2.txt b/sample/day8-sample2.txt new file mode 100644 index 0000000..b8439c3 --- /dev/null +++ b/sample/day8-sample2.txt @@ -0,0 +1,10 @@ +T......... +...T...... +.T........ +.......... +.......... +.......... +.......... +.......... +.......... +.......... diff --git a/src/day8_p1.gleam b/src/day8_p1.gleam new file mode 100644 index 0000000..03aa03c --- /dev/null +++ b/src/day8_p1.gleam @@ -0,0 +1,96 @@ +import gleam/dict.{type Dict} +import gleam/io +import gleam/iterator +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(resolve_antinode) + + [antinodes, ..acc] + }) + |> list.flatten + |> list.unique + |> filter(fn(coord) { + let #(x, y) = coord + x >= 0 && x < w && y >= 0 && y < h + }) + |> list.length +} + +fn resolve_antinode(coords: #(#(Int, Int), #(Int, Int))) -> #(Int, Int) { + let #(#(ax, ay), #(bx, by)) = coords + + #(ax - { bx - ax }, ay - { by - ay }) +} + +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) } +} diff --git a/src/day8_p2.gleam b/src/day8_p2.gleam new file mode 100644 index 0000000..f7d402f --- /dev/null +++ b/src/day8_p2.gleam @@ -0,0 +1,108 @@ +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) } +}