73 lines
1.8 KiB
Ruby
73 lines
1.8 KiB
Ruby
|
#!/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
|