|
3 | 3 | importcom.codefork.aoc2024.Problem; |
4 | 4 | importcom.codefork.aoc2024.util.Assert; |
5 | 5 |
|
| 6 | +importjava.util.ArrayList; |
| 7 | +importjava.util.List; |
6 | 8 | importjava.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 | publicclassPart02extendsProblem { |
9 | 32 |
|
10 | 33 | publicStringsolve(Stream<String>data) { |
11 | | -varcomputer =Computer.parse(data).withA(35184372088831L); |
12 | | -while(true) { |
13 | | -varresult =computer.run();//UntilMatch(); |
14 | | -// if(result.isPresent()) { |
15 | | -// return result.get().getOutputAsString(); |
16 | | -// } |
17 | | -if(result.program().equals(result.output())) { |
18 | | -returnString.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 | +varinitialComputer =Computer.parse(data); |
| 35 | +varprogramSize =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 | | -publicvoidsearch(Computercomputer) { |
48 | | -varlower =0L; |
49 | | -varupper =Long.MAX_VALUE; |
50 | | -longmid =0L; |
51 | | -varfound =false; |
| 45 | +List<Long>newCandidates =newArrayList<>(); |
52 | 46 |
|
53 | | -while (!found) { |
54 | | -mid = (lower +upper) /2; |
55 | | -varresult =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(varcandidate :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 | +varlowest =candidates.stream().mapToLong(n ->n).min().orElseThrow(); |
| 65 | +returnString.valueOf(lowest); |
66 | 66 | } |
67 | 67 |
|
68 | 68 | @Override |
69 | 69 | publicStringsolve() { |
70 | | -//Assert.assertEquals("0,3,5,4,3,0", solve(getFileAsStream("sample2"))); |
71 | 70 | returnsolve(getInput()); |
72 | 71 | } |
73 | 72 |
|
|