view day5b.rb @ 12:891878e52a31

Implement Day 9 - diffing and predicting There might be a better way with Reduce instead of pushing values into the arrays, but it's quick and it worked
author IBBoard <dev@ibboard.co.uk>
date Sat, 09 Dec 2023 16:55:59 +0000
parents 25dda3397797
children 7826431dbc4f
line wrap: on
line source

#! /usr/bin/env ruby

require 'set'

if ARGV.length != 1
        abort("Incorrect arguments - needs input file")
elsif not File.exist? (ARGV[0])
	abort("File #{ARGV[0]} did not exist")
end

file = ARGV[0]

maps = Hash.new

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}"

RawMapping = Struct.new(:from, :to, :ranges)
MappingRange = Struct.new(:source_range, :offset)

mappings = Array.new
mappings_array = []

lines.drop(1).reduce(mappings_array) do |mappings, val|
	if m = /([a-z]+)-to-([a-z]+) map:/.match(val) then
		mappings << RawMapping.new(m[1], m[2], [])
	elsif val != "" then
		dest_start, source_start, range_length = val.split(" ").map(&:to_i)
		mappings[-1].ranges << MappingRange.new((source_start...(source_start + range_length)), dest_start - source_start)
	end
	mappings
end

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)
				]
			end
		end
	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()