|
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 | + var i = programSize - 1; |
| 38 | + List<Integer> expectedOutput = new ArrayList<>(); |
| 39 | + List<Long> candidates = new ArrayList<>(); |
| 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 |
| - } else if(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(var threeBits = 0; threeBits < 8; threeBits++) { |
| 51 | + var testA = (candidate << 3) + threeBits; |
| 52 | + var testComputer = initialComputer.withA(testA); |
| 53 | + var finalState = 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