@@ -7,13 +7,16 @@ class Day14 < Day # >
7
7
def part1
8
8
Platform
9
9
. new ( input )
10
- . tilt
10
+ . tilt ( :north )
11
11
. total_load_on_north_beams
12
12
end
13
13
14
- # example 1_000_000_000 cycles
14
+ # @ example 1_000_000_000 cycles
15
15
# day.part2 #=> 64
16
16
def part2
17
+ p = Platform . new ( input )
18
+ p . cycle ( 1_000_000_000 )
19
+ p . total_load_on_north_beams
17
20
end
18
21
19
22
EXAMPLE_INPUT = <<~INPUT
@@ -41,6 +44,46 @@ def part2
41
44
#....###..
42
45
#....#....
43
46
TILT
47
+
48
+ AFTER_1_CYCLE = <<~CYCLE
49
+ .....#....
50
+ ....#...O#
51
+ ...OO##...
52
+ .OO#......
53
+ .....OOO#.
54
+ .O#...O#.#
55
+ ....O#....
56
+ ......OOOO
57
+ #...O###..
58
+ #..OO#....
59
+ CYCLE
60
+
61
+ AFTER_2_CYCLES = <<~CYCLE
62
+ .....#....
63
+ ....#...O#
64
+ .....##...
65
+ ..O#......
66
+ .....OOO#.
67
+ .O#...O#.#
68
+ ....O#...O
69
+ .......OOO
70
+ #..OO###..
71
+ #.OOO#...O
72
+ CYCLE
73
+
74
+ AFTER_3_CYCLES = <<~CYCLE
75
+ .....#....
76
+ ....#...O#
77
+ .....##...
78
+ ..O#......
79
+ .....OOO#.
80
+ .O#...O#.#
81
+ ....O#...O
82
+ .......OOO
83
+ #...O###.O
84
+ #.OOO#...O
85
+ CYCLE
86
+
44
87
end
45
88
46
89
class Platform
@@ -51,24 +94,65 @@ class Platform
51
94
CUBED = "#"
52
95
EMPTY = "."
53
96
54
- attr_reader :rounded_rocks , :immovable_rocks , :grid
97
+ attr_reader :rounded_rocks , :immovable_rocks , :grid , :states
55
98
56
99
def initialize ( input )
57
100
@input = input
101
+ @states = [ ]
102
+ @loop_length = 0
58
103
@grid = Grid . new ( input ) . parse
59
104
@rows_max = @grid . row_bounds . max
60
105
end
61
106
62
- # @example
107
+ # @example once
108
+ # p = new(Day14::EXAMPLE_INPUT)
109
+ # p.cycle
110
+ # p.to_s #=> Day14::AFTER_1_CYCLE
111
+ # @example twice
112
+ # p = new(Day14::EXAMPLE_INPUT)
113
+ # p.cycle(2)
114
+ # p.to_s #=> Day14::AFTER_2_CYCLES
115
+ # @example thrice
116
+ # p = new(Day14::EXAMPLE_INPUT)
117
+ # p.cycle(3)
118
+ # p.to_s #=> Day14::AFTER_3_CYCLES
119
+ def cycle ( iterations = 1 )
120
+ i = 0
121
+ while i < iterations do
122
+ [ :north , :west , :south , :east ] . each { |direction | tilt ( direction ) }
123
+
124
+ current_state = rounded_rocks
125
+
126
+ if ( seen_at = states . find_index ( current_state ) ) && @loop_length == 0
127
+ @loop_length = i - seen_at
128
+ target_iter = ( iterations - i ) % @loop_length + 1
129
+ rounded_rocks . each { |coords | grid . set ( coords , EMPTY ) }
130
+ states [ target_iter ] . each { |coords | grid . set ( coords , ROUNDED ) }
131
+ break [ i , target_iter , total_load_on_north_beams ]
132
+ else
133
+ states << current_state
134
+ i += 1
135
+ end
136
+ end
137
+ end
138
+
139
+ DIRECTIONS = {
140
+ north : Vector [ -1 , 0 ] ,
141
+ west : Vector [ 0 , -1 ] ,
142
+ south : Vector [ 1 , 0 ] ,
143
+ east : Vector [ 0 , 1 ] ,
144
+ }
145
+
146
+ # @example 1_north
63
147
# p = new(Day14::EXAMPLE_INPUT)
64
- # p.tilt
148
+ # p.tilt(:north)
65
149
# p.to_s #=> Day14::FIRST_TILT_NORTH
66
- def tilt
150
+ def tilt ( direction )
67
151
loop do
68
152
things_are_moving = false
69
153
rounded_rocks
70
- . each do |coords , rock |
71
- move_to = ( Vector [ *coords ] + Vector [ - 1 , 0 ] ) . to_a
154
+ . each do |coords |
155
+ move_to = ( Vector [ *coords ] + DIRECTIONS [ direction ] ) . to_a
72
156
if grid . cover? ( move_to ) && grid . at ( move_to ) == EMPTY
73
157
grid . set ( move_to , ROUNDED )
74
158
grid . set ( coords , EMPTY )
@@ -81,15 +165,15 @@ def tilt
81
165
end
82
166
83
167
# @example
84
- # new(Day14::EXAMPLE_INPUT).tilt.total_load_on_north_beams #=> 136
168
+ # new(Day14::EXAMPLE_INPUT).tilt(:north) .total_load_on_north_beams #=> 136
85
169
def total_load_on_north_beams
86
170
rounded_rocks
87
- . map { |coords , _value | @rows_max - coords [ 0 ] + 1 }
171
+ . map { |coords | @rows_max - coords [ 0 ] + 1 }
88
172
. reduce ( &:+ )
89
173
end
90
174
91
175
def rounded_rocks
92
- grid . select { |_coords , value | value == ROUNDED }
176
+ grid . filter_map { |coords , value | coords if value == ROUNDED }
93
177
end
94
178
95
179
# @example
0 commit comments