Advent of Code 2020: Day 7 (Ruby solution)

This time the puzzle is a little bit harder.

You get text instructions in not-trivial to parse form, like:

  • striped white bags contain 4 drab silver bags.
  • drab silver bags contain no other bags.
  • pale plum bags contain 1 dark black bag.
  • muted gold bags contain 1 wavy red bag, 3 mirrored violet bags, 5 bright gold bags, 5 plaid white bags.

Obviously, the file is much longer.

So the first intuitive step is to parse them to ruby structure like Hash:

file = File.read('inputs/day7.txt')

@bags_hash = {}
file.each_line do |line|
  bags_params = line.scan(/(?:\d+ )?[[:alpha:]]+ [[:alpha:]]+(?= bags?)/)
  @bags_hash[bags_params[0]] = {}
  bags_params[1..].each do |bag|
    next if bag == 'no other'
    expression_params = bag.split(/(?<=\d) /)
    quantity = expression_params.size == 1 ? 1 : expression_params.first.to_i
    color_name = expression_params.last
    @bags_hash[bags_params[0]][color_name] = quantity
  end
end

The first task is to count how many bag colors can eventually contain at least one "shiny gold bag". I do it this way:

def bag_include_requested_color_bag? color_bag, requested_color_bag
  return true if @bags_hash[color_bag].keys.include? requested_color_bag
  return @bags_hash[color_bag].any? do |key, value|
    bag_include_requested_color_bag?(key, requested_color_bag)
  end
end

res = @bags_hash.keys.sum do |color|
  bag_include_requested_color_bag?(color, 'shiny gold') ? 1 : 0
end

puts "First task answer: #{res}"

Another task is to find how many individual bags are required inside a single "shiny gold bag". Here is my code:

def bags_count color_bag, quantity
  quantity + @bags_hash[color_bag].sum do |key, value|
    quantity * bags_count(key, value)
  end
end

res = @bags_hash['shiny gold'].sum do |key, value|
  value * bags_count(key, 1)
end

puts "Second task answer: #{res}"