view day3b.rb @ 33:676461cc3a70

Day 23 - track segments, not each space This allows us to explore the branches once then do quicker calculations for valid route lengths. But still requires exploring 1,262,816 routes to find the longest!
author IBBoard <dev@ibboard.co.uk>
date Thu, 04 Jan 2024 14:52:24 +0000
parents 0f4991eca11a
children
line wrap: on
line source

#! /usr/bin/env ruby

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]

number_chars = *('0'..'9')
skip_chars = ['.']

numbers = Hash.new
symbols = Array.new
Position = Struct.new(:x, :y)
NumberValue = Struct.new(:value, :positions)
SymbolValue = Struct.new(:value, :position)

def create_number_position(vals)
	number = vals.reduce("") {|m, v| m + v[0]}.to_i
	positions = vals.map {|v| Position.new(v[1], v[2])}
	NumberValue.new(number, positions)
end

def adjacent(a, b)
	(a.x - b.x).abs <= 1 and (a.y - b.y).abs <= 1
end

sum = 0
positions = File.open(file, "r").each_line(chomp: true).with_index.map do |line, index|
	numbers = line.each_char.with_index.map {|c, i| if number_chars.include? c or !skip_chars.include? c then [c, index, i] end }\
		.filter {|v| v != nil }\
		.reduce([[], []]) do |memo, val| 
			if number_chars.include? val[0] then 
				if memo[1].last and memo[1].last[2] + 1 != val[2] then 
					memo[0] << create_number_position(memo[1])
					memo[1] = []
				end
				memo[1] << val
			else
				if memo[1] != [] then
					memo[0] << create_number_position(memo[1])
					memo[1] = []
				end
				memo[0] << SymbolValue.new(val[0], Position.new(val[1], val[2]))
			end
			memo
		end
	if numbers[1] != [] then
		numbers[0] << create_number_position(numbers[1])
	end
	numbers[0]
end.flatten.group_by {|elem| elem.class}

symbol_pos = positions[SymbolValue]
number_pos = positions[NumberValue]

puts symbol_pos.filter {|sym| sym.value == "*"}.map {|sym| number_pos.filter {|num| num.positions.any? {|num_pos| adjacent(num_pos, sym.position)}}}.filter {|nums| nums.length == 2}.map {|val| val.reduce(1) {|v, k| v * k.value}}.reduce(:+)