changeset 13:7826431dbc4f

Finish day 5 part 2 - seeds with ranges There must be a cleaner method, but this works for splitting ranges when there's a partial overlap. An interim version dropped ranges because we were iterating over an array while also deleting items from it.
author IBBoard <dev@ibboard.co.uk>
date Sat, 09 Dec 2023 19:53:22 +0000
parents 891878e52a31
children dcc060e59c47
files day5b.rb
diffstat 1 files changed, 30 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/day5b.rb	Sat Dec 09 16:55:59 2023 +0000
+++ b/day5b.rb	Sat Dec 09 19:53:22 2023 +0000
@@ -14,9 +14,7 @@
 
 lines = File.open(file, "r").each_line(chomp: true)
 
-seeds = lines.first.split(":")[1].split(" ").map(&:to_i).each_slice(2).map {|v| v[0]..(v[0]+v[1])}
-
-puts "#{seeds}"
+seeds = lines.first.split(":")[1].split(" ").map(&:to_i).each_slice(2).map {|v| v[0]...(v[0]+v[1])}
 
 RawMapping = Struct.new(:from, :to, :ranges)
 MappingRange = Struct.new(:source_range, :offset)
@@ -36,35 +34,40 @@
 
 mappings = mappings_array.map {|mapping| [mapping.from, mapping]}.to_h
 
-def map_with_override(mappings, input)
-	puts "Mappings: #{mappings} - input: #{input}"
-	mappings.ranges.reduce(input) do |input_ranges, mapping| 
-		puts "Input Ranges: #{input_ranges}; Mapping: #{mapping}"
-		input_ranges.flat_map do |input_range|
-			if mapping.source_range.cover?(input_range)
-				# Input is inside the mapped range
-				[(input_range.begin+mapping.offset)..(input_range.end+mapping.offset)]
-			elsif mapping.source_range.end < input_range.begin or input_range.end < mapping.source_range.begin
-				# Input is entirely outside the mapped range
-				[input_range]
-			elsif input_range.begin < mapping.source_range.begin
-				# Input straddles the start
-				[
-					(input_range.begin+mapping.offset)...(mapping.source_range.begin+mapping.offset),
-					(mapping.source_range.begin+mapping.offset)..(input_range.end+mapping.offset)
-				]
-			else
-				# Must straddle the end
-				[
-					(input_range.begin+mapping.offset)...(mapping.source_range.end+mapping.offset),
-					(mapping.source_range.end+mapping.offset)..(input_range.end+mapping.offset)
-				]
+def map_with_override(mappings, inputs)
+	inputs.flat_map do |input|
+		processed = []
+		unprocessed = [input]
+		# This "each… each" seems messy, but otherwise we can accidentally skip values
+		# because we're editing as we iterate
+		mappings.ranges.each do |mapping|
+			unprocessed.each do |input_range|
+				if mapping.source_range.end <= input_range.begin or input_range.end <= mapping.source_range.begin
+					# Input is entirely outside the mapped range
+				elsif mapping.source_range.cover?(input_range)
+					# Input is inside the mapped range
+					processed << ((input_range.begin+mapping.offset)...(input_range.end+mapping.offset))
+					unprocessed.delete(input_range)
+				elsif input_range.begin < mapping.source_range.begin
+					# Input straddles the start
+					unprocessed.delete(input_range)
+					unprocessed << ((input_range.begin)...(mapping.source_range.begin))
+					processed << ((mapping.source_range.begin+mapping.offset)...(input_range.end+mapping.offset))
+				else
+					# Must straddle the end
+					unprocessed.delete(input_range)
+					processed << ((input_range.begin+mapping.offset)...(mapping.source_range.end+mapping.offset))
+					unprocessed << ((mapping.source_range.end)...(input_range.end))
+				end
 			end
 		end
+		processed + unprocessed
 	end
 end
 
 steps = ["seed", "soil", "fertilizer", "water", "light", "temperature", "humidity"]
 
 # FIXME: Some negative values and 0s, and the final `min()` gets a nill value
-puts steps.reduce(seeds) {|vals, map_name| map_with_override(mappings[map_name], vals)}.map{|v| v.min}.min()
+converted_ranges = steps.reduce(seeds) {|vals, map_name| map_with_override(mappings[map_name], vals)}
+puts converted_ranges.map{|v| v.min}.min
+