-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday_9.rb
More file actions
160 lines (134 loc) · 3.54 KB
/
day_9.rb
File metadata and controls
160 lines (134 loc) · 3.54 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# frozen_string_literal: true
require 'readline'
class Knot
attr_accessor :x, :y, :visited_positions, :name
def initialize(x, y, name)
@x = x.to_i
@y = y.to_i
@name = name
@visited_positions = { key => 1 }
end
def move_up
@y += 1
update_visited_positions
end
def move_down
@y -= 1
update_visited_positions
end
def move_left
@x -= 1
update_visited_positions
end
def move_right
@x += 1
update_visited_positions
end
def key
"#{@x}, #{@y}"
end
def update_visited_positions
@visited_positions.key?(key) ? @visited_positions[key] += 1 : @visited_positions[key] = 1
end
end
head_movements = ::File.readlines('inputs/day_9.txt', chomp: true)
# head_movements = ::File.readlines('inputs/day_9.test1.txt', chomp: true)
# head_movements = ::File.readlines('inputs/day_9.test2.txt', chomp: true)
head_position = ::Knot.new(1, 1, 'head')
tail_position = ::Knot.new(1, 1, 'tail')
def move_knot(head, tail)
# Don't move the tail if it's touching diagonally the head still
return if touching_diagonally?(tail, head)
# Can we just move left/right to touch the head?
if tail.y == head.y
tail.x > head.x ? tail.move_left : tail.move_right
return
end
# Can we just move up/down to touch the head?
if tail.x == head.x
tail.y > head.y ? tail.move_down : tail.move_up
return
end
# == Move diagonally to touch the head again ==
# In this case jump manually to not record the intermediate jumps and save the final position.
# However we need to figure out what jumps makes most sense: e.g which jump is the smallest.
jump_horizontally(tail, head)
jump_vertically(tail, head)
tail.update_visited_positions
end
def jump_horizontally(tail, head)
if tail.x > head.x
tail.x -= 1
else
tail.x += 1
end
end
def jump_vertically(tail, head)
if tail.y > head.y
tail.y -= 1
else
tail.y += 1
end
end
def touching_diagonally?(tail, head)
(tail.y - head.y).abs <= 1 && (tail.x - head.x).abs <= 1
end
head_movements.each do |movement|
direction, steps = movement.split(' ')
steps.to_i.times do
case direction
when 'D'
head_position.move_down
when 'L'
head_position.move_left
when 'R'
head_position.move_right
when 'U'
head_position.move_up
else
puts "The direction '#{direction}' is unknown"
end
# == Now figure out where the tail needs to move to ==
move_knot(head_position, tail_position)
end
end
puts "The tail visited #{tail_position.visited_positions.keys.length} positions at least once"
## PART 2
head = ::Knot.new(1, 1, 'H')
one = ::Knot.new(1, 1, '1')
two = ::Knot.new(1, 1, '2')
three = ::Knot.new(1, 1, '3')
four = ::Knot.new(1, 1, '4')
five = ::Knot.new(1, 1, '5')
six = ::Knot.new(1, 1, '6')
seven = ::Knot.new(1, 1, '7')
eight = ::Knot.new(1, 1, '8')
nine = ::Knot.new(1, 1, '9')
head_movements.each do |movement|
direction, steps = movement.split(' ')
steps.to_i.times do
case direction
when 'D'
head.move_down
when 'L'
head.move_left
when 'R'
head.move_right
when 'U'
head.move_up
else
puts "The direction '#{direction}' is unknown"
end
# == Now figure out where the tail needs to move to ==
move_knot(head, one)
move_knot(one, two)
move_knot(two, three)
move_knot(three, four)
move_knot(four, five)
move_knot(five, six)
move_knot(six, seven)
move_knot(seven, eight)
move_knot(eight, nine)
end
end
puts "The tail visited #{nine.visited_positions.keys.length} positions at least once"