From d60432cee48aef7c05ddcd34db03a7737c8be31b Mon Sep 17 00:00:00 2001 From: encse Date: Tue, 17 Dec 2024 17:06:27 +0100 Subject: [PATCH] use the the actual Run method for part2 making it input agnostic --- 2024/Day17/README.md | 3 ++- 2024/Day17/Solution.cs | 53 +++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/2024/Day17/README.md b/2024/Day17/README.md index abd96b0a..dcddf5cf 100644 --- a/2024/Day17/README.md +++ b/2024/Day17/README.md @@ -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) \ No newline at end of file diff --git a/2024/Day17/Solution.cs b/2024/Day17/Solution.cs index a3d1bf2f..b5e44d86 100644 --- a/2024/Day17/Solution.cs +++ b/2024/Day17/Solution.cs @@ -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(); - 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 Run(List state, List program) { + var combo = (int op) => op < 4 ? op : state[op - 4]; + var res = new List(); + 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 GenerateA(List output) { + IEnumerable GenerateA(List program, List 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 state, List program) Parse(string input) { var blocks = input.Split("\n\n").Select(ParseNums).ToArray(); return (blocks[0], blocks[1]); } - long[] ParseNums(string st) => + List ParseNums(string st) => Regex.Matches(st, @"\d+", RegexOptions.Multiline) .Select(m => long.Parse(m.Value)) - .ToArray(); + .ToList(); } \ No newline at end of file