diff --git a/2022/ruby/day_07.rb b/2022/ruby/day_07.rb new file mode 100644 index 0000000..a52c19e --- /dev/null +++ b/2022/ruby/day_07.rb @@ -0,0 +1,69 @@ +input = ARGF.read.lines(chomp: true).slice_when { _2.start_with?(?$) } + +Dir = Struct.new(:parent, :name, :children) do + include Enumerable + + def size = children.sum(&:size) + + def each(&block) + return enum_for(__method__, &block) unless block + + block.(self) + + children.each do |child| + case child + when Dir + child.each(&block) + when File + block.(child) + else + fail child.inspect + end + end + end +end + +File = Struct.new(:parent, :name, :size) + +root = Dir.new(nil, ?/, []) +pwd = root + +input.each do |chunk| + cmd, *out = *chunk + case cmd + when /\$ cd \// + # no-op + when /\$ cd \.\./ + pwd = pwd.parent + when /\$ cd (.+)/ + pwd = pwd.children.find { _1.name == $1 } + when /\$ ls/ + out.each do |line| + case line + when /(\d+) (.+)/ + pwd.children << File.new(pwd, $2, $1.to_i) + when /dir (.+)/ + pwd.children << Dir.new(pwd, $1, []) + else + fail line + end + end + else + fail chunk.inspect + end +end + +# part 1 +p root.each + .select { Dir === _1 } + .map(&:size) + .select { _1 < 100_000 } + .sum + +# part 2 +p root.each + .select { Dir === _1 } + .map(&:size) + .sort + .find { _1 >= 30_000_000 - (70_000_000 - root.size) } +