-
Notifications
You must be signed in to change notification settings - Fork 0
/
twenty_four.rb
130 lines (102 loc) · 2.51 KB
/
twenty_four.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
class TwentyFour < Day
def initialize
super
@walls = []
@blizards = {
'^' => [],
'v' => [],
'<' => [],
'>' => []
}
process_input
set_blizard_area
end
def part_a
@time = 0
solve(Coordinate.new(0, 1), @exit)
@time
end
def part_b
solve(@exit, Coordinate.new(0, 1))
solve(Coordinate.new(0, 1), @exit)
@time
end
private
def solve(start, finish)
locations_to_search = [start]
loop do
@time += 1
move_blizards
locations_to_search = locations_to_search.flat_map { valid_moves(_1, start, finish) }.uniq
break if locations_to_search.include? finish
end
end
def valid_moves(coordinate, start, finish)
[
coordinate,
coordinate.up,
coordinate.down,
coordinate.left,
coordinate.right
].select { (in_bounds?(_1) && no_blizard_at?(_1)) || _1 == finish || _1 == start }
end
def no_blizard_at?(coordinate)
!@blizard_map[coordinate]
end
def move_blizards
@blizard_map = {}
@blizards.each do |key, coordinates|
direction = direction_map[key]
coordinates.map! do |coordinate|
coordinate.send("#{direction}!")
map_to_bounds coordinate
@blizard_map[coordinate] = true
coordinate
end
end
end
def map_to_bounds(coordinate)
if coordinate.x < @x_lower_bound
coordinate.x = @x_upper_bound
elsif coordinate.x > @x_upper_bound
coordinate.x = @x_lower_bound
elsif coordinate.y < @y_lower_bound
coordinate.y = @y_upper_bound
elsif coordinate.y > @y_upper_bound
coordinate.y = @y_lower_bound
end
coordinate
end
def in_bounds?(coordinate)
(@x_lower_bound..@x_upper_bound).include?(coordinate.x) &&
(@y_lower_bound..@y_upper_bound).include?(coordinate.y)
end
def direction_map
{
'^' => 'up',
'v' => 'down',
'<' => 'left',
'>' => 'right'
}
end
def set_blizard_area
@y_lower_bound = 1
@x_lower_bound = 1
@y_upper_bound = @walls.map(&:y).max - 1
@x_upper_bound = @walls.map(&:x).max - 1
@exit = Coordinate.new(@x_upper_bound, @y_upper_bound + 1)
@blizard_map = {}
end
def process_input
File.readlines('twenty_four.txt', chomp: true).each_with_index do |line, y|
line.chars.each_with_index do |char, x|
next if char == '.'
if char == '#'
@walls << Coordinate.new(x, y)
else
@blizards[char] << Coordinate.new(x, y)
end
end
end
end
end