view day16.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 ad73a2ff3d06
children
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]

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

mirror_map = {
	"." => {
		right: [:right],
		up: [:up],
		left: [:left],
		down: [:down]
	},
	"/" => {
		right: [:up],
		up: [:right],
		down: [:left],
		left: [:down]
	},
	"\\" => {
		right: [:down],
		down: [:right],
		up: [:left],
		left: [:up]
	},
	"-" => {
		right: [:right],
		left: [:left],
		down: [:left, :right],
		up: [:left, :right]
	},
	"|" => {
		right: [:up, :down],
		left: [:up, :down],
		down: [:down],
		up: [:up]
	}
}

def next_positions(puzzle, mirror_map, laser)
	x_prime, y_prime = case laser.direction
		when :right then [laser.x + 1, laser.y]
		when :down then [laser.x, laser.y + 1]
		when :left then [laser.x - 1, laser.y]
		when :up then [laser.x, laser.y - 1]
	end
	if x_prime < 0 or x_prime >= puzzle[0].length or y_prime < 0 or y_prime >= puzzle.length
		[]
	else
		new_space = puzzle[y_prime][x_prime]
		# puts "#{laser.direction} to #{x_prime}, #{y_prime} (#{new_space})"
		mirror_map[new_space][laser.direction].map {|dir| Laser.new(x_prime, y_prime, dir)}
	end
end

puzzle = File.open(file, "r").each_line(chomp: true).map {|line| line.each_char.to_a}
lasers = next_positions(puzzle, mirror_map, Laser.new(-1, 0, :right))
energised = Array.new(puzzle.length) {Array.new(puzzle[0].length)}
energised [0][0] = 1
previous_lasers = Set.new

while lasers != []
#	puts "#{lasers}"
	lasers = lasers.flat_map do |laser|
		next_positions(puzzle, mirror_map, laser).filter {|new_laser| !previous_lasers.include? new_laser}.each {|new_laser| energised[new_laser.y][new_laser.x] = 1; previous_lasers << new_laser}
	end
end

puts energised.flatten.map(&:to_i).reduce(:+)