Mercurial > repos > other > adventofcode2023
changeset 32:a1b748f2c416
Implement day 23 "longest route finding"
Allows for "downhill only" and "can climb" approaches. But
climbing still brute-forces the map and takes too long on the
final input.
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Thu, 04 Jan 2024 11:18:56 +0000 |
parents | 47dc75915e91 |
children | 676461cc3a70 |
files | day23.rb day23.txt |
diffstat | 2 files changed, 81 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day23.rb Thu Jan 04 11:18:56 2024 +0000 @@ -0,0 +1,76 @@ +#! /usr/bin/env ruby + +if ARGV.length != 1 and ARGV.length != 2 + abort("Incorrect arguments - needs input file and optional second arg") +elsif not File.exist? (ARGV[0]) +abort("File #{ARGV[0]} did not exist") +end + +file = ARGV[0] + +lines = File.open(file, "r").each_line(chomp: true).to_a +start_pos = [lines[0].index("."), 0] +end_pos = [lines[-1].index("."), lines.length - 1] +maze = lines.map {|line| line.each_char.to_a} + +$maze_width = 0...maze[0].length +$maze_height = 0...maze.length +$can_climb_hills = ARGV.length == 2 + +open_routes = [[start_pos]] + +distances = Array.new(maze.length) {Array.new(maze[0].length) {Hash.new}} + +$moves = [[0,1], [0,-1], [1,0], [-1,0]] + +def valid_move(move, space, maze) + if $maze_width.cover?(space[0]) && $maze_height.cover?(space[1]) + case maze[space[1]][space[0]] + when "#" then false + when "." then true + when "^" then $can_climb_hills || move == [0,-1] + when "v" then $can_climb_hills || move == [0, 1] + when ">" then $can_climb_hills || move == [1, 0] + when "<" then $can_climb_hills || move == [-1,0] + end + else + false + end +end + +def next_steps(route, maze) + last_space = route[-1] + $moves.map do |move| + new_space = [move[0] + last_space[0], move[1] + last_space[1]] + [move, new_space] + end.filter do |move, new_space| + valid_move(move, new_space, maze) && !route.include?(new_space) + end +end + +while open_routes != [] + num_routes = open_routes.length + open_routes = open_routes.flat_map do |route| + next_steps(route, maze).map do |move, next_step| + new_route = route + [next_step] + # Simple "distance to this point" doesn't work when if can approach from different + # directions, because the other route may be shorter to here but longer to the end + # so we use the movement direction to track different directionality + current_distances = distances[next_step[1]][next_step[0]] + if !current_distances.key?(move) || new_route.length > current_distances[move] + distances[next_step[1]][next_step[0]][move] = new_route.length + new_route + else + # We have a longer route to this space in this direction, so prune + nil + end + end.filter {|route| !route.nil?} + end + # if open_routes.length != num_routes + # puts "Now have:" + # open_routes.each {|route| puts " * #{route.length} to #{route[-1]}"} + # end +end + +# Subtract 1 because we don't count the first step +puts "#{distances[end_pos[1]][end_pos[0]].values.max - 1}" \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day23.txt Thu Jan 04 11:18:56 2024 +0000 @@ -0,0 +1,5 @@ +--- Day 23: A Long Walk --- + +You have a map made of blocked spaces (#), open spaces (.) and slopes (^, >, v, and <). You can't go back up slopes. + +What is the LONGEST route from the start (open space in the top row) to the end (open space in the bottom row). \ No newline at end of file