List of binary numbers which, when decoded properly, can tell you many useful things about the conditions of the submarine.
defmodule Load do
def input do
File.read!("inputs/day03.txt")
|> String.split("\n", trim: true)
end
end
You need to use the binary numbers in the diagnostic report to generate two new binary numbers (called the gamma rate and the epsilon rate).
Each bit in the gamma rate can be determined by finding the most common bit in the corresponding position of all numbers in the diagnostic report.
defmodule Part1_gamma do
def gamma_rate() do
input = Load.input()
line_length = String.length(hd(input))
most_common_bit(input, line_length, 0, [])
end
defp most_common_bit(_data, position, position, result) do
result |> Enum.join() |> String.to_integer(2)
end
defp most_common_bit(data, length, position, result) do
bits =
Enum.map(data, fn line -> String.at(line, position) end)
|> Enum.frequencies()
{bit, _} = Enum.max_by(bits, fn {_bit, count} -> count end)
most_common_bit(data, length, position + 1, result ++ [bit])
end
end
The least common bit from each position is used.
defmodule Part1_epsilon do
def epsilon_rate do
input = Load.input()
line_length = String.length(hd(input))
least_common_bit(input, line_length, 0, [])
end
defp least_common_bit(_data, position, position, result) do
result |> Enum.join() |> String.to_integer(2)
end
defp least_common_bit(data, length, position, result) do
bits =
Enum.map(data, fn line -> String.at(line, position) end)
|> Enum.frequencies()
{bit, _} = Enum.min_by(bits, fn {_bit, count} -> count end)
least_common_bit(data, length, position + 1, result ++ [bit])
end
end
Multiplying the gamma rate by the epsilon rate.
defmodule Part1_power_consumption do
def check do
Part1_gamma.gamma_rate() * Part1_epsilon.epsilon_rate()
end
end
Part1_power_consumption.check()
Life support rating can be determined by multiplying the oxygen generator rating by the CO2 scrubber rating.
defmodule Part2 do
def life_support_rating() do
input = Load.input() |> Enum.map(&String.codepoints/1)
find_rating(input, &oxygen_generator_criteria/1, "1", 0) *
find_rating(input, &co2_scrubber_criteria/1, "0", 0)
end
defp oxygen_generator_criteria(values) do
{bit, _} = Enum.max_by(values, fn {_bit, count} -> count end)
bit
end
defp co2_scrubber_criteria(values) do
{bit, _} = Enum.min_by(values, fn {_bit, count} -> count end)
bit
end
defp find_rating([result], _criteria, _default_value, _position) do
result |> Enum.join() |> String.to_integer(2)
end
defp find_rating(data, criteria, default_value, position) do
values =
data
|> Enum.map(fn line -> Enum.at(line, position) end)
|> Enum.frequencies()
common =
cond do
values["0"] == values["1"] -> default_value
true -> criteria.(values)
end
new_data = Enum.filter(data, fn line -> Enum.at(line, position) == common end)
find_rating(new_data, criteria, default_value, position + 1)
end
end
Part2.life_support_rating()
ExUnit.start(autorun: false)
defmodule Test do
use ExUnit.Case, async: true
test "part1" do
assert Part1_power_consumption.check() == 738_234
end
test "part2" do
assert Part2.life_support_rating() == 3_969_126
end
end
ExUnit.run()