Skip to content

Commit 360dc68

Browse files
committed
day 14 part 1
1 parent e66e8d1 commit 360dc68

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.codefork.aoc2024.day14;
2+
3+
import com.codefork.aoc2024.Problem;
4+
import com.codefork.aoc2024.util.Assert;
5+
6+
import java.util.stream.Stream;
7+
8+
public class Part01 extends Problem {
9+
10+
public String solve(int width, int height, Stream<String> data) {
11+
var swarm = Swarm.create(data, width, height);
12+
var finalSwarm = swarm.doMoves(100);
13+
return String.valueOf(finalSwarm.getSafetyFactor());
14+
}
15+
16+
@Override
17+
public String solve() {
18+
Assert.assertEquals("12", solve(11, 7, getSampleInput()));
19+
return solve(101, 103, getInput());
20+
}
21+
22+
public static void main(String[] args) {
23+
new Part01().run();
24+
}
25+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package com.codefork.aoc2024.day14;
2+
3+
import com.codefork.aoc2024.util.Maps;
4+
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.regex.Pattern;
8+
import java.util.stream.Collectors;
9+
import java.util.stream.IntStream;
10+
import java.util.stream.Stream;
11+
12+
import static com.codefork.aoc2024.util.FoldLeft.foldLeft;
13+
14+
public record Swarm(List<Robot> robots, int width, int height) {
15+
16+
public record Position(int x, int y) {
17+
18+
}
19+
20+
public record Velocity(int dx, int dy) {
21+
22+
}
23+
24+
public record Robot(Position position, Velocity v) {
25+
}
26+
27+
private final static Pattern pat = Pattern.compile("p=([0-9]+),([0-9]+) v=([0-9\\-]+),([0-9\\-]+)");
28+
29+
public static Swarm create(Stream<String> data, int width, int height) {
30+
var robots = data
31+
.map(line -> {
32+
var matcher = pat.matcher(line);
33+
if (!matcher.find()) {
34+
throw new RuntimeException("couldn't parse line");
35+
}
36+
var parts = IntStream.range(1, 5)
37+
.mapToObj(matcher::group)
38+
.map(Integer::valueOf)
39+
.toList();
40+
return new Robot(new Position(parts.get(0), parts.get(1)), new Velocity(parts.get(2), parts.get(3)));
41+
})
42+
.toList();
43+
return new Swarm(robots, width, height);
44+
}
45+
46+
public Swarm doMoves(int n) {
47+
var finalRobots = IntStream.range(0, n)
48+
.boxed()
49+
.collect(foldLeft(
50+
() -> robots,
51+
(acc, i) -> {
52+
return acc.stream().map(this::move).toList();
53+
}
54+
));
55+
return new Swarm(finalRobots, width, height);
56+
}
57+
58+
public Robot move(Robot robot) {
59+
var changedX = robot.position().x() + robot.v().dx();
60+
var newX = changedX >= width ? changedX - width : (changedX < 0 ? changedX + width : changedX);
61+
var changedY = (robot.position().y() + robot.v().dy()) % height;
62+
var newY = changedY >= height ? changedY - height : (changedY < 0 ? changedY + height : changedY);
63+
return new Robot(new Position(newX, newY), robot.v());
64+
}
65+
66+
public void print() {
67+
var byPos = robots().stream().collect(Collectors.toMap(
68+
Robot::position,
69+
List::of,
70+
Maps::listConcat));
71+
for (var y = 0; y < height; y++) {
72+
for (var x = 0; x < width; x++) {
73+
var list = byPos.getOrDefault(new Position(x, y), List.of());
74+
var count = list.size();
75+
var ch = count > 0 ? String.valueOf(count) : ".";
76+
System.out.print(ch);
77+
}
78+
System.out.println();
79+
}
80+
}
81+
82+
private static int DISCARD = -1;
83+
84+
/**
85+
* quadrants are numbered in order from left to right, then top to bottom, like reading English
86+
* @return
87+
*/
88+
public Map<Integer, Integer> getQuadrantCounts() {
89+
var byQuadrant = robots.stream()
90+
.collect(Collectors.groupingBy(
91+
(robot) -> {
92+
if (robot.position().y() < height / 2) {
93+
if (robot.position().x() < width / 2) {
94+
return 0;
95+
} else if (robot.position().x() > width / 2) {
96+
return 1;
97+
}
98+
} else if (robot.position().y() > height / 2) {
99+
if (robot.position().x() < width / 2) {
100+
return 2;
101+
} else if (robot.position().x() > width / 2) {
102+
return 3;
103+
}
104+
}
105+
// put the robots on the center lines in a separate group
106+
// that we'll discard
107+
return DISCARD;
108+
})
109+
);
110+
return byQuadrant.entrySet().stream()
111+
.filter(entry -> entry.getKey() != DISCARD)
112+
.collect(Collectors.toMap(
113+
Map.Entry::getKey,
114+
entry -> entry.getValue().size(),
115+
Integer::sum
116+
));
117+
}
118+
119+
/**
120+
* testing for part 2: try smaller sections
121+
*/
122+
public Map<Integer, Integer> getCustomSectionCounts() {
123+
var byQuadrant = robots.stream()
124+
.collect(Collectors.groupingBy(
125+
(robot) -> {
126+
if (robot.position().y() < height / 3) {
127+
if (robot.position().x() < width / 2) {
128+
return 0;
129+
} else if (robot.position().x() > width / 2) {
130+
return 1;
131+
}
132+
} else if (robot.position().y() > height / 3 && robot.position().y() < (height / 3) * 2) {
133+
if (robot.position().x() < width / 2) {
134+
return 2;
135+
} else if (robot.position().x() > width / 2) {
136+
return 3;
137+
}
138+
} else if (robot.position().y() > (height / 3) * 2) {
139+
if (robot.position().x() < width / 2) {
140+
return 4;
141+
} else if (robot.position().x() > width / 2) {
142+
return 5;
143+
}
144+
}
145+
// put the robots on the center lines in a separate group
146+
// that we'll discard
147+
return DISCARD;
148+
})
149+
);
150+
return byQuadrant.entrySet().stream()
151+
.filter(entry -> entry.getKey() != DISCARD)
152+
.collect(Collectors.toMap(
153+
Map.Entry::getKey,
154+
entry -> {
155+
// count occupied positions rather than robots, since they can be stacked, and we only
156+
// care about what they look like from above
157+
record Pos(int x, int y) {
158+
}
159+
var list = entry.getValue();
160+
var occupiedPositions = list.stream()
161+
.map(robot -> new Pos(robot.position().x(), robot.position().y()))
162+
.collect(Collectors.toSet());
163+
return occupiedPositions.size();
164+
},
165+
Integer::sum
166+
));
167+
}
168+
169+
public int getSafetyFactor() {
170+
return getQuadrantCounts().entrySet().stream()
171+
.reduce(1, (acc, entry) -> acc * entry.getValue(), Integer::sum);
172+
}
173+
}

src/main/resources/day14/input

8.17 KB
Binary file not shown.

src/main/resources/day14/sample

182 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)