Day 09
Mix.install([:kino_aoc, :image])
Setup
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2025", "9", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
tiles =
puzzle_input
|> String.split()
|> Enum.map(fn raw ->
raw
|> String.split(",")
|> Enum.map(&String.to_integer/1)
|> List.to_tuple()
end)
Implementation
defmodule Combinatorics do
def combinations2(list) do
Stream.unfold(list, fn
[] -> nil
[x | rest] ->
curr = for y <- rest, do: [x, y]
{curr, rest}
end)
|> Stream.flat_map(& &1)
end
end
defmodule Rect do
require Record
Record.defrecordp(:rect, l: 0, t: 0, r: 0, b: 0)
def new({ax, ay}, {bx, by}) do
rect(l: min(ax, bx), r: max(ax, bx), t: min(ay, by), b: max(ay, by))
end
def area(rect() = r) do
width(r) * height(r)
end
def intersect?(
rect(l: al, r: ar, t: at, b: ab),
rect(l: bl, r: br, t: bt, b: bb)
) do
al < br and ar > bl and at < bb and ab > bt
end
def width(rect(r: r, l: l)), do: r - l + 1
def height(rect(t: t, b: b)), do: b - t + 1
def to_svg(rect(l: x, t: y) = r, opts \\ []) do
~s"""
~s(#{k}="#{v}") end)} />
"""
end
end
rects =
Combinatorics.combinations2(tiles)
|> Stream.map(fn [a, b] -> Rect.new(a, b) end)
|> Enum.sort()
Part 1
rects
|> Enum.max_by(&Rect.area/1)
|> IO.inspect()
|> Rect.area()
Part 2
edges =
tiles
|> Enum.chunk_every(2, 1, tiles)
|> Enum.map(&apply(Rect, :new, &1))
|> Enum.sort()
# [{1916, 50285}, {94619, 50285}, {94619, 48466}, {1668, 48466}]
# |> Stream.flat_map(fn a ->
# for b <- tiles do
# Rect.new(a, b)
# end
# end)
rects
|> Enum.reduce({0, nil}, fn r, {max, p} ->
a = Rect.area(r)
if a > max and not Enum.any?(edges, &Rect.intersect?(r, &1)) do
{a, r}
else
{max, p}
end
end)
Draw
{{min_x, _}, {max_x, _}} = Enum.min_max(tiles)
{{_, min_y}, {_, max_y}} = Enum.min_max_by(tiles, &elem(&1, 1))
h = max_y + min_y
w = max_x + min_x
{x, y} = hd(tiles)
p1 = {:rect, 16055, 14805, 85282, 83613}
p2 = {:rect, 5741, 50285, 94619, 67351}
svg = """
#{Rect.to_svg(p1, stroke: :orange, fill: :transparent, "stroke-width": 200)}
#{Rect.to_svg(p2, stroke: :yellow, fill: :transparent, "stroke-width": 200)}
#{
for {x, y} <- tiles do
~s()
end
}
"""
Kino.Image.new(svg, :svg)