diff --git a/2021/day3.exs b/2021/day3.exs index 72700c5..4c6ac10 100644 --- a/2021/day3.exs +++ b/2021/day3.exs @@ -1,24 +1,40 @@ defmodule Day3 do + def part1(input) do + gamma_rating = find_rating(input, 0, :most, <<>>) + epsillon_rating = find_rating(input, 0, :least, <<>>) + gamma_rating * epsillon_rating + end + + defp find_rating([value | _], _, _, bits) when bit_size(value) == bit_size(bits) do + <> = bits + rating + end + + defp find_rating(values, bits_seen, mode, acc) do + bit = find_common(values, bits_seen, mode) + find_rating(values, bits_seen + 1, mode, <>) + end + def part2(input) do - oxygen_generator_rating = find_rating(input, 0, :oxygen_generator) - co2_scrubber_rating = find_rating(input, 0, :co2_scrubber) + oxygen_generator_rating = find_rating2(input, 0, :most) + co2_scrubber_rating = find_rating2(input, 0, :least) oxygen_generator_rating * co2_scrubber_rating end - def find_rating([bits], _bits_seen, _mode) do + defp find_rating2([bits], _bits_seen, _mode) do <> = bits value end - def find_rating(values, bits_seen, mode) do + defp find_rating2(values, bits_seen, mode) do bit = find_common(values, bits_seen, mode) values |> filter_by_bit(bits_seen, bit) - |> find_rating(bits_seen + 1, mode) + |> find_rating2(bits_seen + 1, mode) end - def find_common(values, bits_seen, mode) do + defp find_common(values, bits_seen, mode) do {zeros, ones} = values |> Enum.map(fn <<_::size(bits_seen), bit::1, _rest::bits>> -> bit end) @@ -28,12 +44,12 @@ defmodule Day3 do end) case mode do - :oxygen_generator -> if zeros <= ones, do: 1, else: 0 - :co2_scrubber -> if zeros <= ones, do: 0, else: 1 + :most -> if zeros <= ones, do: 1, else: 0 + :least -> if zeros <= ones, do: 0, else: 1 end end - def filter_by_bit(values, num_prev_bits, bit) do + defp filter_by_bit(values, num_prev_bits, bit) do Enum.filter(values, &match?(<<_::size(num_prev_bits), ^bit::1, _rest::bits>>, &1)) end @@ -55,13 +71,18 @@ defmodule Day3 do def run do case input() do :error -> print_usage() - input -> run_with_timer(fn -> part2(input) end) + input -> run_parts_with_timer(input) end end - defp run_with_timer(fun) do + defp run_parts_with_timer(input) do + run_with_timer(1, fn -> part1(input) end) + run_with_timer(2, fn -> part2(input) end) + end + + defp run_with_timer(part, fun) do {time, result} = :timer.tc(fun) - IO.puts("Part 2 (completed in #{format_time(time)}):\n") + IO.puts("Part #{part} (completed in #{format_time(time)}):\n") IO.puts("#{result}\n") end @@ -70,7 +91,7 @@ defmodule Day3 do defp format_time(μsec), do: "#{μsec / 1_000_000}s" defp print_usage do - IO.puts("Usage: elixir day3.exs input_filename") + IO.puts("Usage: elixir dayREPLACE_ME.exs input_filename") end end