#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