Created
December 3, 2021 20:25
-
-
Save Insti/4b24f0a26dfef288eea2373732739804 to your computer and use it in GitHub Desktop.
Advent of code 2021 - Day 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require 'minitest/autorun' | |
require_relative 'input_data' | |
class InputData | |
@file = __FILE__ | |
def parse | |
raw_data.lines.map { |line| line.scan(/\d/) } | |
end | |
end | |
# This is horrible and confusing | |
def part_one(parsed) | |
freq = parsed.transpose.map { |row| row.group_by { |x| x }.transform_values(&:size).invert } | |
something = freq.map do |f| | |
f.minmax.map(&:last) | |
end.transpose.map { |v| v.join.to_i(2) }.reduce(:*) | |
end | |
def part_two(parsed) | |
oxygen_rating(parsed) * co2_scrubber_rating(parsed) | |
end | |
def oxygen_rating(parsed) | |
candidates = parsed.dup | |
guard = candidates.first.size | |
n = 0 | |
while candidates.size > 1 && guard | |
# Find the most common bit in position n | |
mcv = most_common_value(candidates, n, tiebreak: "1") | |
candidates.select! { |candidate| candidate[n] == mcv } | |
n += 1 | |
guard -= 1 | |
end | |
candidates.first.join.to_i(2) | |
end | |
def co2_scrubber_rating(parsed) | |
candidates = parsed.dup | |
guard = candidates.first.size | |
n = 0 | |
while candidates.size > 1 && guard | |
# Find the most common bit in position n | |
mcv = least_common_value(candidates, n) | |
candidates.select! { |candidate| candidate[n] == mcv } | |
n += 1 | |
guard -= 1 | |
end | |
candidates.first.join.to_i(2) | |
end | |
def most_common_value(parsed, position, tiebreak: "1") | |
ones = parsed.count { |row| row[position] == "1" } | |
zeros = parsed.size - ones | |
{ -1 => "0", 0 => tiebreak, 1 => "1"}[ones <=> zeros] | |
end | |
def least_common_value(parsed, position, tiebreak: "0") | |
ones = parsed.count { |row| row[position] == "1" } | |
zeros = parsed.size - ones | |
{ 1 => "0", 0 => tiebreak, -1 => "1"}[ones <=> zeros] | |
end | |
class TestDay < Minitest::Test | |
EXAMPLE_ONE = <<~LINES | |
00100 | |
11110 | |
10110 | |
10111 | |
10101 | |
01111 | |
00111 | |
11100 | |
10000 | |
11001 | |
00010 | |
01010 | |
LINES | |
def test_part_one_example | |
data = InputData.new(EXAMPLE_ONE).parse | |
assert_equal 198, part_one(data) | |
end | |
def test_part_one_answer | |
data = InputData.new.parse | |
assert_equal 775304, part_one(data) | |
end | |
def test_example_oxygen_rating | |
data = InputData.new(EXAMPLE_ONE).parse | |
assert_equal 23, oxygen_rating(data) | |
end | |
def test_example_co2_scrubber_rating | |
data = InputData.new(EXAMPLE_ONE).parse | |
assert_equal 10, co2_scrubber_rating(data) | |
end | |
def test_part_two_example | |
data = InputData.new(EXAMPLE_ONE).parse | |
assert_equal 230, part_two(data) | |
end | |
def test_part_two_answer | |
data = InputData.new.parse | |
assert_equal 1370737, part_two(data) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment