|
3 | 3 | import com.codefork.aoc2024.Problem;
|
4 | 4 | import com.codefork.aoc2024.util.Assert;
|
5 | 5 |
|
| 6 | +import java.util.ArrayList; |
| 7 | +import java.util.List; |
6 | 8 | import java.util.stream.Stream;
|
7 | 9 |
|
| 10 | +/** |
| 11 | + * Adapted from these solutions: |
| 12 | + * https://github.com/robabrazado/adventofcode2024/blob/main/src/com/robabrazado/aoc2024/day17/Computer.java |
| 13 | + * https://git.sr.ht/~murr/advent-of-code/tree/master/item/2024/17/p2.c |
| 14 | + * <p> |
| 15 | + * Writing out the program by hand, you can see it's a single giant loop that |
| 16 | + * does the following: |
| 17 | + * - set register B = last 3 bits of register A |
| 18 | + * - update registers B and C with a bunch of operations, using all 3 registers |
| 19 | + * - right-shift 3 bits off of register A |
| 20 | + * - print the rightmost 3 bits of register B |
| 21 | + * - starts again from the beginning if A != 0 |
| 22 | + * This means we don't have to care about the bunch of operations sandwiched |
| 23 | + * in the loop. Since the loop gradually right-shifts register A until it's 0, |
| 24 | + * we can work backwards: |
| 25 | + * - find the 3 bit values (there will be more than one) that will produce the last |
| 26 | + * desired item |
| 27 | + * - left shift those values |
| 28 | + * - add another 3 bits to those values, to try to produce the last two desired items |
| 29 | + * - etc. |
| 30 | + */ |
8 | 31 | public class Part02 extends Problem {
|
9 | 32 |
|
10 | 33 | public String solve(Stream<String> data) {
|
11 | | - var computer = Computer.parse(data).withA(35184372088831L); |
12 | | - while(true) { |
13 | | - var result = computer.run(); //UntilMatch(); |
14 | | -// if(result.isPresent()) { |
15 | | -// return result.get().getOutputAsString(); |
16 | | -// } |
17 | | - if(result.program().equals(result.output())) { |
18 | | - return String.valueOf(computer.a()); |
19 | | - } |
20 | | - System.out.println(computer.a() + " = " + result); |
21 | | - computer = computer.clearOutput().withA(computer.a() + 2000000); |
22 | | -// if(computer.a() % 1000000 == 0) { |
23 | | -// System.out.println(computer.a() + " = " + result); |
24 | | -// } |
25 | | - } |
| 34 | + var initialComputer = Computer.parse(data); |
| 35 | + var programSize = initialComputer.program().size(); |
26 | 36 |
|
27 | | -// ------------------------------- |
28 | | - // output with 16 numbers begins at a=35184372088832, |
29 | | - // 17 numbers begins at 281474976710656. |
30 | | - // brute force would need to scan 246290604621824 numbers. |
| 37 | +vari = programSize - 1; |
| 38 | + List<Integer> expectedOutput = newArrayList<>(); |
| 39 | + List<Long> candidates = newArrayList<>(); |
| 40 | + candidates.add(0L); |
31 | 41 |
|
32 | | -// var computer = Computer.parse(data).withA(35184372088831L); |
33 | | -// |
34 | | -// //search(computer); |
35 | | -// |
36 | | -// while(true) { |
37 | | -// var result = computer.run(); |
38 | | -// System.out.println(computer.a() + " = " + result); |
39 | | -// if(result.output().equals(result.program())) { |
40 | | -// return String.valueOf(computer.a()); |
41 | | -// } |
42 | | -// //computer = computer.withA((computer.a() * 2) - 1); |
43 | | -// computer = computer.clearOutput().withA(computer.a() +1); |
44 | | -// } |
45 | | - } |
| 42 | + while (i >= 0) { |
| 43 | + expectedOutput.addFirst(initialComputer.program().get(i)); |
46 | 44 |
|
47 | | - public void search(Computer computer) { |
48 | | - var lower = 0L; |
49 | | - var upper = Long.MAX_VALUE; |
50 | | - long mid = 0L; |
51 | | - var found = false; |
| 45 | + List<Long> newCandidates = new ArrayList<>(); |
52 | 46 |
|
53 | | - while (!found) { |
54 | | -mid = (lower + upper) / 2; |
55 | | - var result = computer.withA(mid).run(); |
56 | | - System.out.println(computer.a() + " = " + result); |
57 | | - if(result.output().size() < result.program().size()) { |
58 | | - upper = mid; |
59 | | - } elseif(result.output().size() > result.program().size()) { |
60 | | - lower = mid; |
61 | | - } else { |
62 | | - System.out.println("finished? " + mid); |
63 | | - found = true; |
| 47 | + //System.out.println("looking for next expected output=" + expectedOutput); |
| 48 | + |
| 49 | + for(var candidate : candidates) { |
| 50 | + for(varthreeBits = 0; threeBits < 8; threeBits++) { |
| 51 | + vartestA = (candidate << 3) + threeBits; |
| 52 | + vartestComputer = initialComputer.withA(testA); |
| 53 | + varfinalState = testComputer.run(); |
| 54 | + if(finalState.output().equals(expectedOutput)) { |
| 55 | + newCandidates.add(testA); |
| 56 | + } |
| 57 | + } |
64 | 58 | }
|
| 59 | + candidates = newCandidates; |
| 60 | + //System.out.println("candidates=" + candidates); |
| 61 | + i--; |
65 | 62 | }
|
| 63 | + |
| 64 | + var lowest = candidates.stream().mapToLong(n -> n).min().orElseThrow(); |
| 65 | + return String.valueOf(lowest); |
66 | 66 | }
|
67 | 67 |
|
68 | 68 | @Override
|
69 | 69 | public String solve() {
|
70 | | - //Assert.assertEquals("0,3,5,4,3,0", solve(getFileAsStream("sample2"))); |
71 | 70 | return solve(getInput());
|
72 | 71 | }
|
73 | 72 |
|
|
0 commit comments