Skip to content

Commit 2be1db4

Browse files
committed
aoc 2024 day 21 & 22
1 parent e5f96d3 commit 2be1db4

File tree

22 files changed

+320
-181
lines changed

22 files changed

+320
-181
lines changed

adventofcode/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@
14541454
[20232402tests]: src/test/java/org/ck/adventofcode/year2023/Day24Test.java
14551455
[20232501tests]: src/test/java/org/ck/adventofcode/year2023/Day25Test.java
14561456

1457-
# 2024 (40/49)
1457+
# 2024 (44/49)
14581458

14591459
| # | Name | Solution | Test |
14601460
|---------:|-----------------------------------------------------|:------------------------------------:|:---------------------------------:|
@@ -1498,10 +1498,10 @@
14981498
| 20241902 | [Day 19: Linen Layout - Part 2][20241902] | ✅[💾][20241902solution] | ✅[💾][20241902tests] |
14991499
| 20242001 | [Day 20: Race Condition][20242001] | ✅[💾][20242001solution] | ✅[💾][20242001tests] |
15001500
| 20242002 | [Day 20: Race Condition - Part 2][20242002] | ✅[💾][20242002solution] | ✅[💾][20242002tests] |
1501-
| 20242101 | [Day 21: ?][20242101] | [💾][20242101solution] | [💾][20242101tests] |
1502-
| 20242102 | [Day 21: ? - Part 2][20242102] | [💾][20242102solution] | [💾][20242102tests] |
1503-
| 20242201 | [Day 22: ?][20242201] | [💾][20242201solution] | [💾][20242201tests] |
1504-
| 20242202 | [Day 22: ? - Part 2][20242202] | [💾][20242202solution] | [💾][20242202tests] |
1501+
| 20242101 | [Day 21: Keypad Conundrum][20242101] | ✅[💾][20242101solution] | ✅[💾][20242101tests] |
1502+
| 20242102 | [Day 21: Keypad Conundrum - Part 2][20242102] | ✅[💾][20242102solution] | ✅[💾][20242102tests] |
1503+
| 20242201 | [Day 22: Monkey Market][20242201] | ✅[💾][20242201solution] | ✅[💾][20242201tests] |
1504+
| 20242202 | [Day 22: Monkey Market - Part 2][20242202] | ✅[💾][20242202solution] | ✅[💾][20242202tests] |
15051505
| 20242301 | [Day 23: ?][20242301] | [💾][20242301solution] | [💾][20242301tests] |
15061506
| 20242302 | [Day 23: ? - Part 2][20242302] | [💾][20242302solution] | [💾][20242302tests] |
15071507
| 20242401 | [Day 24: ?][20242401] | [💾][20242401solution] | [💾][20242401tests] |
Lines changed: 214 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,237 @@
11
package org.ck.adventofcode.year2024;
22

3-
import java.util.Scanner;
3+
import java.util.*;
4+
import java.util.stream.Collectors;
5+
import java.util.stream.Stream;
46
import org.ck.adventofcode.util.AOCSolution;
57
import org.ck.codechallengelib.annotation.Solution;
68

79
@Solution(
810
id = 20242101,
9-
name = "Day 21: ?",
11+
name = "Day 21: Keypad Conundrum",
1012
url = "https://adventofcode.com/2024/day/21",
11-
category = "2024",
12-
solved = false)
13+
category = "2024")
1314
@Solution(
1415
id = 20242102,
15-
name = "Day 21: ? - Part 2",
16+
name = "Day 21: Keypad Conundrum - Part 2",
1617
url = "https://adventofcode.com/2024/day/21#part2",
17-
category = "2024",
18-
solved = false)
18+
category = "2024")
1919
public class Day21 extends AOCSolution {
20+
private static final Map<Character, Position> NUM_PAD = new HashMap<>();
21+
private static final Map<Character, Position> DIR_PAD = new HashMap<>();
22+
23+
static {
24+
initNumPadMovements();
25+
initDirPadMovements();
26+
}
27+
28+
private static void initNumPadMovements() {
29+
NUM_PAD.put('0', new Position(1, 0));
30+
NUM_PAD.put('1', new Position(0, 1));
31+
NUM_PAD.put('2', new Position(1, 1));
32+
NUM_PAD.put('3', new Position(2, 1));
33+
NUM_PAD.put('4', new Position(0, 2));
34+
NUM_PAD.put('5', new Position(1, 2));
35+
NUM_PAD.put('6', new Position(2, 2));
36+
NUM_PAD.put('7', new Position(0, 3));
37+
NUM_PAD.put('8', new Position(1, 3));
38+
NUM_PAD.put('9', new Position(2, 3));
39+
NUM_PAD.put('A', new Position(2, 0));
40+
}
41+
42+
private static void initDirPadMovements() {
43+
DIR_PAD.put('^', new Position(1, 1));
44+
DIR_PAD.put('<', new Position(0, 0));
45+
DIR_PAD.put('v', new Position(1, 0));
46+
DIR_PAD.put('>', new Position(2, 0));
47+
DIR_PAD.put('A', new Position(2, 1));
48+
}
2049

2150
@Override
2251
protected void runPartOne(final Scanner in) {
23-
run(in);
52+
run(in, 2);
2453
}
2554

2655
@Override
2756
protected void runPartTwo(final Scanner in) {
28-
run(in);
57+
run(in, 25);
2958
}
3059

31-
private void run(final Scanner in) {
32-
print("Whoopsie");
60+
private void run(final Scanner in, final int intermediateRobots) {
61+
final List<String> codes = new ArrayList<>();
62+
while (in.hasNextLine()) {
63+
codes.add(in.nextLine());
64+
}
65+
66+
long result = 0;
67+
for (String code : codes) {
68+
Position currentPosition = NUM_PAD.get('A');
69+
final StringBuilder keyPresses = new StringBuilder();
70+
71+
for (char c : code.toCharArray()) {
72+
final Position nextPosition = NUM_PAD.get(c);
73+
keyPresses.append(getKeyPresses(currentPosition, nextPosition));
74+
keyPresses.append('A');
75+
76+
currentPosition = nextPosition;
77+
}
78+
79+
final Map<CacheKey, Long> cache = new HashMap<>();
80+
81+
char current = 'A';
82+
long length = 0;
83+
for (final char next : "%sA".formatted(keyPresses).toCharArray()) {
84+
length += getKeyPresses(current, next, cache, intermediateRobots - 1);
85+
current = next;
86+
}
87+
88+
result += (length - 1) * Long.parseLong(code.replaceAll("\\D", ""));
89+
}
90+
91+
print(result);
3392
}
93+
94+
private long getKeyPresses(
95+
final char one, final char two, final Map<CacheKey, Long> cache, int depth) {
96+
final CacheKey cacheKey = new CacheKey(one, two, depth);
97+
98+
if (cache.containsKey(cacheKey)) {
99+
return cache.get(cacheKey);
100+
}
101+
102+
final Set<String> presses = getCombos(DIR_PAD.get(one), DIR_PAD.get(two), 1);
103+
104+
if (depth == 0) {
105+
return presses.stream().findFirst().orElseThrow().length();
106+
}
107+
108+
long min = Long.MAX_VALUE;
109+
110+
for (final String press : presses) {
111+
char current = 'A';
112+
long result = 0;
113+
for (final char next : "%sA".formatted(press).toCharArray()) {
114+
result += getKeyPresses(current, next, cache, depth - 1);
115+
current = next;
116+
}
117+
118+
min = Math.min(min, result);
119+
}
120+
121+
cache.put(cacheKey, min - 1);
122+
return min - 1;
123+
}
124+
125+
private Set<String> getCombos(
126+
final Position currentPosition, final Position nextPosition, final int invalidKeyY) {
127+
final List<Character> keyPresses = new ArrayList<>();
128+
129+
final int xDiff = currentPosition.x() - nextPosition.x();
130+
final int yDiff = currentPosition.y() - nextPosition.y();
131+
132+
for (int i = yDiff; i < 0; ++i) {
133+
keyPresses.add('^');
134+
}
135+
136+
for (int i = 0; i < yDiff; ++i) {
137+
keyPresses.add('v');
138+
}
139+
140+
for (int i = xDiff; i < 0; ++i) {
141+
keyPresses.add('>');
142+
}
143+
144+
for (int i = 0; i < xDiff; ++i) {
145+
keyPresses.add('<');
146+
}
147+
148+
return shuffle(keyPresses).stream()
149+
.filter(
150+
keys -> {
151+
if (currentPosition.y() == invalidKeyY
152+
&& xDiff != 0
153+
&& nextPosition.x() == 0
154+
&& keys.startsWith("<".repeat(xDiff))) {
155+
return false;
156+
}
157+
158+
return !(currentPosition.x() == 0
159+
&& nextPosition.y() == invalidKeyY
160+
&& (keys.startsWith("^") || keys.startsWith("v")));
161+
})
162+
.collect(Collectors.toSet());
163+
}
164+
165+
private Set<String> shuffle(final List<Character> chars) {
166+
if (chars.isEmpty()) {
167+
return Set.of("A");
168+
}
169+
170+
if (chars.size() == 1) {
171+
return Set.of(chars.getFirst() + "A");
172+
}
173+
174+
Set<String> result = new HashSet<>();
175+
176+
for (int i = 0; i < chars.size(); ++i) {
177+
final List<Character> remaining =
178+
Stream.concat(chars.stream().limit(i), chars.stream().skip(i + 1L)).toList();
179+
180+
Set<String> others = shuffle(remaining);
181+
for (String other : others) {
182+
result.add(chars.get(i) + other);
183+
}
184+
}
185+
186+
return result;
187+
}
188+
189+
private String getKeyPresses(final Position currentPosition, final Position nextPosition) {
190+
final StringBuilder keyPresses = new StringBuilder();
191+
192+
final int xDiff = currentPosition.x() - nextPosition.x();
193+
final int yDiff = currentPosition.y() - nextPosition.y();
194+
195+
if (currentPosition.y() == 0 && nextPosition.x() == 0) {
196+
if (yDiff < 0) {
197+
keyPresses.append("^".repeat(-1 * yDiff));
198+
}
199+
200+
if (yDiff > 0) {
201+
keyPresses.append("v".repeat(yDiff));
202+
}
203+
204+
if (xDiff > 0) {
205+
keyPresses.append("<".repeat(xDiff));
206+
}
207+
208+
if (xDiff < 0) {
209+
keyPresses.append(">".repeat(-1 * xDiff));
210+
}
211+
212+
return keyPresses.toString();
213+
}
214+
215+
if (xDiff > 0) {
216+
keyPresses.append("<".repeat(xDiff));
217+
}
218+
219+
if (yDiff < 0) {
220+
keyPresses.append("^".repeat(-1 * yDiff));
221+
}
222+
223+
if (yDiff > 0) {
224+
keyPresses.append("v".repeat(yDiff));
225+
}
226+
227+
if (xDiff < 0) {
228+
keyPresses.append(">".repeat(-1 * xDiff));
229+
}
230+
231+
return keyPresses.toString();
232+
}
233+
234+
private record CacheKey(char start, char end, int depth) {}
235+
236+
private record Position(int x, int y) {}
34237
}
Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,99 @@
11
package org.ck.adventofcode.year2024;
22

3-
import java.util.Scanner;
3+
import java.util.*;
4+
import java.util.function.Function;
45
import org.ck.adventofcode.util.AOCSolution;
56
import org.ck.codechallengelib.annotation.Solution;
67

78
@Solution(
89
id = 20242201,
9-
name = "Day 22: ?",
10+
name = "Day 22: Monkey Market",
1011
url = "https://adventofcode.com/2024/day/22",
11-
category = "2024",
12-
solved = false)
12+
category = "2024")
1313
@Solution(
1414
id = 20242202,
15-
name = "Day 22: ? - Part 2",
15+
name = "Day 22: Monkey Market - Part 2",
1616
url = "https://adventofcode.com/2024/day/22#part2",
17-
category = "2024",
18-
solved = false)
17+
category = "2024")
1918
public class Day22 extends AOCSolution {
2019

2120
@Override
2221
protected void runPartOne(final Scanner in) {
23-
run(in);
22+
run(in, secrets -> secrets.stream().mapToLong(List::getLast).sum());
2423
}
2524

2625
@Override
2726
protected void runPartTwo(final Scanner in) {
28-
run(in);
27+
run(in, Day22::getPart2Result);
2928
}
3029

31-
private void run(final Scanner in) {
32-
print("Whoopsie");
30+
private void run(final Scanner in, final Function<List<List<Long>>, Long> getResult) {
31+
final List<List<Long>> secrets = new ArrayList<>();
32+
33+
while (in.hasNextLine()) {
34+
final List<Long> newSecrets = new ArrayList<>();
35+
newSecrets.add(Long.parseLong(in.nextLine()));
36+
37+
for (int i = 0; i < 2000; i++) {
38+
newSecrets.add(getNextNumber(newSecrets.getLast()));
39+
}
40+
41+
secrets.add(newSecrets);
42+
}
43+
44+
print(getResult.apply(secrets));
45+
}
46+
47+
private long getNextNumber(final long number) {
48+
long result = ((number * 64) ^ number) % 16777216;
49+
result = ((result / 32) ^ result) % 16777216;
50+
result = ((result * 2048) ^ result) % 16777216;
51+
52+
return result;
3353
}
54+
55+
private static long getPart2Result(List<List<Long>> lists) {
56+
final Map<Sequence, Long> possiblePrices = new HashMap<>();
57+
58+
for (final List<Long> buyerSecrets : lists) {
59+
final List<Price> prices = getPrices(buyerSecrets);
60+
final Set<Sequence> seen = new HashSet<>();
61+
62+
for (int i = 0; i < prices.size() - 3; i++) {
63+
final Sequence sequence =
64+
new Sequence(
65+
prices.get(i).change(),
66+
prices.get(i + 1).change(),
67+
prices.get(i + 2).change(),
68+
prices.get(i + 3).change());
69+
70+
if (!seen.contains(sequence)) {
71+
seen.add(sequence);
72+
possiblePrices.put(
73+
sequence, possiblePrices.getOrDefault(sequence, 0L) + prices.get(i + 3).price());
74+
}
75+
}
76+
}
77+
78+
return possiblePrices.entrySet().stream()
79+
.max(Comparator.comparingLong(Map.Entry::getValue))
80+
.orElseThrow()
81+
.getValue();
82+
}
83+
84+
private static List<Price> getPrices(final List<Long> buyerSecrets) {
85+
final List<Price> prices = new ArrayList<>();
86+
87+
for (int i = 1; i < buyerSecrets.size(); ++i) {
88+
prices.add(
89+
new Price(
90+
buyerSecrets.get(i) % 10, buyerSecrets.get(i) % 10 - buyerSecrets.get(i - 1) % 10));
91+
}
92+
93+
return prices;
94+
}
95+
96+
private record Price(long price, long change) {}
97+
98+
private record Sequence(long one, long two, long three, long four) {}
3499
}

0 commit comments

Comments
 (0)