Advent of Code 2021 - Day 3
Utils
defmodule Utils do
def read_textarea(name) do
Stream.iterate("", fn _ -> IO.gets(name) end)
|> Stream.take_while(&(&1 != :eof))
|> Enum.join("\r\n")
end
end
{:module, Utils, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:read_textarea, 1}}
Part 1
defmodule Day3 do
def solve(input) do
bit_frequencies =
input
|> String.split(~r{\s}, trim: true)
|> Enum.map(&String.to_charlist/1)
|> Enum.zip()
|> Enum.map(&Tuple.to_list/1)
|> Enum.map(&Enum.frequencies/1)
gamma_rate =
bit_frequencies
|> Enum.map(&Enum.max_by(&1, fn {_bit, count} -> count end))
|> Enum.map(fn {bit, _count} -> bit end)
|> to_string()
|> String.to_integer(2)
epsilon_rate =
bit_frequencies
# same as gamma_rate, but -count instead of count
|> Enum.map(&Enum.max_by(&1, fn {_bit, count} -> -count end))
|> Enum.map(fn {bit, _count} -> bit end)
|> to_string()
|> String.to_integer(2)
gamma_rate * epsilon_rate
end
end
Day3.solve(Utils.read_textarea("example_input"))
Day3.solve(Utils.read_textarea("my_input"))
1131506
defmodule Diagnostics do
def power_consumption(report) do
bit_frequencies =
report
|> to_bitlists()
|> to_bit_frequencies()
gamma_rate = gamma_rate(bit_frequencies)
epsilon_rate = epsilon_rate(bit_frequencies)
gamma_rate * epsilon_rate
end
def gamma_rate(bit_frequencies) do
picker_fn = fn freq0, freq1 ->
if freq0 > freq1, do: ?0, else: ?1
end
rate(bit_frequencies, picker_fn)
end
def epsilon_rate(bit_frequencies) do
picker_fn = fn freq0, freq1 ->
if freq0 < freq1, do: ?0, else: ?1
end
rate(bit_frequencies, picker_fn)
end
defp rate(bit_frequencies, picker_fn) do
bit_frequencies
|> Enum.map(fn freqs ->
freq0 = Map.get(freqs, ?0, 0)
freq1 = Map.get(freqs, ?1, 0)
picker_fn.(freq0, freq1)
end)
|> to_string()
|> String.to_integer(2)
end
def to_bitlists(report) do
report
|> String.split(~r{\s}, trim: true)
|> Enum.map(&String.to_charlist/1)
end
defp to_bit_frequencies(bitlists) do
bitlists
|> Enum.zip()
|> Enum.map(&Tuple.to_list/1)
|> Enum.map(&Enum.frequencies/1)
end
end
Diagnostics.power_consumption(Utils.read_textarea("example_input"))
Diagnostics.power_consumption(Utils.read_textarea("my_input"))
1131506
Part2
defmodule Diagnostics.Part2 do
def life_support_rating(report) do
bitlists = Diagnostics.to_bitlists(report)
oxygen_generator_rating = oxygen_generator_rating(bitlists)
co2_scrubber_rating = co2_scrubber_rating(bitlists)
oxygen_generator_rating * co2_scrubber_rating
end
def oxygen_generator_rating(bitlists) do
filter_fn = fn bit, freq0, freq1 ->
if bit == ?1 do
freq1 >= freq0
else
freq0 > freq1
end
end
rating(bitlists, filter_fn, 0)
end
def co2_scrubber_rating(bitlists) do
filter_fn = fn bit, freq0, freq1 ->
if bit == ?0 do
freq0 <= freq1
else
freq1 < freq0
end
end
rating(bitlists, filter_fn, 0)
end
defp rating([bitlist], _filter_fn, _pos) do
bitlist
|> to_string()
|> String.to_integer(2)
end
defp rating(bitlists, filter_fn, pos) do
# calculate frequencies of 0 & 1 at this position
freqs =
bitlists
|> Enum.map(&Enum.at(&1, pos))
|> Enum.frequencies()
freq0 = Map.get(freqs, ?0, 0)
freq1 = Map.get(freqs, ?1, 0)
new_bitlists =
bitlists
|> Enum.filter(fn bitlist ->
bit = Enum.at(bitlist, pos)
filter_fn.(bit, freq0, freq1)
end)
rating(new_bitlists, filter_fn, pos + 1)
end
end
Diagnostics.Part2.life_support_rating(Utils.read_textarea("example_input"))
Diagnostics.Part2.life_support_rating(Utils.read_textarea("my_input"))
7863147