Skip to content

Commit fdde568

Browse files
aoc 2024 day 12 part 1
1 parent 5491ca5 commit fdde568

File tree

5 files changed

+125
-2
lines changed

5 files changed

+125
-2
lines changed

src/main/java/dev/jacobandersen/codechallenges/challenge/adventofcode/year2024/Year2024.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day1.Day1;
55
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day10.Day10;
66
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day11.Day11;
7+
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day12.Day12;
78
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day2.Day2;
89
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day3.Day3;
910
import dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day4.Day4;
@@ -28,7 +29,8 @@ public static List<Day> getDays() {
2829
new Day8(),
2930
new Day9(),
3031
new Day10(),
31-
new Day11()
32+
new Day11(),
33+
new Day12()
3234
);
3335
}
3436
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package dev.jacobandersen.codechallenges.challenge.adventofcode.year2024.day12;
2+
3+
import dev.jacobandersen.codechallenges.challenge.adventofcode.Day;
4+
import dev.jacobandersen.codechallenges.util.Direction;
5+
import dev.jacobandersen.codechallenges.util.Grid;
6+
import dev.jacobandersen.codechallenges.util.Pair;
7+
8+
import java.util.*;
9+
import java.util.List;
10+
import java.util.stream.Collectors;
11+
12+
public class Day12 extends Day {
13+
public Day12() {
14+
super(2024, 12, "Garden Groups");
15+
}
16+
17+
private boolean isInRegion(List<Region> regions, int y, int x) {
18+
return regions.stream().anyMatch(rg -> rg.plots.stream().anyMatch(plot -> plot.y == y && plot.x == x));
19+
}
20+
21+
private void exploreFrom(Grid<String> grid, Plot plot, Region region) {
22+
if (region.plots.contains(plot)) return; // don't backtrack
23+
24+
region.plots.add(plot);
25+
26+
Grid<String> local = grid.copy();
27+
for (Direction direction : Direction.cardinalValues()) {
28+
final String peek = local.peek(direction);
29+
if (peek != null && peek.equals(plot.crop)) {
30+
local.move(direction);
31+
exploreFrom(local, new Plot(plot.crop, local.getCurrentRow(), local.getCurrentCol()), region);
32+
local.move(direction.getOpposite());
33+
}
34+
}
35+
}
36+
37+
private List<Region> explore(Grid<String> grid) {
38+
List<Region> regions = new ArrayList<>();
39+
40+
for (int y = 0; y < grid.getRows(); y++) {
41+
for (int x = 0; x < grid.getCols(); x++) {
42+
grid.move(y, x);
43+
if (isInRegion(regions, y, x)) continue;
44+
45+
Region region = new Region(new ArrayList<>());
46+
exploreFrom(grid, new Plot(grid.get(), y, x), region);
47+
regions.add(region);
48+
}
49+
}
50+
51+
return regions;
52+
}
53+
54+
private Grid<String> loadGrid() {
55+
return Grid.create(getInputLinesStreamNoBlanks(), str -> Arrays.stream(str.split("")).toList());
56+
}
57+
58+
@Override
59+
public String partOne() {
60+
return String.valueOf(
61+
explore(loadGrid()).stream().mapToInt(Region::fencePrice).sum()
62+
);
63+
}
64+
65+
@Override
66+
public String partTwo() {
67+
Grid<String> grid = loadGrid();
68+
List<Region> regions = explore(grid);
69+
return String.valueOf(
70+
regions.stream().mapToInt(Region::discountedFencePrice).sum()
71+
);
72+
}
73+
74+
record Plot(String crop, int y, int x) {
75+
}
76+
77+
record Region(List<Plot> plots) {
78+
public int area() {
79+
return plots.size();
80+
}
81+
82+
public int perimeter() {
83+
final Set<Pair<Integer, Integer>> points = plots.stream().map(plot -> Pair.of(plot.y, plot.x)).collect(Collectors.toSet());
84+
return points.stream().mapToInt(pt -> {
85+
int perimeter = 4;
86+
for (final Direction direction : Direction.cardinalValues()) {
87+
final Pair<Integer, Integer> rel = direction.relativeCoordinate();
88+
final Pair<Integer, Integer> neighbor = Pair.of(pt.first() + rel.first(), pt.second() + rel.second());
89+
if (points.contains(neighbor)) perimeter--;
90+
}
91+
return perimeter;
92+
}).sum();
93+
}
94+
95+
public int fencePrice() {
96+
return area() * perimeter();
97+
}
98+
99+
public int sides() {
100+
return 0;
101+
}
102+
103+
public int discountedFencePrice() {
104+
return area() * sides();
105+
}
106+
}
107+
}

src/main/java/dev/jacobandersen/codechallenges/util/Direction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ public final Direction getOpposite() {
3333
};
3434
}
3535

36+
public final Direction getCardinalLeft() {
37+
return switch (this) {
38+
case NORTH -> WEST;
39+
case WEST -> SOUTH;
40+
case SOUTH -> EAST;
41+
case EAST -> NORTH;
42+
default -> this;
43+
};
44+
}
45+
3646
public final Direction getCardinalRight() {
3747
return switch (this) {
3848
case NORTH -> EAST;

src/main/java/dev/jacobandersen/codechallenges/util/Grid.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ public Grid<T> copy() {
209209
return new Grid<>(rows, cols, currentRow, currentCol, copy);
210210
}
211211

212+
public boolean contains(Pair<Integer, Integer> position) {
213+
return position.first() >= 0 && position.first() < rows && position.second() >= 0 && position.second() < cols;
214+
}
215+
212216
@Override
213217
public String toString() {
214218
StringBuilder builder = new StringBuilder("Grid {\n" +

src/main/resources/inputdata

0 commit comments

Comments
 (0)