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

  • SteveDinn
    link
    fedilink
    arrow-up
    3
    ·
    17 hours ago

    C#

    This one is mostly thanks to reading @mykl@[email protected]’s code to understand WTF was going on for part 2, and then once I understood the basics, finally got to solving it myself. Instructions were read in as long because I didn’t want to deal with int vs. long all the time.

    using System.Collections.Immutable;
    using System.Diagnostics;
    using Common;
    
    namespace Day17;
    
    static class Program
    {
        public record State(long A, long B, long C, int InstPtr, ImmutableList<long> Output);
    
        static void Main()
        {
            var start = Stopwatch.GetTimestamp();
    
            var (sampleReg, sampleInst) = ReceiveInput("sample.txt");
            var (inputReg, inputInst) = ReceiveInput("input.txt");
    
            Console.WriteLine($"Part 1 sample: {Part1(sampleReg, sampleInst)}");
            Console.WriteLine($"Part 1 input: {Part1(inputReg, inputInst)}");
    
            (sampleReg, sampleInst) = ReceiveInput("sample2.txt");
            Console.WriteLine($"Part 2 sample: {Part2(sampleReg, sampleInst)}");
            Console.WriteLine($"Part 2 input: {Part2(inputReg, inputInst)}");
    
            Console.WriteLine($"That took about {Stopwatch.GetElapsedTime(start)}");
        }
    
        static object Part1(State state, ImmutableArray<long> instructions) =>
            Execute(instructions, state).Output.StringifyAndJoin(",");
    
        static object Part2(State state, ImmutableArray<long> instructions) =>
            RecursiveSolve(instructions, state with { A = 0 }, []).First();
    
        static IEnumerable<long> RecursiveSolve(ImmutableArray<long> instructions, State state, ImmutableList<long> soFar) =>
            (soFar.Count == instructions.Length) ? [state.A] :
            Enumerable.Range(0, 8)
                .Select(a => state with { A = (state.A << 3) + a })
                .Where(newState => newState.A != state.A)
                .Select(newState => new { newState, Execute(instructions, newState).Output, })
                .Where(states => states.Output.SequenceEqual(instructions.TakeLast(states.Output.Count)))
                .SelectMany(states => RecursiveSolve(instructions, states.newState, states.Output));
    
        static State Execute(ImmutableArray<long> instructions, State state)
        {
            while (state.InstPtr < instructions.Length)
            {
                var opcode = instructions[state.InstPtr];
                var operand = instructions[state.InstPtr + 1];
                state = Operations[opcode](state, operand);
            }
    
            return state;
        }
    
        static long ComboOperand(long operand, State state) => operand switch
        {
            >= 0 and <= 3 => operand,
            4 => state.A,
            5 => state.B,
            6 => state.C,
            _ => throw new Exception("Invalid operand."),
        };
    
        static long Adv(long op, State state) => state.A / (long)Math.Pow(2, ComboOperand(op, state));
    
        static readonly Func<State, long, State>[] Operations =
        [
            (s, op) => s with { InstPtr = s.InstPtr + 2, A = Adv(op, s) },
            (s, op) => s with { InstPtr = s.InstPtr + 2, B = s.B ^ op },
            (s, op) => s with { InstPtr = s.InstPtr + 2, B = ComboOperand(op, s) % 8 },
            (s, op) => s with { InstPtr = (s.A == 0) ? (s.InstPtr + 2) : (op <= int.MaxValue) ? (int)op : throw new ArithmeticException("Integer overflow!") },
            (s, _) => s with { InstPtr = s.InstPtr + 2, B = s.B ^ s.C },
            (s, op) => s with { InstPtr = s.InstPtr + 2, Output = s.Output.Add(ComboOperand(op, s) % 8) },
            (s, op) => s with { InstPtr = s.InstPtr + 2, B = Adv(op, s) },
            (s, op) => s with { InstPtr = s.InstPtr + 2, C = Adv(op, s) },
        ];
    
    
        static (State, ImmutableArray<long> instructions) ReceiveInput(string file)
        {
            var input = File.ReadAllLines(file);
    
            return
            (
                new State(
                    long.Parse(input[0].Substring("Register A: ".Length)),
                    long.Parse(input[1].Substring("Register B: ".Length)),
                    long.Parse(input[2].Substring("Register C: ".Length)),
                    0,
                    []),
                input[4].Substring("Program: ".Length)
                    .Split(",")
                    .Select(long.Parse)
                    .ToImmutableArray()
            );
        }
    }