Problem difficulty so far (up to day 16)
- Day 15 - Warehouse Woes: 30m00s
- Day 12 - Garden Groups: 17m42s
- Day 14 - Restroom Redoubt: 15m48s
- Day 09 - Disk Fragmenter: 14m05s
- Day 16 - Reindeer Maze: 13m47s
- Day 13 - Claw Contraption: 11m04s
- Day 06 - Guard Gallivant: 08m53s
- Day 08 - Resonant Collinearity: 07m12s
- Day 11 - Plutonian Pebbles: 06m24s
- Day 04 - Ceres Search: 05m41s
- Day 02 - Red Nosed Reports: 04m42s
- Day 10 - Hoof It: 04m14s
- Day 07 - Bridge Repair: 03m47s
- Day 05 - Print Queue: 03m43s
- Day 03 - Mull It Over: 03m22s
- Day 01 - Historian Hysteria: 02m31s
17!
p1 discussion
Simultaneously very fun and also the fucking worst.
Fun: Ooooh, I get to simulate a computer, exciting!
Worst: Literally 8 edge cases where fucking up even just one can fuck up your hour.
p2 discussion
I did this by hand. sort of. I mean I didn’t code up something that found the answer.
Basically I looked at the program in the input and wrote it out, and realised that A was essentially a loop variable, where the number of iterations was the number of octal digits A would take to represent. The most significant octal digits (octits?) would determine the tail end of the output sequence, so to find the smallest A you can do a DFS starting from the MS octit. I did this by hand.
EDIT: code. Not gonna explain any of it.
class Comp { List<int> reg; List<int> prog; int ip = 0; List<int> output = []; late List<(int, bool) Function()> ops; int get combo => prog[ip + 1] < 4 ? prog[ip + 1] : reg[prog[ip + 1] - 4]; Comp(this.reg, this.prog) { ops = [ () => (reg[0] = (reg[0] >> combo), false), () => (reg[1] ^= prog[ip + 1], false), () => (reg[1] = combo % 8, false), () => (reg[0] != 0) ? (ip = prog[ip + 1], true) : (0, false), () => (reg[1] ^= reg[2], false), () { output.add(combo % 8); return (0, false); }, () => (reg[1] = (reg[0] >> combo), false), () => (reg[2] = (reg[0] >> combo), false) ]; } compute() { output.clear(); while (ip < prog.length) { if (!ops[prog[ip]]().$2) { ip += 2; } } } reset(int A) { ip = 0; reg[0] = A; reg[1] = 0; reg[2] = 0; } } void d17(bool sub) { List<String> input = getLines(); Comp c = Comp( input.take(3).map((s) => s.split(" ").last).map(int.parse).toList(), input.last.split(" ").last.split(",").map(int.parse).toList()) ..compute(); print("Part a: ${c.output.join(",")}"); if (!sub) return; List<int> sols = []; bool dfs(int cur) { bool found = false; sols.add(cur); int sol = sols.reduce((a, b) => 8 * a + b); c..reset(sol)..compute(); if (c.prog .whereIndexed((i, e) => i >= c.prog.length - c.output.length) .foldIndexed(true, (i, p, e) => p && c.output[i] == e)) { if (found = c.output.length == c.prog.length) { print("Part b: $sol"); } else { for (int i = 0; i < 8 && !(found = found || dfs(i)); i++) {} } } sols.removeLast(); return found; } for (int a = 0; a < 8 && !dfs(a); a++) {} }
re: p1
I literally created different test inputs for all the examples given and that found a lot of bugs for me. Specifically the difference between literal and combo operators.
EDIT: I have a sneaking suspicion that the computer will need to be re-used since the combo-operand 7 does not occur and is “reserved”.
re p2
Also did this by hand to get my precious gold star, but then actually went back and implemented it Some JQ extension required: