aoc2023/day_5/impl_2.rb

110 lines
3.0 KiB
Ruby

#prepare the input which is a string containing new lines
def parse(input)
data = []
map = []
input.each_line do |line|
if data.empty?
seed_ranges = []
seeds = line.split(":").last.split(" ").map(&:to_i)
(seeds.length/2).times do |i|
seed_ranges << [seeds[2*i],seeds[2*i+1]]
end
data << seed_ranges
next
end
if line.include?(":") && !map.empty?
data << map
map = []
next
end
next if line.include?(":")
next if line.strip.empty?
# build the map
target,source,ranges = line.split(" ").map(&:to_i)
diff = target-source
map << [source,ranges,diff]
end
data << map
data
end
# result should a single string or integer
def calculate(data)
seeds = nil
data.each do |d|
if seeds.nil?
seeds = d
next
end
# start mapping
i=0
d.each do |mapping|
new_seeds = []
map_start,map_range,diff = mapping
map_end = map_start + map_range -1
puts "map: #{map_start}--#{map_end} doing #{diff}"
seeds.each do |seed_pair|
seed_start,seed_range = seed_pair
seed_end = seed_start+seed_range
# <---|---|--->
if seed_start <= map_start && map_end <= seed_end
puts "<---|---|--->"
new_seed_start = seed_start
new_seed_range = map_start - seed_start
additional_start = map_start + diff
additional_range = map_end - map_start
third_start = map_end
third_end = seed_end - map_end
new_seeds << [new_seed_start,new_seed_range]
new_seeds << [additional_start,additional_range]
new_seeds << [third_start,third_end]
next
end
# |---<---|--->
if map_start <= seed_start && map_end >= seed_start && map_end <= seed_end
puts "|---<---|--->"
new_seed_start = seed_start + diff
new_seed_range = map_end - seed_start
additional_start = map_end
additional_range = seed_end - map_end
new_seeds << [new_seed_start,new_seed_range]
new_seeds << [additional_start,additional_range]
next
end
# <---|--->---|
if seed_start <= map_start && seed_end >= map_start && seed_end <= map_end
puts "<---|--->---|"
new_seed_start = seed_start
new_seed_range = map_start - seed_start
additional_start = map_start + diff
additional_range = seed_end - map_start
new_seeds << [new_seed_start,new_seed_range]
new_seeds << [additional_start,additional_range]
next
end
# |---<-->---|
if map_start <= seed_start && seed_end <= map_end
puts "|---<-->---|"
new_seed_start = seed_start + diff
new_seed_range = seed_range
new_seeds << [new_seed_start,new_seed_range]
next
end
# else
new_seeds << seed_pair
end
pp new_seeds
seeds = new_seeds
end
break if i==1
i+=1
end
seeds = seeds.map{|seed_pair| seed_pair[0]}
seeds.min
end