@@ -4,41 +4,73 @@ class Day08 < Day # >
4
4
5
5
# @example
6
6
# day.part1 #=> 2
7
+ # @example with cycles
8
+ # day = Day08.new(SIX_STEPS_INPUT)
9
+ # day.part1 #=> 6
7
10
def part1
8
- parse ( input )
11
+ instructions , network = parse ( input )
9
12
steps = 0
10
- node = "AAA"
11
- @ instructions
13
+ current_node = "AAA"
14
+ instructions
12
15
. cycle do |instruction |
13
- break if node == "ZZZ"
16
+ break if current_node == "ZZZ"
14
17
steps += 1
15
- node = @ network[ node ] [ instruction ]
18
+ current_node = network [ current_node ] [ instruction ]
16
19
end
17
20
steps
18
21
end
19
22
20
23
# @example
21
- # day.part2 #=> 'how are you'
24
+ # day = Day08.new(PART2_EXAMPLE_INPUT)
25
+ # day.part2 #=> 6
22
26
def part2
23
- end
27
+ instructions , network = parse ( input )
28
+ steps = 0
29
+ start_nodes = network . keys . select { |node | node [ -1 ] == "A" }
24
30
25
- # @example
26
- # inst, net = day.parse(EXAMPLE_INPUT)
27
- # inst #=> ["R", "L"]
28
- def parse ( input )
29
- stanzas = input . split ( "\n \n " )
31
+ start_nodes
32
+ . map { |current_node |
33
+ Thread . new { # for whatever multitasking Ruby will give me
34
+ steps = 0
35
+ a_to_z = nil
36
+
37
+ instructions
38
+ . cycle do |instruction |
39
+ if current_node [ -1 ] == "Z" # on a Z node
40
+ !a_to_z ? a_to_z = steps : break # note how many steps to the first Z node, stop on second Z node
41
+ end
30
42
31
- @instructions = stanzas [ 0 ] . chars
43
+ steps += 1
44
+ current_node = network [ current_node ] [ instruction ]
45
+ end
32
46
33
- @network = { }
34
- stanzas [ 1 ]
35
- . each_line
36
- . map { |line | line . scan ( /\w +/ ) }
37
- . each { |node , left , right |
38
- @network [ node ] = { "L" => left , "R" => right }
47
+ if ( steps - a_to_z ) != a_to_z
48
+ raise ( "steps from Z-to-Z must match A-to-Z to use least common multiple" )
49
+ end
50
+ a_to_z
51
+ }
39
52
}
53
+ . map ( &:value )
54
+ . reduce ( 1 , :lcm )
55
+ end
40
56
41
- [ @instructions , @network ]
57
+ # @example
58
+ # instructions, network = day.parse(EXAMPLE_INPUT)
59
+ # instructions #=> ["R", "L"]
60
+ # network["AAA"] #=> {"L" => "BBB", "R" => "CCC"}
61
+ def parse ( input )
62
+ @stanzas ||= input . split ( "\n \n " )
63
+
64
+ @parsed ||=
65
+ [
66
+ @stanzas [ 0 ] . chars ,
67
+ @stanzas [ 1 ]
68
+ . each_line
69
+ . map { |line | line . scan ( /\w +/ ) }
70
+ . each_with_object ( { } ) { |( node , left , right ) , network |
71
+ network [ node ] = { "L" => left , "R" => right }
72
+ }
73
+ ]
42
74
end
43
75
44
76
EXAMPLE_INPUT = <<~INPUT
@@ -60,4 +92,17 @@ def parse(input)
60
92
BBB = (AAA, ZZZ)
61
93
ZZZ = (ZZZ, ZZZ)
62
94
INPUT
95
+
96
+ PART2_EXAMPLE_INPUT = <<~INPUT
97
+ LR
98
+
99
+ 11A = (11B, XXX)
100
+ 11B = (XXX, 11Z)
101
+ 11Z = (11B, XXX)
102
+ 22A = (22B, XXX)
103
+ 22B = (22C, 22C)
104
+ 22C = (22Z, 22Z)
105
+ 22Z = (22B, 22B)
106
+ XXX = (XXX, XXX)
107
+ INPUT
63
108
end
0 commit comments