Day 7
Setup
input = Aoc.get_input(7)
textarea = Kino.Input.textarea("Puzzle input", default: input)
test_textarea = Kino.Input.textarea("Test input")
options = [
puzzle: "Puzzle",
test: "Test"
]
select = Kino.Input.select("Input source", options)
lines =
select
|> Kino.Input.read()
|> case do
:puzzle -> input
:test -> test_textarea |> Kino.Input.read()
end
|> String.trim()
|> String.split(",", trim: true)
|> Enum.map(&String.to_integer/1)
Part 1
max = lines |> Enum.max() |> IO.inspect(label: "max")
min = lines |> Enum.min() |> IO.inspect(label: "min")
calc = fn lines, n -> {n, lines |> Enum.map(fn x -> abs(n - x) end) |> Enum.sum()} end
min..max
|> Enum.map(fn i -> calc.(lines, i) end)
|> Enum.min_by(&elem(&1, 1))
|> elem(1)
Part 2
max = lines |> Enum.max() |> IO.inspect(label: "max")
min = lines |> Enum.min() |> IO.inspect(label: "min")
costs =
0..max
|> Enum.reduce(%{}, fn n, acc ->
prev = Map.get(acc, n - 1, 0)
Map.put(acc, n, prev + n)
end)
calc = fn lines, n ->
{n, lines |> Enum.map(fn x -> Map.get(costs, abs(n - x)) end) |> Enum.sum()}
end
min..max
|> Enum.map(fn i -> calc.(lines, i) end)
|> Enum.min_by(&elem(&1, 1))
|> elem(1)
Part 2 binary search
max = lines |> Enum.max() |> IO.inspect(label: "max")
min = lines |> Enum.min() |> IO.inspect(label: "min")
costs =
0..max
|> Enum.reduce(%{}, fn n, acc ->
prev = Map.get(acc, n - 1, 0)
Map.put(acc, n, prev + n)
end)
calc = fn lines, n ->
{n, lines |> Enum.map(fn x -> Map.get(costs, abs(n - x)) end) |> Enum.sum()}
end
left = calc.(lines, min)
right = calc.(lines, max)
Stream.iterate(0, &(&1 + 1))
|> Enum.reduce_while([left, right], fn _, [{l, _lc}, {r, _rc}] = acc ->
min = Enum.min_by(acc, &elem(&1, 1))
case div(r - l, 2) do
0 ->
{:halt, min}
half ->
mid_index = l + half
mid = calc.(lines, mid_index)
{:cont, [min, mid] |> Enum.sort_by(&elem(&1, 0))}
end
end)
|> elem(1)