Day 14: Extended Polymerization
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Setup
[polymer_template_input | pair_insertion_rule_input] =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
polymer_template = polymer_template_input |> String.graphemes()
pair_insertion_rules =
pair_insertion_rule_input
|> Enum.map(fn <> <> " -> " <> <> ->
[[e1, e2], e]
end)
{polymer_template, pair_insertion_rules}
Part 1
https://adventofcode.com/2021/day/14
Solve: Part 1
defmodule Day14.Part1 do
def run(polymer_template, step) do
do_run(polymer_template, step)
end
def answer(polymer) do
{{_, min_frequency}, {_, max_frequency}} =
polymer
|> Enum.frequencies()
|> Enum.min_max_by(fn {_e, frequency} -> frequency end)
max_frequency - min_frequency
end
defp do_run(polymer, _remain_step = 0) do
polymer
end
defp do_run(polymer, remain_step) do
new_polymer =
polymer
|> Enum.chunk_every(2, 1)
|> Enum.reduce([], fn
[e1, e2], new_polymer -> insert(e1, e2, new_polymer)
[e_last], new_polymer -> [e_last | new_polymer]
end)
|> Enum.reverse()
do_run(new_polymer, remain_step - 1)
end
pair_insertion_rules
|> Enum.map(fn [[e1, e2], e] ->
def insert(unquote(e1), unquote(e2), polymer) do
[unquote(e), unquote(e1) | polymer]
end
end)
end
Day14.Part1.run(polymer_template, 40)
|> Polymerizer.answer()
Part 2
https://adventofcode.com/2021/day/14#part2
Solve: Part 2
defmodule Day14.Part2 do
def run(polymer_template, step) do
pair_count_map =
polymer_template
|> Enum.chunk_every(2, 1, :discard)
|> Enum.frequencies()
do_run(pair_count_map, step)
end
def answer(polymer_template, pair_count_map) do
first_e = polymer_template |> List.first()
last_e = polymer_template |> List.last()
{{min_e, min_frequency}, {max_e, max_frequency}} =
pair_count_map
|> Enum.reduce(%{}, fn {[e1, e2], count}, frequncies ->
frequncies
|> Map.update(e1, count, &(&1 + count))
|> Map.update(e2, count, &(&1 + count))
end)
|> Enum.min_max_by(fn {_e, frequency} -> frequency end)
min_frequency =
case min_e in [first_e, last_e] do
true -> min_frequency + 1
false -> min_frequency
end
max_frequency =
case max_e in [first_e, last_e] do
true -> max_frequency + 1
false -> max_frequency
end
div(max_frequency - min_frequency, 2)
end
defp do_run(pair_count_map, _remain_step = 0) do
pair_count_map
end
defp do_run(pair_count_map, remain_step) do
new_pair_count_map =
pair_count_map
|> Enum.reduce(%{}, fn {[e1, e2], count}, new_pair_count_map ->
new_pair_count_map
|> insert_pairs([e1, e2], count)
end)
do_run(new_pair_count_map, remain_step - 1)
end
pair_insertion_rules
|> Enum.map(fn [[e1, e2], e] ->
def insert_pairs(pair_count_map, [unquote(e1), unquote(e2)], count) do
pair_count_map
|> Map.update([unquote(e1), unquote(e)], count, &(&1 + count))
|> Map.update([unquote(e), unquote(e2)], count, &(&1 + count))
end
end)
end
Day14.Part2.run(polymer_template, 40)
|> then(fn pair_count_map -> Day14.Part2.answer(polymer_template, pair_count_map) end)