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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy