#!/usr/bin/env ruby require_relative '../common' class Day07 < Day class Tree attr_reader :tree def self.parse(input) input.each_with_object(Tree.new) do |command, tree| if command.start_with?('$ ') cmd, directory = command.match(/\A\$ (cd|ls) ?([A-Za-z\/.]*)\z/).captures tree.cd directory if cmd == "cd" else if command.start_with?('dir ') tree.directory command.split.last else size, file = command.match(/\A([0-9]+) (.+)\z/).captures tree.file file, size end end end end def initialize @current_directory = [] @tree = {} end def cd(directory) if directory == ".." @current_directory.pop else @current_directory << directory if @tree.dig(*@current_directory).nil? @current_directory.inject(@tree) do |tree, directory| tree[directory] = {} if tree[directory].nil? tree[directory] end end end end def directory(name) @tree.dig(*@current_directory)[name] = {} end def file(name, size) @tree.dig(*@current_directory)[name] = size.to_i end def sizes(directory = ["/"]) @tree.dig(*directory).each_with_object({directory.join('/') => 0}) do |(name, content), res| if content.is_a?(Hash) res.merge!(sizes(directory + [name])) res[directory.join('/')] += res[(directory + [name]).join('/')] else res[directory.join('/')] += content end end end end def part1 Tree.parse(stdin).sizes.values.select { |v| v <= 100000 }.sum end def part2 Tree.parse(stdin).sizes.values.select { |v| v >= 8381165 }.min end end Day07.run