Advent of Code 2022, Day 3: Rucksack Reorganization

#ruby #advent of code 2022

Part A

Day 3 is about finding character that appears in two strings. We have input like this:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

Each line represents items packed into a rucksack and additionally the first half of the string describes the first compartment and second half of the string describes the second compartment. One item appears in both parts and we need to find out which one.

I went for splitting the string in half, converting it into array of characters and then ANDing both arrays. This should give me items that are present in both arrays. There should be only 1 such item.

data = File.readlines("3.txt").map(&:strip)

points = {}

('a'..'z').each do |char|
  points[char] = char.ord - 'a'.ord + 1
end

('A'..'Z').each do |char|
  points[char] = char.ord - 'A'.ord + 27
end

data.map! do |item|
  size = item.size / 2
  left = item[0...size].split("")
  right = item[size..].split("")

  points[(left & right)[0]]
end

puts data.sum

In the end we need to convert each character into a number and return a sum of all numbers. 1 for ‘a’, 2 for ‘b’ and so on and then 27 for ‘A’. I prepared a hash with all characters mapped to numbers.

Part B

In Part B we are looking for the common item in the groups of 3 lines. Our initial input consist of 2 such groups:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg

wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

THe solution is similar. Now I am iterating every 3 indexes, converting all three lines into separate arrays of characters and then ANDing all 3 together, which should give just one common item.

data = File.readlines("3.txt").map(&:strip)

points = {}

('a'..'z').each do |char|
  points[char] = char.ord - 'a'.ord + 1
end

('A'..'Z').each do |char|
  points[char] = char.ord - 'A'.ord + 27
end

size = data.size

total = 0

(size / 3).times do |index|
  a = data[index * 3 + 0].split("")
  b = data[index * 3 + 1].split("")
  c = data[index * 3 + 2].split("")

  total += points[(a & b & c)[0]]
end

puts total