Skip to content

Commit 2bb2a4f

Browse files
committed
more aoc
1 parent caf1869 commit 2bb2a4f

File tree

19 files changed

+501
-200
lines changed

19 files changed

+501
-200
lines changed

adventofcode/README.md

Lines changed: 4 additions & 4 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 (46/49)
1457+
# 2024 (48/49)
14581458

14591459
| # | Name | Solution | Test |
14601460
|---------:|-----------------------------------------------------|:------------------------------------:|:---------------------------------:|
@@ -1504,9 +1504,9 @@
15041504
| 20242202 | [Day 22: Monkey Market - Part 2][20242202] | ✅[💾][20242202solution] | ✅[💾][20242202tests] |
15051505
| 20242301 | [Day 23: LAN Party][20242301] | ✅[💾][20242301solution] | ✅[💾][20242301tests] |
15061506
| 20242302 | [Day 23: LAN Party - Part 2][20242302] | ✅[💾][20242302solution] | ✅[💾][20242302tests] |
1507-
| 20242401 | [Day 24: ?][20242401] | [💾][20242401solution] | [💾][20242401tests] |
1508-
| 20242402 | [Day 24: ? - Part 2][20242402] | [💾][20242402solution] | [💾][20242402tests] |
1509-
| 20242501 | [Day 25: ?][20242501] | [💾][20242501solution] | [💾][20242501tests] |
1507+
| 20242401 | [Day 24: Crossed Wires][20242401] | ✅[💾][20242401solution] | ✅[💾][20242401tests] |
1508+
| 20242402 | [Day 24: Crossed Wires - Part 2][20242402] | [💾][20242402solution] | [💾][20242402tests] |
1509+
| 20242501 | [Day 25: Code Chronicle][20242501] | ✅[💾][20242501solution] | ✅[💾][20242501tests] |
15101510

15111511
[20240101]: https://adventofcode.com/2024/day/1
15121512
[20240102]: https://adventofcode.com/2024/day/1#part2
Lines changed: 209 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
package org.ck.adventofcode.year2024;
22

3-
import java.util.Scanner;
3+
import java.util.*;
4+
import java.util.function.BinaryOperator;
5+
import java.util.function.Consumer;
6+
import java.util.regex.Matcher;
7+
import java.util.regex.Pattern;
8+
import java.util.stream.Collectors;
49
import org.ck.adventofcode.util.AOCSolution;
510
import org.ck.codechallengelib.annotation.Solution;
611

712
@Solution(
813
id = 20242401,
9-
name = "Day 24: ?",
14+
name = "Day 24: Crossed Wires",
1015
url = "https://adventofcode.com/2024/day/24",
11-
category = "2024",
12-
solved = false)
16+
category = "2024")
1317
@Solution(
1418
id = 20242402,
15-
name = "Day 24: ? - Part 2",
19+
name = "Day 24: Crossed Wires - Part 2",
1620
url = "https://adventofcode.com/2024/day/24#part2",
1721
category = "2024",
1822
solved = false)
1923
public class Day24 extends AOCSolution {
24+
private static final Pattern PATTERN =
25+
Pattern.compile(
26+
"(?<one>[a-z0-9]+) (?<type>XOR|AND|OR) (?<two>[a-z0-9]+) -> (?<result>[a-z0-9]+)");
2027

2128
@Override
2229
protected void runPartOne(final Scanner in) {
@@ -25,10 +32,205 @@ protected void runPartOne(final Scanner in) {
2532

2633
@Override
2734
protected void runPartTwo(final Scanner in) {
28-
run(in);
35+
run2(in);
36+
}
37+
38+
private void run2(final Scanner in) {
39+
final Map<String, Boolean> initialValues = new HashMap<>();
40+
final Map<String, Boolean> outputs = new HashMap<>();
41+
final List<String> rawGates = new ArrayList<>();
42+
43+
while (in.hasNextLine()) {
44+
final String[] line = in.nextLine().split(": ");
45+
46+
if (line.length == 1) {
47+
break;
48+
}
49+
50+
initialValues.put(line[0], "1".equals(line[1]));
51+
}
52+
53+
final List<String> inputWires =
54+
initialValues.keySet().stream()
55+
.map(inputWire -> inputWire.substring(1))
56+
.sorted()
57+
.distinct()
58+
.toList();
59+
60+
while (in.hasNextLine()) {
61+
rawGates.add(in.nextLine());
62+
}
63+
64+
long x = 0;
65+
long y = 0;
66+
for (final String inputWire : inputWires) {
67+
x <<= 1;
68+
y <<= 1;
69+
70+
x += Boolean.TRUE.equals(initialValues.get("x" + inputWire)) ? 1 : 0;
71+
y += Boolean.TRUE.equals(initialValues.get("y" + inputWire)) ? 1 : 0;
72+
}
73+
74+
final long z = x + y;
75+
final String binaryZ = Long.toBinaryString(z);
76+
final Map<String, Boolean> zWires = new HashMap<>();
77+
final Queue<Swappable> swappables = new LinkedList<>();
78+
79+
boolean numberIsCorrect = false;
80+
while (!numberIsCorrect) {
81+
final Swappable swappable = swappables.poll();
82+
83+
final Map<String, List<Gate>> currentGates = generateGates(rawGates, outputs, swappable);
84+
numberIsCorrect = true;
85+
86+
for (String inputWire : inputWires) {
87+
outputs.clear();
88+
89+
final String xWire = "x" + inputWire;
90+
final String yWire = "y" + inputWire;
91+
final String zWire = "z" + inputWire;
92+
93+
currentGates.get(xWire).forEach(gate -> gate.accept(initialValues.get(xWire)));
94+
currentGates.get(yWire).forEach(gate -> gate.accept(initialValues.get(yWire)));
95+
96+
if (outputs.containsKey(zWire)) {
97+
zWires.put(zWire, outputs.get(zWire));
98+
99+
if (!outputs
100+
.get(zWire)
101+
.equals(binaryZ.charAt(binaryZ.length() - Integer.parseInt(inputWire) - 1) == '1')) {
102+
103+
Set<String> swapCandidates =
104+
outputs.keySet().stream()
105+
.filter(wire -> !zWire.equals(wire))
106+
.collect(Collectors.toSet());
107+
108+
numberIsCorrect = false;
109+
break;
110+
}
111+
} else {
112+
// z wires don't seem to be swapped in my implementation, so I'll skip this
113+
}
114+
}
115+
}
116+
117+
System.err.println(binaryZ);
118+
System.err.println(
119+
zWires.entrySet().stream()
120+
.sorted(Map.Entry.<String, Boolean>comparingByKey().reversed())
121+
.map(entry -> Boolean.TRUE.equals(entry.getValue()) ? "1" : "0")
122+
.collect(Collectors.joining()));
123+
}
124+
125+
private Map<String, List<Gate>> generateGates(
126+
final List<String> rawGates, final Map<String, Boolean> outputs, final Swappable swappable) {
127+
final Map<String, List<Gate>> gates = new HashMap<>();
128+
129+
for (final String rawGate : rawGates) {
130+
final Matcher matcher = PATTERN.matcher(rawGate);
131+
132+
if (matcher.matches()) {
133+
final Gate gate =
134+
new Gate(matcher.group("result"), gates, outputs, getOperation(matcher.group("type")));
135+
136+
gates.computeIfAbsent(matcher.group("one"), k -> new ArrayList<>()).add(gate);
137+
gates.computeIfAbsent(matcher.group("two"), k -> new ArrayList<>()).add(gate);
138+
}
139+
}
140+
141+
return gates;
29142
}
30143

31144
private void run(final Scanner in) {
32-
print("Whoopsie");
145+
final Map<String, Boolean> initialValues = new HashMap<>();
146+
final Map<String, List<Gate>> gates = new HashMap<>();
147+
final Map<String, Boolean> outputs = new HashMap<>();
148+
149+
while (in.hasNextLine()) {
150+
final String[] line = in.nextLine().split(": ");
151+
152+
if (line.length == 1) {
153+
break;
154+
}
155+
156+
initialValues.put(line[0], "1".equals(line[1]));
157+
}
158+
159+
while (in.hasNextLine()) {
160+
final Matcher matcher = PATTERN.matcher(in.nextLine());
161+
162+
if (matcher.matches()) {
163+
final Gate gate =
164+
new Gate(matcher.group("result"), gates, outputs, getOperation(matcher.group("type")));
165+
166+
gates.computeIfAbsent(matcher.group("one"), k -> new ArrayList<>()).add(gate);
167+
gates.computeIfAbsent(matcher.group("two"), k -> new ArrayList<>()).add(gate);
168+
}
169+
}
170+
171+
for (final String gate : initialValues.keySet()) {
172+
gates.get(gate).forEach(function -> function.accept(initialValues.get(gate)));
173+
}
174+
175+
long result = 0;
176+
177+
final List<String> outputGates =
178+
outputs.keySet().stream()
179+
.filter(gate -> gate.startsWith("z"))
180+
.sorted(Comparator.reverseOrder())
181+
.toList();
182+
for (final String gate : outputGates) {
183+
result <<= 1;
184+
if (Boolean.TRUE.equals(outputs.get(gate))) {
185+
++result;
186+
}
187+
}
188+
189+
print(result);
190+
}
191+
192+
private BinaryOperator<Boolean> getOperation(final String type) {
193+
return switch (type) {
194+
case "AND" -> (one, two) -> one && two;
195+
case "OR" -> (one, two) -> one || two;
196+
case "XOR" -> (one, two) -> one ^ two;
197+
default -> throw new IllegalStateException("Unexpected operation: " + type);
198+
};
199+
}
200+
201+
private static class Gate implements Consumer<Boolean> {
202+
private final String resultGate;
203+
private final Map<String, List<Gate>> gates;
204+
private final Map<String, Boolean> outputs;
205+
private final BinaryOperator<Boolean> operation;
206+
207+
private Boolean one;
208+
209+
public Gate(
210+
final String resultGate,
211+
final Map<String, List<Gate>> gates,
212+
final Map<String, Boolean> outputs,
213+
final BinaryOperator<Boolean> operation) {
214+
this.resultGate = resultGate;
215+
this.gates = gates;
216+
this.outputs = outputs;
217+
this.operation = operation;
218+
}
219+
220+
@Override
221+
public void accept(final Boolean input) {
222+
if (one == null) {
223+
one = input;
224+
} else {
225+
final Boolean result = operation.apply(one, input);
226+
outputs.put(resultGate, result);
227+
228+
if (gates.containsKey(resultGate)) {
229+
gates.get(resultGate).forEach(function -> function.accept(result));
230+
}
231+
}
232+
}
33233
}
234+
235+
private record Swappable(String wireNumber, String one, String two) {}
34236
}

adventofcode/src/main/java/org/ck/adventofcode/year2024/Day25.java

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package org.ck.adventofcode.year2024;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
35
import java.util.Scanner;
6+
import java.util.concurrent.atomic.AtomicInteger;
47
import org.apache.commons.lang3.NotImplementedException;
58
import org.ck.adventofcode.util.AOCSolution;
69
import org.ck.codechallengelib.annotation.Solution;
710

811
@Solution(
912
id = 20242501,
10-
name = "Day 25: ?",
13+
name = "Day 25: Code Chronicle",
1114
url = "https://adventofcode.com/2024/day/25",
12-
category = "2024",
13-
solved = false)
15+
category = "2024")
1416
public class Day25 extends AOCSolution {
1517

1618
@Override
@@ -24,6 +26,74 @@ protected void runPartTwo(final Scanner in) {
2426
}
2527

2628
private void run(final Scanner in) {
27-
print("Whoopsie");
29+
final List<Key> keys = new ArrayList<>();
30+
final List<Lock> locks = new ArrayList<>();
31+
32+
Component component = null;
33+
while (in.hasNextLine()) {
34+
final String line = in.nextLine();
35+
36+
if (component == null && "#####".equals(line)) {
37+
component =
38+
new Key(
39+
List.of(
40+
new AtomicInteger(1),
41+
new AtomicInteger(1),
42+
new AtomicInteger(1),
43+
new AtomicInteger(1),
44+
new AtomicInteger(1)));
45+
keys.add((Key) component);
46+
} else if (component == null && ".....".equals(line)) {
47+
component =
48+
new Lock(
49+
List.of(
50+
new AtomicInteger(0),
51+
new AtomicInteger(0),
52+
new AtomicInteger(0),
53+
new AtomicInteger(0),
54+
new AtomicInteger(0)));
55+
locks.add((Lock) component);
56+
} else if (line.isBlank()) {
57+
component = null;
58+
} else if (component != null) {
59+
for (int i = 0; i < line.length(); i++) {
60+
if (line.charAt(i) == '#') {
61+
component.heights().get(i).set(component.heights().get(i).get() + 1);
62+
}
63+
}
64+
}
65+
}
66+
67+
print(getMatchingPairs(locks, keys));
68+
}
69+
70+
private static long getMatchingPairs(final List<Lock> locks, final List<Key> keys) {
71+
long sum = 0;
72+
73+
for (Lock lock : locks) {
74+
for (Key key : keys) {
75+
boolean fits = true;
76+
77+
for (int i = 0; i < lock.heights().size(); ++i) {
78+
if (lock.heights().get(i).get() + key.heights().get(i).get() > 7) {
79+
fits = false;
80+
break;
81+
}
82+
}
83+
84+
if (fits) {
85+
++sum;
86+
}
87+
}
88+
}
89+
return sum;
90+
}
91+
92+
private sealed interface Component permits Key, Lock {
93+
List<AtomicInteger> heights();
2894
}
95+
96+
private record Key(List<AtomicInteger> heights) implements Component {}
97+
98+
private record Lock(List<AtomicInteger> heights) implements Component {}
2999
}

adventofcode/src/test/java/org/ck/adventofcode/year2024/Day24Test.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
import org.ck.adventofcode.util.BaseAOCTest;
44
import org.junit.jupiter.api.Disabled;
5+
import org.junit.jupiter.api.Test;
56
import org.junit.jupiter.params.ParameterizedTest;
67
import org.junit.jupiter.params.provider.ValueSource;
78

8-
@Disabled
99
class Day24Test extends BaseAOCTest {
1010
@ParameterizedTest
11-
@ValueSource(strings = {"01a"})
11+
@ValueSource(strings = {"01a", "01b"})
1212
void testPartOneExamples(final String name) throws Exception {
1313
runTest(new Day24()::partOne, "day24/%s".formatted(name));
1414
}
1515

16-
@ParameterizedTest
17-
@ValueSource(strings = {"02a"})
18-
void testPartTwoExamples(final String name) throws Exception {
19-
runTest(new Day24()::partTwo, "day24/%s".formatted(name));
16+
@Test
17+
@Disabled
18+
void testPartTwo() throws Exception {
19+
// not working yet
2020
}
2121
}

0 commit comments

Comments
 (0)