this post was submitted on 17 Dec 2024
8 points (100.0% liked)

Advent Of Code

920 readers
56 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2024

Solution Threads

M T W T F S S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 18 20 21 22
23 24 25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 1 year ago
MODERATORS
 

Day 17: Chronospatial Computer

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

you are viewing a single comment's thread
view the rest of the comments
[โ€“] mykl 2 points 20 hours ago* (last edited 11 hours ago) (1 children)

Dart

Part one was an exercise in building a simple OpCode machine. Part two was trickier. It was clear that the a register was repeatedly being divided by 8, and testing a few values showed that each 3-bits of the initial value defined one entry in the output, so I built a recursive routine that brute-forced each one in turn. Only <1ms to run though, so not that brutal.

(It's worth pointing out that at some stages multiple 3-bit values gave rise to the required value, causing a failure to resolve later on if not checked.)

(edit: for-loop in buildQuine now avoids using a 0 for the initial triplet, as this should not be a valid value, and if it turns out to generate the required digit of the quine, you will get an infinite recursion. Thanks to SteveDinn for bringing this to my attention.)

import 'dart:math';
import 'package:collection/collection.dart';
import 'package:more/more.dart';

var prog = <int>[];
typedef State = (int, int, int);
State parse(List<String> lines) {
  var regs = lines.takeTo('').map((e) => int.parse(e.split(' ').last)).toList();
  var (a, b, c) = (regs[0], regs[1], regs[2]);
  prog = lines.last.split(' ').last.split(',').map(int.parse).toList();
  return (a, b, c);
}

List<int> runProg(State rec) {
  var (int a, int b, int c) = rec;
  combo(int v) => switch (v) { 4 => a, 5 => b, 6 => c, _ => v };
  var output = <int>[], pc = 0;
  while (pc < prog.length) {
    var code = prog[pc], arg = prog[pc + 1];
    var _ = switch (code) {
      0 => a ~/= pow(2, combo(arg)),
      1 => b ^= arg,
      2 => b = combo(arg) % 8,
      3 => (a != 0) ? (pc = arg - 2) : 0,
      4 => b ^= c, //ignores arg
      5 => output.add(combo(arg) % 8),
      6 => b = a ~/ pow(2, combo(arg)),
      7 => c = a ~/ pow(2, combo(arg)),
      _ => 0
    };
    pc += 2;
  }
  return output;
}

Function eq = const ListEquality().equals;
Iterable<int> buildQuine(State rec, List<int> quine, [top = false]) sync* {
  var (int a0, int b0, int c0) = rec;
  if (top) a0 = 0;
  if (quine.length == prog.length) {
    yield a0;
    return;
  }
  for (var a in (top ? 1 : 0).to(8)) {
    var newState = (a0 * 8 + a, b0, c0);
    var newQuine = runProg(newState);
    if (eq(prog.slice(prog.length - newQuine.length), newQuine)) {
      yield* buildQuine(newState, newQuine);
    }
  }
}

part1(List<String> lines) => runProg(parse(lines)).join(',');

part2(List<String> lines) => buildQuine(parse(lines), [], true).first;
[โ€“] [email protected] 3 points 14 hours ago (1 children)

I'm confused reading the buildQuine() method. It reads to me that when you call it from the top level with top = true, A0 will be set to 0, and then when we get to the 0 to 8 loop, the 'A' register will be 0 * 8 + 0 for the first iteration, and then recurse with top = false, but with a0 still ending up 0, causing infinite recursion.

Am I missing something?

I got it to work with a check that avoids the recursion if the last state's A register value is the same as the new state's value.

[โ€“] mykl 3 points 12 hours ago

Oh, good catch. That's certainly the case if an initial value of 0 correctly generates the required value of the quine. As I'd already started running some code against the live data that's what I tested against, and so it's only when I just tested it against the example data that I saw the problem.

I have changed the for-loop to read for (var a in (top ? 1 : 0).to(8)) for maximum terseness :-)

That still works for the example and my live data, and I don't think there should be a valid solution that relies on the first triplet being 0. Thanks for your reply!