view day10.rb @ 24:19481b061461

Implement tilting and cycling for Day 14 part 2 Lots of false starts trying to iterate. Eventually looked for "back in same position" to spot a loop. Then took longer to spot that "same position" isn't necessarily "start position" and loop can be offset!
author IBBoard <dev@ibboard.co.uk>
date Sat, 16 Dec 2023 20:39:02 +0000
parents 9b1d04091335
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]

charmap = File.open(file, "r").each_line(chomp: true).map {|line| line.each_char.to_a}.to_a
$map_height = charmap.length
$map_width = charmap[0].length

# Ugly way to find the start, because we know there's one (for now)
start = charmap.each_with_index.flat_map { |columns, i| j = columns.find_index("S"); if j then [j, i] else nil end }.compact
start_x, start_y = start

$direction_inversion = {north: :south, south: :north, east: :west, west: :east}

$pipemap = charmap.map do |row|
	row.map do |cell|
		case cell
		when "|"
			[:north, :south]
		when "-"
			[:east, :west]
		when "L"
			[:north, :east]
		when "J"
			[:north, :west]
		when "7"
			[:south, :west]
		when "F"
			[:south, :east]
		when "S"
			# Assume all directions are valid
			[:north, :source, :east, :west]
		else
			[]
		end
	end
end

def valid_position? (x, y)
	x >= 0 and x < $map_width and y >= 0 and y < $map_height
end

def get_target_for_step(step)
	case step.direction
		when :north then [step.x, step.y-1]
		when :south then [step.x, step.y+1]
		when :east then [step.x+1, step.y]
		when :west then [step.x-1, step.y]
	end
end

def get_next_step(step)
	new_x, new_y = get_target_for_step(step)
	target_inputs = valid_position?(new_x, new_y) ? $pipemap[new_y][new_x] : [] 
	required_direction = $direction_inversion[step.direction]
	target_inputs.include?(required_direction) ? Step.new(new_x, new_y, (target_inputs - [required_direction])[0]) : nil
end

Step = Struct.new(:x, :y, :direction)

routes = [:north, :south, :east, :west].map {|dir| [Step.new(start_x, start_y, dir)]}

while ! routes.any? {|route| last_step = route[-1]; route.length > 1 and last_step.x == start_x and last_step.y == start_y}
	routes = routes.map do |route|
		next_step = get_next_step(route[-1])
		if next_step
			route << next_step
		else
			nil
		end
	end.compact
end

routes.each {|route| puts "Route: #{route.map{|step| [step.x, step.y]}}"}
# Subtract one because we end up back at the start
puts "Steps: #{routes.map{|route| (route.length - 1)/2}}"