1
0
Fork 0
advent-of-code/2021/lib/2021/3.ex
2022-09-21 09:19:53 -04:00

115 lines
2.8 KiB
Elixir

import AOC
aoc 2021, 3 do
def p1 do
sums =
input_stream()
|> Stream.map(fn w ->
String.split(w, "", trim: true)
|> Enum.map(&if &1 == "0", do: "-1", else: &1)
|> Enum.map(&String.to_integer/1)
end)
|> Enum.to_list()
|> Nx.tensor(type: {:s, 8})
|> Nx.sum(axes: [0])
|> Nx.to_flat_list()
for digit <- sums, reduce: {"", ""} do
{gamma, epsilon} ->
if digit > 0 do
{gamma <> "1", epsilon <> "0"}
else
{gamma <> "0", epsilon <> "1"}
end
end
|> then(fn {gamma, epsilon} ->
String.to_integer(gamma, 2) * String.to_integer(epsilon, 2)
end)
end
def p1_ do
[first] = Stream.take(input_stream(), 1) |> Enum.to_list()
bit_length = String.length(first)
tallies = :atomics.new(bit_length, [])
Stream.concat([first], input_stream())
|> Stream.each(fn value ->
for {v, i} <- Enum.with_index(String.split(value, "", trim: true), 1) do
:atomics.add(tallies, i, String.to_integer(v))
end
end)
|> Stream.run()
gamma_str =
for b <- 1..bit_length, into: "" do
if :atomics.get(tallies, b) > 500 do
"1"
else
"0"
end
end
epsilon_str =
for b <- String.split(gamma_str, "", trim: true), into: "" do
if b == "1", do: "0", else: "1"
end
gamma = String.to_integer(gamma_str, 2)
epsilon = String.to_integer(epsilon_str, 2)
gamma * epsilon
end
def p2 do
input_list =
input_stream()
|> Enum.map(fn word ->
String.split(word, "", trim: true) |> Enum.map(&String.to_integer/1)
end)
word_size = input_list |> hd() |> length()
[o2_gen_rating] =
Enum.reduce(0..word_size, input_list, fn
_bit, [value] ->
[value]
bit_index, list ->
total_values = length(list)
bit_sum =
for word <- list, reduce: 0 do
acc -> acc + Enum.at(word, bit_index)
end
matching_bit = if bit_sum >= total_values / 2, do: 1, else: 0
Enum.filter(list, fn word -> Enum.at(word, bit_index) == matching_bit end)
end)
o2_gen_rating = Enum.join(o2_gen_rating) |> String.to_integer(2)
[co2_scrub_rating] =
Enum.reduce(0..word_size, input_list, fn
_bit, [value] ->
[value]
bit_index, list ->
total_values = length(list)
bit_sum =
for word <- list, reduce: 0 do
acc -> acc + Enum.at(word, bit_index)
end
matching_bit = if bit_sum >= total_values / 2, do: 0, else: 1
Enum.filter(list, fn word -> Enum.at(word, bit_index) == matching_bit end)
end)
co2_scrub_rating = Enum.join(co2_scrub_rating) |> String.to_integer(2)
o2_gen_rating * co2_scrub_rating
end
end