@@ -15,6 +15,24 @@ def part_two(input)
1515 @cols = @map [ 0 ] . length
1616 @visited = Array . new ( @rows ) { Array . new ( @cols , false ) }
1717
18+ @grid = Grid . new ( @map )
19+
20+ price_perimeter , price_sides = @grid . calculate_price_area_perimeter
21+
22+ puts "Price perimeter: #{ price_perimeter } "
23+ puts "Price sides: #{ price_sides } "
24+
25+ price_sides
26+ end
27+ end
28+
29+ class Day12Part1
30+ def part_one ( input )
31+ @map = input . split ( "\n " )
32+ @rows = @map . length
33+ @cols = @map [ 0 ] . length
34+ @visited = Array . new ( @rows ) { Array . new ( @cols , false ) }
35+
1836 total_price
1937 end
2038
@@ -71,65 +89,108 @@ def out_of_bounds?(row, col)
7189 end
7290end
7391
74- class Day12Part1
75- def part_one ( input )
76- @map = input . split ( "\n " )
77- @rows = @map . length
78- @cols = @map [ 0 ] . length
79- @visited = Array . new ( @rows ) { Array . new ( @cols , false ) }
92+ class Grid
93+ attr_reader :width , :height
8094
81- total_price
82- end
95+ def initialize ( grid )
96+ @grid = grid
97+ @height = @grid . size
98+ @width = @grid [ 0 ] . size
99+ @visited = Array . new ( @height ) { Array . new ( @width , false ) }
83100
84- def total_price
85- regions = find_regions
86- regions . sum { |region | region [ :area ] * region [ :perimeter ] }
101+ # directions: up, down, left, right
102+ @directions = [ [ -1 , 0 ] , [ 1 , 0 ] , [ 0 , -1 ] , [ 0 , 1 ] ]
87103 end
88104
89- def find_regions
90- regions = [ ]
91- ( 0 ...@rows ) . each do |row |
92- ( 0 ...@cols ) . each do |col |
93- next if @visited [ row ] [ col ]
94-
95- char = @map [ row ] [ col ]
96- area , perimeter = explore_region ( row , col , char )
97- regions << { area : area , perimeter : perimeter }
98- end
99- end
100- regions
105+ def on_map? ( x , y )
106+ # check if x, y coord exist
107+ x . between? ( 0 , @height - 1 ) && y . between? ( 0 , @width - 1 )
101108 end
102109
103- def explore_region ( row , col , char )
104- queue = [ [ row , col ] ]
110+ def find_plot_BFS ( start_x , start_y )
111+ plant_type = @grid [ start_x ] [ start_y ]
112+ queue = [ [ start_x , start_y ] ]
113+ @visited [ start_x ] [ start_y ] = true
114+
105115 area = 0
106116 perimeter = 0
117+ cells = Set . new ( [ [ start_x , start_y ] ] )
107118
108119 until queue . empty?
109- current_row , current_col = queue . shift
110- next if out_of_bounds? ( current_row , current_col ) || @visited [ current_row ] [ current_col ]
111-
112- next unless @map [ current_row ] [ current_col ] == char
113-
114- @visited [ current_row ] [ current_col ] = true
120+ x , y = queue . shift
115121 area += 1
116122
117- # Check all four directions
118- [ [ 0 , 1 ] , [ 1 , 0 ] , [ 0 , -1 ] , [ -1 , 0 ] ] . each do |dr , dc |
119- new_row = current_row + dr
120- new_col = current_col + dc
121- if out_of_bounds? ( new_row , new_col ) || @map [ new_row ] [ new_col ] != char
122- perimeter += 1
123+ @directions . each do |dx , dy |
124+ nx = x + dx
125+ ny = y + dy
126+
127+ if on_map? ( nx , ny )
128+ if @grid [ nx ] [ ny ] == plant_type && !@visited [ nx ] [ ny ]
129+ @visited [ nx ] [ ny ] = true
130+ queue << [ nx , ny ]
131+ cells . add ( [ nx , ny ] )
132+ elsif @grid [ nx ] [ ny ] != plant_type
133+ perimeter += 1
134+ end
123135 else
124- queue << [ new_row , new_col ] unless @visited [ new_row ] [ new_col ]
136+ # Out of bounds contributes to perimeter
137+ perimeter += 1
125138 end
126139 end
127140 end
128141
129- [ area , perimeter ]
142+ # Calculate the number of sides (== corners) for the plot
143+ sides = calculate_corners ( cells )
144+ [ area , perimeter , sides ]
130145 end
131146
132- def out_of_bounds? ( row , col )
133- row < 0 || row >= @rows || col < 0 || col >= @cols
147+ def calculate_corners ( cells )
148+ corners = 0
149+
150+ cells . each do |cell |
151+ x , y = cell
152+ u = [ x - 1 , y ] # Up
153+ d = [ x + 1 , y ] # Down
154+ r = [ x , y + 1 ] # Right
155+ l = [ x , y - 1 ] # Left
156+
157+ # External corners
158+ corners += 1 if !cells . include? ( u ) && !cells . include? ( r )
159+ corners += 1 if !cells . include? ( r ) && !cells . include? ( d )
160+ corners += 1 if !cells . include? ( d ) && !cells . include? ( l )
161+ corners += 1 if !cells . include? ( l ) && !cells . include? ( u )
162+
163+ # Internal (diagonal) corners
164+ ur = [ x - 1 , y + 1 ] # Up-Right
165+ ul = [ x - 1 , y - 1 ] # Up-Left
166+ dr = [ x + 1 , y + 1 ] # Down-Right
167+ dl = [ x + 1 , y - 1 ] # Down-Left
168+
169+ corners += 1 if cells . include? ( u ) && cells . include? ( r ) && !cells . include? ( ur )
170+ corners += 1 if cells . include? ( r ) && cells . include? ( d ) && !cells . include? ( dr )
171+ corners += 1 if cells . include? ( d ) && cells . include? ( l ) && !cells . include? ( dl )
172+ corners += 1 if cells . include? ( l ) && cells . include? ( u ) && !cells . include? ( ul )
173+ end
174+
175+ corners
176+ end
177+
178+ def calculate_price_area_perimeter
179+ total_price_perimeter = 0
180+ total_price_sides = 0
181+ @visited = Array . new ( @height ) { Array . new ( @width , false ) }
182+
183+ @height . times do |x |
184+ @width . times do |y |
185+ next if @visited [ x ] [ y ]
186+
187+ area , perimeter , sides = find_plot_BFS ( x , y )
188+ total_price_perimeter += area * perimeter
189+ total_price_sides += area * sides
190+ end
191+ end
192+
193+ [ total_price_perimeter , total_price_sides ]
134194 end
135195end
196+
0 commit comments