From e7795b324edf28f2affdb53fa6bc07679a598eea Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Thu, 9 Dec 2021 16:24:09 +0100 Subject: [PATCH] feat: Day 3 --- puzzles/03_1/main.rb | 34 ++++++++++++++++++++++++++++++++++ puzzles/03_2/main.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 puzzles/03_1/main.rb create mode 100644 puzzles/03_2/main.rb diff --git a/puzzles/03_1/main.rb b/puzzles/03_1/main.rb new file mode 100644 index 0000000..359d36b --- /dev/null +++ b/puzzles/03_1/main.rb @@ -0,0 +1,34 @@ +def run(f) + len = 0 + bits = [] + + f.each do |line| + if len == 0 + # Skip the trailing newline character and convert to 0-based index + len = line.length() - 2 + 0.upto(len) { |n| bits[n] = [0, 0] } + end + + len.downto(0) { |n| + digit = Integer(line[n]) + bits[n][digit] += 1 + } + end + + gamma = 0 + epsilon = 0 + + len.downto(0) { |n| + # Since we iterated from left to right on the input + # we need to do the same when building the integers + width = len - n + + if bits[n][0] > bits[n][1] + gamma += 1 << width + else + epsilon += 1 << width + end + } + + return gamma * epsilon +end diff --git a/puzzles/03_2/main.rb b/puzzles/03_2/main.rb new file mode 100644 index 0000000..0603b6d --- /dev/null +++ b/puzzles/03_2/main.rb @@ -0,0 +1,42 @@ +def find(lines, index, search) + if index > (lines.first.length() - 2) + raise "Invalid index" + end + + bits = [0, 0] + + # Count the occurrences of each digit at the index + lines.each do |line| + digit = Integer(line[index]) + bits[digit] += 1 + end + + # Not the most expressive way to do this, but should get the job done + if search == 1 + # Return most common value, or 1 on a tie + target = bits[0] > bits[1] ? 0 : 1 + else + # Return least common value, or 0 on a tie + target = bits[0] <= bits[1] ? 0 : 1 + end + + # Filter lines to only the ones that have the target value at `index` + lines = lines.filter { |line| line[index] == target.to_s } + + # If there's only one left, we found our value. + # Otherwise, continue filtering at the next index + if lines.length() == 1 + return lines.first + else + return find(lines, index + 1, search) + end +end + +def run(f) + lines = f.readlines() + # This should filter down to a single number, which we need to convert from a base 2 bit string + oxygen = find(lines, 0, 1).to_i(2) + co2 = find(lines, 0, 0).to_i(2) + + return oxygen * co2 +end