Skip to content

Commit

Permalink
use the the actual Run method for part2 making it input agnostic
Browse files Browse the repository at this point in the history
  • Loading branch information
encse committed Dec 17, 2024
1 parent 9fd6a0d commit d60432c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 28 deletions.
3 changes: 2 additions & 1 deletion 2024/Day17/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ There is _some interconnection_ between the consecutive numbers, so one cannot j
for each. But I was able to come up with a _recursive solution_ that generates the input _backwards_. Once we know the
higher bits, we can try all combinations for the next 3 bits, and so on down to the first bit.

As an added bonus I implemented (part of) the emulator in [VIC-20 BASIC](https://hu.wikipedia.org/wiki/Commodore_VIC-20). This is how it runs the second sample that prints out its own source code.
As an added bonus I implemented (part of) the emulator in [VIC-20 BASIC](https://hu.wikipedia.org/wiki/Commodore_VIC-20).
This is how it runs the second sample that prints out its own source code.

![vic20.gif](vic20.gif)
53 changes: 26 additions & 27 deletions 2024/Day17/Solution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,60 @@ enum Opcode {
Adv, Bxl, Bst, Jnz, Bxc, Out, Bdv, Cdv
}

public object PartOne(string input) => Run(input);
public object PartTwo(string input) => GenerateA(Parse(input).program.ToList()).Min();

string Run(string input) {
public object PartOne(string input) {
var (state, program) = Parse(input);
var combo = (long op) => op < 4 ? (int)op : (int)state[op - 4];
var res = new List<int>();
for (var ip = 0; ip < program.Length; ip += 2) {
switch ((Opcode)program[ip], program[ip + 1]) {
case (Opcode.Adv, var op): state[0] = state[0] >> combo(op); break;
case (Opcode.Bdv, var op): state[1] = state[0] >> combo(op); break;
case (Opcode.Cdv, var op): state[2] = state[0] >> combo(op); break;
return string.Join(",", Run(state, program));
}
public object PartTwo(string input) {
var (_, program) = Parse(input);
return GenerateA(program, program).Min();
}

List<long> Run(List<long> state, List<long> program) {
var combo = (int op) => op < 4 ? op : state[op - 4];
var res = new List<long>();
for (var ip = 0; ip < program.Count; ip += 2) {
switch ((Opcode)program[ip], (int)program[ip + 1]) {
case (Opcode.Adv, var op): state[0] = state[0] >> (int)combo(op); break;
case (Opcode.Bdv, var op): state[1] = state[0] >> (int)combo(op); break;
case (Opcode.Cdv, var op): state[2] = state[0] >> (int)combo(op); break;
case (Opcode.Bxl, var op): state[1] = state[1] ^ op; break;
case (Opcode.Bst, var op): state[1] = combo(op) % 8; break;
case (Opcode.Jnz, var op): ip = state[0] == 0 ? ip : (int)op - 2; break;
case (Opcode.Jnz, var op): ip = state[0] == 0 ? ip : op - 2; break;
case (Opcode.Bxc, var op): state[1] = state[1] ^ state[2]; break;
case (Opcode.Out, var op): res.Add(combo(op) % 8); break;
}
}
return string.Join(",", res);
return res;
}

/*
Determines register A for the given output. The search works recursively and in reverse order,
starting from the last number to be printed and ending with the first.
Determines register A for the given output. The search works recursively and in
reverse order, starting from the last number to be printed and ending with the first.
*/
IEnumerable<long> GenerateA(List<long> output) {
IEnumerable<long> GenerateA(List<long> program, List<long> output) {
if (!output.Any()) {
yield return 0;
yield break;
}

// this loop is pretty much the assembly code of the program reimplemented in c#
foreach (var ah in GenerateA(output[1..])) {
foreach (var ah in GenerateA(program, output[1..])) {
for (var al = 0; al < 8; al++) {
var a = ah * 8 + al;
long b = a % 8;
b = b ^ 3;
var c = a >> (int)b;
b = b ^ c;
b = b ^ 5;
if (output[0] == b % 8) {
if (Run([a, 0, 0], program).SequenceEqual(output)) {
yield return a;
}
}
}
}

(long[] state, long[] program) Parse(string input) {
(List<long> state, List<long> program) Parse(string input) {
var blocks = input.Split("\n\n").Select(ParseNums).ToArray();
return (blocks[0], blocks[1]);
}

long[] ParseNums(string st) =>
List<long> ParseNums(string st) =>
Regex.Matches(st, @"\d+", RegexOptions.Multiline)
.Select(m => long.Parse(m.Value))
.ToArray();
.ToList();
}

0 comments on commit d60432c

Please sign in to comment.