diff --git a/2024/ruby/day_09.rb b/2024/ruby/day_09.rb index a1053ad..dcca30e 100644 --- a/2024/ruby/day_09.rb +++ b/2024/ruby/day_09.rb @@ -3,19 +3,70 @@ disk_map = DATA.read.chars.each_slice(2) [ Array.new(a.to_i, i), Array.new(b.to_i, nil) ] }.reject(&:empty?) -while (prev, free = disk_map.each_cons(2).find { _2.include?(nil) }) - tail = disk_map.last - until free.empty? || tail.empty? - prev << tail.shift - free.pop +# while (prev, free = disk_map.each_cons(2).find { _2.include?(nil) }) +# tail = disk_map.last +# until free.empty? || tail.empty? +# prev << tail.shift +# free.pop +# end +# +# while disk_map.last.all?(&:nil?) +# disk_map.pop +# end +# end + +# pp disk_map.flatten.compact.each.with_index.sum { _1 * _2 } + +Block = Struct.new(:id, :size, :prev, :next) do + def each + return enum_for(__method__) unless block_given? + + cur = self + while cur + yield cur + cur = cur.next + end + end + + def inspect + "" + end + + def to_s + (id || ?.).to_s * size end +end + +blocks = disk_map.map { Block.new(_1[0], _1.size) } + .each_cons(2) { _1.next = _2; _2.prev = _1 } - while disk_map.last.all?(&:nil?) - disk_map.pop +head = blocks.first +tail = blocks.last + +until tail == head + unless tail.id.nil? + find_free = head + until (find_free.id.nil? && find_free.size >= tail.size) || (find_free == tail) + find_free = find_free.next + end + if find_free != tail + a = find_free + b = tail + a.id, b.id = b.id, a.id + + if a.size > b.size + c = Block.new(nil, a.size - b.size, a, a.next) + a.size = b.size + a.next = c + c.next.prev = c + end + end end + + tail = tail.prev end -pp disk_map.flatten.each.with_index.sum { _1 * _2 } +pp head.each.flat_map { Array.new(_1.size, _1.id) }.each.with_index.sum { _1.to_i * _2 } __END__ 2333133121414131402