From b0b4a3f040eca4fde0aaec77e9030ba2aa56141b Mon Sep 17 00:00:00 2001 From: Adam Millerchip Date: Fri, 2 Dec 2022 23:45:27 +0900 Subject: [PATCH] 2021 Day3 just for kicks. Lost my part 1 answer... --- 2021/day3.exs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 2021/day3.exs diff --git a/2021/day3.exs b/2021/day3.exs new file mode 100644 index 0000000..72700c5 --- /dev/null +++ b/2021/day3.exs @@ -0,0 +1,77 @@ +defmodule Day3 do + 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 * co2_scrubber_rating + end + + def find_rating([bits], _bits_seen, _mode) do + <> = bits + value + end + + def find_rating(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) + end + + def find_common(values, bits_seen, mode) do + {zeros, ones} = + values + |> Enum.map(fn <<_::size(bits_seen), bit::1, _rest::bits>> -> bit end) + |> Enum.reduce({_zeros = 0, _ones = 0}, fn + 0, {zeros, ones} -> {zeros + 1, ones} + 1, {zeros, ones} -> {zeros, ones + 1} + end) + + case mode do + :oxygen_generator -> if zeros <= ones, do: 1, else: 0 + :co2_scrubber -> if zeros <= ones, do: 0, else: 1 + end + end + + def filter_by_bit(values, num_prev_bits, bit) do + Enum.filter(values, &match?(<<_::size(num_prev_bits), ^bit::1, _rest::bits>>, &1)) + end + + def input do + with [input_filename] <- System.argv(), + {:ok, input} <- File.read(input_filename) do + strings = String.split(input, "\n", trim: true) + length = byte_size(hd(strings)) + Enum.map(strings, &<>) + else + _ -> :error + end + end + + ####################### + # HERE BE BOILERPLATE # + ####################### + + def run do + case input() do + :error -> print_usage() + input -> run_with_timer(fn -> part2(input) end) + end + end + + defp run_with_timer(fun) do + {time, result} = :timer.tc(fun) + IO.puts("Part 2 (completed in #{format_time(time)}):\n") + IO.puts("#{result}\n") + end + + defp format_time(μsec) when μsec < 1_000, do: "#{μsec}μs" + defp format_time(μsec) when μsec < 1_000_000, do: "#{μsec / 1000}ms" + defp format_time(μsec), do: "#{μsec / 1_000_000}s" + + defp print_usage do + IO.puts("Usage: elixir day3.exs input_filename") + end +end + +Day3.run()