Skip to content

Commit 42ff1ed

Browse files
committed
feat: solve day 12 part 1, part 2 WIP
1 parent bd6166f commit 42ff1ed

File tree

5 files changed

+415
-8
lines changed

5 files changed

+415
-8
lines changed

src/main/java/com/adventofcode/flashk/day12/GardenGroups.java

Lines changed: 346 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
public 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

src/test/java/com/adventofcode/flashk/common/test/constants/TestDisplayName.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ private TestDisplayName() {}
3737
public static final String PART_1_DEBUG = "Part 1 - Debug";
3838
public static final String PART_2_SAMPLE = "Part 2 - Sample data";
3939
public static final String PART_2_INPUT = "Part 2 - Input data";
40+
public static final String PART_2_SAMPLE_2 = "Part 2 - Sample 2";
41+
public static final String PART_2_SAMPLE_3 = "Part 2 - Sample 3";
42+
public static final String PART_2_SAMPLE_4 = "Part 2 - Sample 4";
4043
public static final String PART_2_DEBUG = "Part 2 - Debug";
4144

4245
public static final String PART_ONE_SINGLE_SAMPLE = "Part 1 - Single sample data";

0 commit comments

Comments
 (0)