@@ -26,25 +26,20 @@ def part2
2626class TachyonManifold < Grid
2727 include UglySweater
2828
29- attr_reader :entrance , :splitter_coords , :splitters_by_row , :beams_by_row
30-
31- def self . example
32- new ( Day07 ::EXAMPLE_INPUT ) . parse
33- end
29+ attr_reader :entrance , :splitter_coords
3430
3531 def initialize ( input = nil )
3632 super
3733 @entrance = nil
3834 @splitter_coords = Set . new
35+ @beam_density = Hash . new { 0 }
3936 end
4037
4138 # @example
4239 # tachmani = new(Day07::EXAMPLE_INPUT)
4340 # tachmani.parse
4441 # tachmani.entrance #=> [0,7]
4542 # tachmani.splitter_coords #=> Set[[2, 7], [4, 6], [4, 8], [6, 5], [6, 7], [6, 9], [8, 4], [8, 6], [8, 10], [10, 3], [10, 5], [10, 9], [10, 11], [12, 2], [12, 6], [12, 12], [14, 1], [14, 3], [14, 5], [14, 7], [14, 9], [14, 13]]
46- # tachmani.splitters_by_row[4] #=> Set[6,8]
47- # tachmani.beams_by_row[0] #=> Set[7]
4843 def parse
4944 super { |coord , char |
5045 case char
@@ -53,47 +48,41 @@ def parse
5348 else ; # keep calm and parse on
5449 end
5550 }
56-
57- @beams_by_row = Array . new ( @row_bounds . count ) { Set . new }
58- @beams_by_row [ @entrance [ 0 ] ] << @entrance [ 1 ]
59-
60- @beam_density = Hash . new { 0 }
61- @beam_density [ @entrance ] += 1
62-
63- @splitters_by_row = Array . new ( @row_bounds . count ) { Set . new }
64- @splitter_coords . each { |( r , c ) |
65- @splitters_by_row [ r ] << c
66- }
67-
68- @beam_splits = 0
69-
70- self
7151 end
7252
7353 def track_beam
74- @row_bounds . to_a [ 1 ..] . each { |r |
75- @beams_by_row [ r -1 ] . each { |c |
76- if @splitters_by_row [ r ] . include? ( c )
77- @beams_by_row [ r ] << c -1
78- @beams_by_row [ r ] << c +1
79- @beam_splits += 1
80- @beam_density [ [ r , c -1 ] ] += @beam_density [ [ r -1 , c ] ]
81- @beam_density [ [ r , c +1 ] ] += @beam_density [ [ r -1 , c ] ]
82- else
83- @beams_by_row [ r ] << c
84- @beam_density [ [ r , c ] ] += @beam_density [ [ r -1 , c ] ]
85- end
86- }
87- }
54+ @beam_density [ @entrance ] += 1
55+
56+ @row_bounds
57+ . each do |row |
58+ next if row == @row_bounds . min # skip first row, that's where the beam enters
59+
60+ @beam_density
61+ . select { |( beam_row , _ ) , _ | beam_row == row -1 } # beams from above
62+ . each do |( _ , beam_col ) , density |
63+ if @splitter_coords . include? ( [ row , beam_col ] )
64+ @beam_density [ [ row , beam_col -1 ] ] += density
65+ @beam_density [ [ row , beam_col +1 ] ] += density
66+ else
67+ @beam_density [ [ row , beam_col ] ] += density
68+ end
69+ end
70+ end
8871 end
8972
9073 def beam_splits
91- @beam_splits
74+ @splitter_coords
75+ . select { |( r , c ) |
76+ @beam_density [ [ r -1 , c ] ] > 0 # look above every splitter for beaminess
77+ }
78+ . count
9279 end
9380
9481 def timeline_splits
9582 @beam_density
96- . filter_map { |( r , c ) , density | density if r == @row_bounds . max }
83+ . filter_map { |( r , c ) , density |
84+ density if r == @row_bounds . max # beam densities on manifold exit
85+ }
9786 . reduce ( &:+ )
9887 end
9988
@@ -107,5 +96,4 @@ def to_s
10796 end
10897 }
10998 end
110-
11199end
0 commit comments