Skip to content

Commit 18aae43

Browse files
author
Robb Kidd
committed
AoC 2022 Day 12 - attempted rewrite with Grid
Looks like I did a lot, but it doesn't work. Save as a different file for posterity.
1 parent afde4e0 commit 18aae43

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

2022/ruby/day12_with_grid.rb

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
require_relative "day"
2+
require_relative "grid"
3+
4+
class Day12 < Day
5+
def initialize(*)
6+
super
7+
@path_finder = HillClimbingAlgorithm.new(input)
8+
end
9+
10+
# @example
11+
# day.part1 #=> 31
12+
def part1
13+
@path_finder
14+
.shortest_hike_from_start
15+
.tap { |path| @path_finder.print(path) }
16+
.length - 1 # start doesn't count towards steps
17+
end
18+
19+
# @example
20+
# day.part2 #=> 29
21+
def part2
22+
@path_finder
23+
.shortest_hike_from_lowest_points
24+
.tap { |path| @path_finder.print(path) }
25+
.length - 1 # start doesn't count towards steps
26+
end
27+
28+
EXAMPLE_INPUT = <<~INPUT
29+
Sabqponm
30+
abcryxxl
31+
accszExk
32+
acctuvwj
33+
abdefghi
34+
INPUT
35+
end
36+
37+
class HillClimbingAlgorithm
38+
def initialize(input = "")
39+
@start_coords = nil
40+
@goal_coords = nil
41+
42+
@hills = Grid.new(input)
43+
@hills.parse do |coords, elevation|
44+
@start_coords = coords if elevation == "S"
45+
@goal_coords = coords if elevation == "E"
46+
end
47+
@hills.set_step_cost_calculator do |h, from, to|
48+
if hikable?(h.at(from), h.at(to))
49+
HIKABLE_HILL_COST
50+
else
51+
CLIMBING_GEAR_REQUIRED_COST
52+
end
53+
end
54+
end
55+
56+
HIKABLE_HILL_COST = 1 # one step on the hike
57+
CLIMBING_GEAR_REQUIRED_COST = Float::INFINITY # effectively ruling them out
58+
59+
# @example from puzzle
60+
# new.hikable? 'm', 'n' #=> true
61+
# new.hikable? 'm', 'a' #=> true
62+
# new.hikable? 'n', 'm' #=> true
63+
# new.hikable? 'm', 'o' #=> false
64+
# @example treat start like a
65+
# new.hikable? 'S', 'a' #=> true
66+
# new.hikable? 'a', 'S' #=> true
67+
# new.hikable? 'S', 'c' #=> false
68+
# new.hikable? 'a', 'c' #=> false
69+
# @example treat goal like z
70+
# new.hikable? 'y', 'z' #=> true
71+
# new.hikable? 'y', 'E' #=> true
72+
# new.hikable? 'x', 'E' #=> false
73+
def hikable?(from_elevation, to_elevation)
74+
[to_elevation, from_elevation].map do |el| # "S", "E", or [a-z],
75+
el
76+
.tr("S", "a") # treat S as lowest (a)
77+
.tr("E", "z") # treat E as highest (z)
78+
.ord # integer value for elevation character for comparison
79+
end
80+
.reduce(&:-) <= 1 # elevation diff is less than 1 higher
81+
end
82+
83+
def shortest_hike_from_start
84+
@hills.shortest_path_between(@start_coords, @goal_coords)
85+
end
86+
87+
def shortest_hike_from_lowest_points
88+
@hills
89+
.select { |coords, elevation| %w[S a].include?(elevation) }
90+
.map { |coords, _| @hills.shortest_path_between(coords, @goal_coords) }
91+
.reject(
92+
&:empty?
93+
) # reject if there was no hikable path from some lowest points
94+
.min_by { |path| path.length }
95+
end
96+
97+
def print(path)
98+
puts "\n" + @hills.render_path(path)
99+
end
100+
end

0 commit comments

Comments
 (0)