99
1010public class GardenGroups {
1111
12- private int rows ;
13- private int cols ;
14- private GardenPlot [][] map ;
12+ private final int rows ;
13+ private final int cols ;
14+ private final GardenPlot [][] map ;
1515 private final Map <Integer , Integer > regionAreas = new HashMap <>();
16+ private final Map <Integer , Integer > regionSides = new HashMap <>();
17+ private final Map <Integer , Set <GardenPlot >> regionPlots = new HashMap <>();
1618
1719 public GardenGroups (char [][] inputs ) {
1820
@@ -35,16 +37,355 @@ public long solveA() {
3537
3638 public long solveB () {
3739 findRegions ();
40+
41+ long price = 0 ;
42+ // Para cada región, calculamos cuantos lados tiene
43+ System .out .println ("Region | Sides" );
44+ for (Set <GardenPlot > gardenPlots : regionPlots .values ()) {
45+ int sides = calculateRegionSides (gardenPlots );
46+ regionSides .put (gardenPlots .stream ().findFirst ().get ().getRegionId (), sides );
47+ //price += regionAreas.get(gardenPlots.stream().findFirst().get().getRegionId()) * sides;
48+ //System.out.println(gardenPlots.stream().findFirst().get().getPlant()+" | "+sides);
49+ }
50+
3851 // TODO calculate sides of each region
3952 // then calculate price
40- return 0L ;
53+
54+ for (Integer regionId : regionAreas .keySet ()) {
55+ price += regionAreas .get (regionId ) * regionSides .get (regionId );
56+ }
57+
58+ return price ;
59+ }
60+
61+ private int calculateRegionSides (Set <GardenPlot > gardenPlots ) {
62+ // Número de lados en un polígono irregular es:
63+ // nº lados = (suma de los ángulos interiores / 180) + 2
64+ // Por ejemplo, un polígono con forma de "L" tiene 5 ángulos internos de 90º y uno más de 270º, lo que suma 720º.
65+ // Por lo tanto, el número de lados es (720 / 180) + 2 = 6.
66+
67+ // Problema: encontrar todos los ángulos interiores de cada región.
68+
69+ // Cualquier plot del polígono puede tener estos casos:
70+ // - No tiene ángulos
71+ // - Tiene ángulos
72+
73+ // Para determinar si hay ángulos, examinamos para cada región sus plots.
74+ //
75+ // Para cada plot hay que mirar los plots adyacentes:
76+ // - Si los dos adyacentes son de la misma región pero el diagonal es de otra región, entonces hay un ángulo
77+ // interior de 270 en dicha esquina.
78+ // - Si los dos adyacentes son de otra región, independientemente de la diagonal, hay un ángulo interior de 90º
79+ // - En el resto de casos, no hay ángulos.
80+
81+ int angles = 0 ;
82+
83+ for (GardenPlot gardenPlot : gardenPlots ) {
84+ angles += sumExternalAngles (gardenPlot );
85+ angles += sumInternalAngles (gardenPlot ); // TODO descomenta esto para resultado final
86+ }
87+
88+ // https://www.sciencing.com/how-to-find-the-number-of-sides-of-a-polygon-12751688/
89+ return (angles / 180 ) + 2 ;
90+ }
91+
92+ private int sumInternalAngles (GardenPlot gardenPlot ) {
93+ int angles = 0 ;
94+
95+ if (hasUpLeftInternalAngle (gardenPlot )) {
96+ angles += 270 ;
97+ }
98+
99+ if (hasUpRightInternalAngle (gardenPlot )) {
100+ angles += 270 ;
101+ }
102+
103+ if (hasDownLeftInternalAngle (gardenPlot )) {
104+ angles += 270 ;
105+ }
106+
107+ if (hasDownRightInternalAngle (gardenPlot )) {
108+ angles += 270 ;
109+ }
110+
111+ return angles ;
112+
113+ }
114+
115+ private boolean hasUpLeftInternalAngle (GardenPlot gardenPlot ) {
116+
117+ // Get adjacent up and left
118+ Vector2 upPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .down ());
119+ Vector2 leftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .left ());
120+
121+ // Garden plot is at top or left corner of the map
122+ if (!isInbounds (leftPos )) {
123+ return false ;
124+ }
125+
126+ if (!isInbounds (upPos )) {
127+ return false ;
128+ }
129+
130+ Vector2 upLeftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .downLeft ());
131+
132+ // If diagonal is the same region, there is no internal angle
133+ if (map [upLeftPos .getY ()][upLeftPos .getX ()].getRegionId () == gardenPlot .getRegionId ()) {
134+ return false ;
135+ }
136+
137+ // Garden plot is at any other position of the map
138+ return (map [leftPos .getY ()][leftPos .getX ()].getRegionId () == gardenPlot .getRegionId () &&
139+ map [upPos .getY ()][upPos .getX ()].getRegionId () == gardenPlot .getRegionId ());
140+
141+ }
142+
143+ private boolean hasUpRightInternalAngle (GardenPlot gardenPlot ) {
144+
145+ // Get adjacent up and right
146+ Vector2 upPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .down ());
147+ Vector2 rightPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .right ());
148+
149+ // Garden plot is at top or right corner of the map
150+ if (!isInbounds (rightPos )) {
151+ return false ;
152+ }
153+
154+ if (!isInbounds (upPos )) {
155+ return false ;
156+ }
157+
158+ Vector2 upRightPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .downRight ());
159+
160+ // If diagonal is the same region, there is no internal angle
161+ if (map [upRightPos .getY ()][upRightPos .getX ()].getRegionId () == gardenPlot .getRegionId ()) {
162+ return false ;
163+ }
164+
165+ // Garden plot is at any other position of the map
166+ return (map [rightPos .getY ()][rightPos .getX ()].getRegionId () == gardenPlot .getRegionId () &&
167+ map [upPos .getY ()][upPos .getX ()].getRegionId () == gardenPlot .getRegionId ());
168+
169+ }
170+
171+ private boolean hasDownLeftInternalAngle (GardenPlot gardenPlot ) {
172+ // Get adjacent down and left
173+ Vector2 downPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .up ());
174+ Vector2 leftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .left ());
175+
176+ // Garden plot is at bottom or left corner of the map
177+ if (!isInbounds (leftPos )) {
178+ return false ;
179+ }
180+
181+ if (!isInbounds (downPos )) {
182+ return false ;
183+ }
184+
185+ Vector2 downLeftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .upLeft ());
186+
187+ // If diagonal is the same region, there is no internal angle
188+ if (map [downLeftPos .getY ()][downLeftPos .getX ()].getRegionId () == gardenPlot .getRegionId ()) {
189+ return false ;
190+ }
191+
192+ // Garden plot is at any other position of the map
193+ return (map [leftPos .getY ()][leftPos .getX ()].getRegionId () == gardenPlot .getRegionId () &&
194+ map [downPos .getY ()][downPos .getX ()].getRegionId () == gardenPlot .getRegionId ());
195+ }
196+
197+ private boolean hasDownRightInternalAngle (GardenPlot gardenPlot ) {
198+ // Get adjacent down and right
199+ Vector2 downPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .up ());
200+ Vector2 rightPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .right ());
201+
202+ // Garden plot is at bottom or right corner of the map
203+ if (!isInbounds (rightPos )) {
204+ return false ;
205+ }
206+
207+ if (!isInbounds (downPos )) {
208+ return false ;
209+ }
210+
211+ Vector2 upLeftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .upRight ());
212+
213+ // If diagonal is the same region, there is no internal angle
214+ if (map [upLeftPos .getY ()][upLeftPos .getX ()].getRegionId () == gardenPlot .getRegionId ()) {
215+ return false ;
216+ }
217+
218+ // Garden plot is at any other position of the map
219+ return (map [rightPos .getY ()][rightPos .getX ()].getRegionId () == gardenPlot .getRegionId () &&
220+ map [downPos .getY ()][downPos .getX ()].getRegionId () == gardenPlot .getRegionId ());
221+ }
222+
223+ private int sumExternalAngles (GardenPlot gardenPlot ) {
224+
225+ int angles = 0 ;
226+
227+ if (hasUpLeftExternalAngle (gardenPlot )) {
228+ angles += 90 ;
229+ }
230+
231+ if (hasUpRightExternalAngle (gardenPlot )) {
232+ angles += 90 ;
233+ }
234+
235+ if (hasDownLeftExternalAngle (gardenPlot )) {
236+ angles += 90 ;
237+ }
238+
239+ if (hasDownRightExternalAngle (gardenPlot )) {
240+ angles += 90 ;
241+ }
242+
243+ return angles ;
41244 }
42245
246+ private boolean hasUpLeftExternalAngle (GardenPlot gardenPlot ) {
247+
248+ // Get adjacent up and left
249+ Vector2 upPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .down ());
250+ Vector2 leftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .left ());
251+
252+ // Garden plot is at top-left corner of the map
253+ if (!isInbounds (upPos ) && !isInbounds (leftPos )) {
254+ return true ;
255+ }
256+
257+ // Garden plot is at left side of the map
258+ if (!isInbounds (leftPos ) && isInbounds (upPos ) &&
259+ map [upPos .getY ()][upPos .getX ()].getRegionId () != gardenPlot .getRegionId ()) {
260+ return true ;
261+ }
262+
263+ // Garden plot is at top side of the map
264+ if ((!isInbounds (upPos ) && isInbounds (leftPos )) &&
265+ map [leftPos .getY ()][leftPos .getX ()].getRegionId () != gardenPlot .getRegionId ()) {
266+ return true ;
267+ }
268+
269+ Vector2 diagonalPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .downLeft ());
270+
271+ return (isInbounds (upPos ) &&
272+ isInbounds (leftPos ) &&
273+ isInbounds (diagonalPos ) &&
274+ map [upPos .getY ()][upPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
275+ map [leftPos .getY ()][leftPos .getX ()].getRegionId () != gardenPlot .getRegionId ()) &&
276+ map [diagonalPos .getY ()][diagonalPos .getX ()].getRegionId () != gardenPlot .getRegionId ();
277+
278+ }
279+
280+ private boolean hasUpRightExternalAngle (GardenPlot gardenPlot ) {
281+
282+ // Get adjacent up and right
283+ Vector2 upPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .down ());
284+ Vector2 rightPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .right ());
285+
286+ // Garden plot is at a corner of the map
287+ if (!isInbounds (upPos ) && !isInbounds (rightPos )) {
288+ return true ;
289+ }
290+
291+ // Garden plot is at the right side of the map
292+ if (isInbounds (upPos ) && !isInbounds (rightPos ) &&
293+ map [upPos .getY ()][upPos .getX ()].getRegionId () != gardenPlot .getRegionId ()) {
294+ return true ;
295+ }
296+
297+ // Garden plot is at top side of the map
298+ if ((!isInbounds (upPos ) && isInbounds (rightPos )) &&
299+ map [rightPos .getY ()][rightPos .getX ()].getRegionId () != gardenPlot .getRegionId ()) {
300+ return true ;
301+ }
302+
303+ Vector2 diagonalPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .downRight ());
304+
305+ // Garden plot is at any other position of the map
306+ return (isInbounds (rightPos ) &&
307+ isInbounds (upPos ) &&
308+ map [rightPos .getY ()][rightPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
309+ map [upPos .getY ()][upPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
310+ map [diagonalPos .getY ()][diagonalPos .getX ()].getRegionId () != gardenPlot .getRegionId ());
311+
312+ }
313+
314+ private boolean hasDownLeftExternalAngle (GardenPlot gardenPlot ) {
315+
316+ // Get adjacent up and left
317+ Vector2 downPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .up ());
318+ Vector2 leftPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .left ());
319+
320+ // Garden plot is at bottom-left corner of the map
321+ if (!isInbounds (downPos ) && !isInbounds (leftPos )) {
322+ return true ;
323+ }
324+
325+ // Garden plot is at left side of the map
326+ if (isInbounds (downPos ) && map [downPos .getY ()][downPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
327+ (!isInbounds (leftPos ))) {
328+ return true ;
329+ }
330+
331+ // Garden plot is at bottom side of the map
332+ if (isInbounds (leftPos ) && map [leftPos .getY ()][leftPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
333+ (!isInbounds (downPos ))) {
334+ return true ;
335+ }
336+
337+ Vector2 diagonalPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .upLeft ());
338+
339+ // Garden plot is at any other position of the map
340+ return (isInbounds (leftPos ) &&
341+ isInbounds (downPos )&&
342+ map [leftPos .getY ()][leftPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
343+ map [downPos .getY ()][downPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
344+ map [diagonalPos .getY ()][diagonalPos .getX ()].getRegionId () != gardenPlot .getRegionId ());
345+
346+ }
347+
348+ private boolean hasDownRightExternalAngle (GardenPlot gardenPlot ) {
349+
350+ // Get adjacent down and right
351+ Vector2 downPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .up ());
352+ Vector2 rightPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .right ());
353+
354+ // Garden plot is at bottom-right corner of the map
355+ if (!isInbounds (downPos ) && !isInbounds (rightPos )) {
356+ return true ;
357+ }
358+
359+ // Garden plot is at right side of the map
360+ if (isInbounds (downPos ) && map [downPos .getY ()][downPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
361+ (!isInbounds (rightPos ))) {
362+ return true ;
363+ }
364+
365+ // Garden plot is at bottom side of the map
366+ if (isInbounds (rightPos ) && map [rightPos .getY ()][rightPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
367+ (!isInbounds (downPos ))) {
368+ return true ;
369+ }
370+
371+ Vector2 diagonalPos = Vector2 .transform (gardenPlot .getPosition (), Vector2 .upRight ());
372+
373+ // Garden plot is at any other position of the map
374+ return (isInbounds (rightPos ) &&
375+ isInbounds (downPos ) &&
376+ map [rightPos .getY ()][rightPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
377+ map [downPos .getY ()][downPos .getX ()].getRegionId () != gardenPlot .getRegionId () &&
378+ map [diagonalPos .getY ()][diagonalPos .getX ()].getRegionId () != gardenPlot .getRegionId ());
379+
380+ }
381+
382+
43383 private void findRegions () {
44384 int regionId = 1 ;
45385 for (int row = 0 ; row < rows ; row ++) {
46386 for (int col = 0 ; col < cols ; col ++) {
47387 if (!map [row ][col ].hasRegion ()) {
388+ regionPlots .put (regionId , new HashSet <>());
48389 int regionArea = findRegion (map [row ][col ], map [row ][col ].getPlant (), regionId );
49390 regionAreas .put (regionId , regionArea );
50391 regionId ++;
@@ -71,6 +412,7 @@ private int findRegion(GardenPlot gardenPlot, char plant, int regionId) {
71412 int area = 1 ;
72413 gardenPlot .setVisited (true );
73414 gardenPlot .setRegionId (regionId );
415+ regionPlots .get (regionId ).add (gardenPlot );
74416
75417 Set <GardenPlot > adjacentPlots = getAdjacentPlots (gardenPlot );
76418
0 commit comments