Beispiel #1
0
        public void RunProgramComparisonTests()
        {
            // https://adventofcode.com/2019/day/5
            // 3,9,8,9,10,9,4,9,99,-1,8 - Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
            // 3,9,7,9,10,9,4,9,99,-1,8 - Using position mode, consider whether the input is less than 8; output 1(if it is) or 0(if it is not).
            // 3,3,1108,-1,8,3,4,3,99 - Using immediate mode, consider whether the input is equal to 8; output 1(if it is) or 0(if it is not).
            // 3,3,1107,-1,8,3,4,3,99 - Using immediate mode, consider whether the input is less than 8; output 1(if it is) or 0(if it is not).
            var testData = new List <Tuple <int[], int, int> >(new Tuple <int[], int, int>[] {
                new Tuple <int[], int, int>(new int[] { 3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8 }, 7, 0),
                new Tuple <int[], int, int>(new int[] { 3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8 }, 8, 1),
                new Tuple <int[], int, int>(new int[] { 3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8 }, 9, 0),
                new Tuple <int[], int, int>(new int[] { 3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8 }, 7, 1),
                new Tuple <int[], int, int>(new int[] { 3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8 }, 8, 0),
                new Tuple <int[], int, int>(new int[] { 3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8 }, 9, 0),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1108, -1, 8, 3, 4, 3, 99 }, 7, 0),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1108, -1, 8, 3, 4, 3, 99 }, 8, 1),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1108, -1, 8, 3, 4, 3, 99 }, 9, 0),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1107, -1, 8, 3, 4, 3, 99 }, 7, 1),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1107, -1, 8, 3, 4, 3, 99 }, 8, 0),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1107, -1, 8, 3, 4, 3, 99 }, 9, 0),
            });

            foreach (var testExample in testData)
            {
                var inputProvider  = new StaticValueInputProvider(testExample.Item2);
                var outputListener = new ListOutputListener();
                var computer       = new IntcodeComputer(inputProvider, outputListener);
                computer.LoadProgram(testExample.Item1);
                var status = computer.RunProgram();
                Assert.Equal(IntcodeProgramStatus.Completed, status);
                Assert.True(outputListener.Values.Count > 0);
                Assert.Equal(testExample.Item3, outputListener.Values[outputListener.Values.Count - 1]);
            }
        }
Beispiel #2
0
        private void InitializeGame(
            BigInteger[] program,
            int numberOfQuarters,
            IList <int> preProgrammedInputs)
        {
            _program = new BigInteger[program.Length];
            Array.Copy(program, _program, program.Length);
            // Memory address 0 represents the number of quarters that have
            // been inserted; set it to 2 to play for free.
            if (numberOfQuarters > 0)
            {
                _program[0] = numberOfQuarters;
            }
            InputProvider = new BufferedInputProvider();
            if (preProgrammedInputs != null)
            {
                PreProgrammedInputs = preProgrammedInputs.ToList();
            }
            OutputListener = new ListOutputListener();
            _computer      = new IntcodeComputer(InputProvider, OutputListener);
            _computer.LoadProgram(_program);

            GridCells  = new HashSet <GameGridCell>();
            GameStatus = IntcodeProgramStatus.Running;
        }
Beispiel #3
0
        public void RunProgramJumpTests()
        {
            // https://adventofcode.com/2019/day/5
            // Here are some jump tests that take an input, then output 0 if the input was zero or 1 if the input was non-zero:
            // 3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9(using position mode)
            // 3,3,1105,-1,9,1101,0,0,12,4,12,99,1(using immediate mode)
            // The following example program uses an input instruction to ask
            // for a single number. The program will then output 999 if the
            // input value is below 8, output 1000 if the input value is equal
            // to 8, or output 1001 if the input value is greater than 8.
            // 3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
            var testData = new List <Tuple <int[], int, int> >(new Tuple <int[], int, int>[] {
                new Tuple <int[], int, int>(new int[] { 3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9 }, -1, 1),
                new Tuple <int[], int, int>(new int[] { 3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9 }, 0, 0),
                new Tuple <int[], int, int>(new int[] { 3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9 }, 1, 1),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1 }, -1, 1),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1 }, 0, 0),
                new Tuple <int[], int, int>(new int[] { 3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1 }, 1, 1),
                new Tuple <int[], int, int>(new int[] { 3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99 }, 7, 999),
                new Tuple <int[], int, int>(new int[] { 3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99 }, 8, 1000),
                new Tuple <int[], int, int>(new int[] { 3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99 }, 9, 1001)
            });

            foreach (var testExample in testData)
            {
                var inputProvider  = new StaticValueInputProvider(testExample.Item2);
                var outputListener = new ListOutputListener();
                var computer       = new IntcodeComputer(inputProvider, outputListener);
                computer.LoadProgram(testExample.Item1);
                var status = computer.RunProgram();
                Assert.Equal(IntcodeProgramStatus.Completed, status);
                Assert.True(outputListener.Values.Count > 0);
                Assert.Equal(testExample.Item3, outputListener.Values[outputListener.Values.Count - 1]);
            }
        }
Beispiel #4
0
        public static BigInteger RunVaccuumRobot(bool isManualInput)
        {
            // Upon inspection, the following commands solve the problem:
            // A,B,A,B,A,C,B,C,A,C
            // A: L,6,R,6,6,L,6
            // B: R,6,6,L,5,5,L,4,L,6
            // C: L,5,5,L,5,5,L,4,L,6
            BigInteger[] program = GetDay17Input();
            program[0] = 2;
            var encodedCommands = EncodeRobotCommands(
                mainMovementRoutine: "A,B,A,B,A,C,B,C,A,C",
                movementFunctionA: "L,6,R,6,6,L,6",
                movementFunctionB: "R,6,6,L,5,5,L,4,L,6",
                movementFunctionC: "L,5,5,L,5,5,L,4,L,6",
                continuousVideoFeed: false);
            IInputProvider inputProvider;

            if (isManualInput)
            {
                inputProvider = new ConsoleInputProvider();
            }
            else
            {
                inputProvider = new BufferedInputProvider();
            }
            var             outputListener = new ListOutputListener();
            IntcodeComputer computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            var computerStatus   = IntcodeProgramStatus.Running;
            int outputStartIndex = 0;
            int commandIndex     = 0;

            while (IntcodeProgramStatus.Running.Equals(computerStatus) ||
                   IntcodeProgramStatus.AwaitingInput.Equals(computerStatus))
            {
                // Provide inputs if automated
                if (IntcodeProgramStatus.AwaitingInput.Equals(computerStatus) &&
                    !isManualInput)
                {
                    ((BufferedInputProvider)inputProvider).AddInputValue(encodedCommands[commandIndex]);
                    Console.Write(encodedCommands[commandIndex]);
                    commandIndex++;
                }

                // Run program
                computerStatus = computer.RunProgram();

                // Display output
                if (outputListener.Values.Count > 0)
                {
                    DisplayProgramOutput(outputListener, outputStartIndex);
                    outputStartIndex = outputListener.Values.Count;
                }
            }
            return(outputListener.Values.LastOrDefault());
        }
Beispiel #5
0
        public static BigInteger GetDay21Part1Answer()
        {
            // Program the springdroid with logic that allows it to survey the
            // hull without falling into space. What amount of hull damage
            // does it report?
            // Answer: 19360724
            BigInteger result = 0;

            Console.WriteLine("Starting Day 21 - Part 1...");
            var program        = GetDay21Input();
            var inputProvider  = new BufferedInputProvider();
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);

            // Define the robot instructions
            // Note - a jump will land 4 spaces ahead
            // Jump only if any of A, B, or C are holes
            // AND D is not a hole
            // ->
            // NOT A J <- JUMP is true if A is a hole
            // NOT B T <- TEMP is true if B is a hole
            // OR T J  <- JUMP is true if A or B is a hole
            // NOT C T <- TEMP is true if C is a hole
            // OR T J  <- JUMP is true if A or B or C is a hole
            // NOT D T <- TEMP is true if D is a hole
            // NOT T T <- TEMP is true if D is *not* a hole
            // AND T J <- JUMP is true if (A or B or C is a hole) AND (D is not a hole)
            var robotInstructions = new List <string>()
            {
                "NOT A J",
                "NOT B T",
                "OR T J",
                "NOT C T",
                "OR T J",
                "NOT D T",
                "NOT T T",
                "AND T J",
                "WALK"
            };
            var robotInstructionAsciiInput = GetRobotInstructionAsciiInputValues(robotInstructions);

            inputProvider.Values.AddRange(robotInstructionAsciiInput);

            computer.RunProgram();
            // If the robot successfully made it across, then the last output
            // value will be a large non-ascii character
            if (outputListener.Values.Count > 0 && outputListener.Values.Last() > 255)
            {
                result = outputListener.Values.Last();
                outputListener.Values.RemoveAt(outputListener.Values.Count - 1);
            }
            IntcodeComputerHelper.DrawAsciiOutput(outputListener.Values);
            return(result);
        }
Beispiel #6
0
        public static void DisplayProgramOutput(ListOutputListener outputListener, int startIndex)
        {
            var outputStrings = GetProgramOutputStrings(outputListener.Values.GetRange(startIndex, outputListener.Values.Count - startIndex));

            Console.WriteLine();
            foreach (var outputString in outputStrings)
            {
                Console.WriteLine("     " + outputString);
            }
        }
Beispiel #7
0
        public static Dictionary <GridPoint, string> PerformInitialScan()
        {
            BigInteger[]    program        = GetDay17Input();
            var             inputProvider  = new BufferedInputProvider();
            var             outputListener = new ListOutputListener();
            IntcodeComputer computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            computer.RunProgram();
            var scaffoldMap = ProcessInitialScan(outputListener.Values);

            return(scaffoldMap);
        }
Beispiel #8
0
        public static DroneStatus ScanPoint(BigInteger[] program, GridPoint point)
        {
            var inputProvider  = new BufferedInputProvider();
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            inputProvider.AddInputValue(point.X);
            inputProvider.AddInputValue(point.Y);
            computer.RunProgram();
            var droneStatus = (DroneStatus)(int)outputListener.Values[0];

            return(droneStatus);
        }
Beispiel #9
0
        public static BigInteger GetDay9Part2Answer()
        {
            // The program runs in sensor boost mode by providing the input
            // instruction the value 2. Once run, it will boost the sensors
            // automatically, but it might take a few seconds to complete the
            // operation on slower hardware. In sensor boost mode, the program
            // will output a single value: the coordinates of the distress signal.
            // Run the BOOST program in sensor boost mode.What are the
            // coordinates of the distress signal?
            // Answer: 63441
            var program        = GetDay9Input();
            var inputProvider  = new StaticValueInputProvider(2);
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            computer.RunProgram();
            return(outputListener.Values[0]);
        }
Beispiel #10
0
        public static BigInteger GetDay9Part1Answer()
        {
            // The BOOST program will ask for a single input; run it in test
            // mode by providing it the value 1. It will perform a series of
            // checks on each opcode, output any opcodes (and the associated
            // parameter modes) that seem to be functioning incorrectly, and
            // finally output a BOOST keycode.
            // Once your Intcode computer is fully functional, the BOOST
            // program should report no malfunctioning opcodes when run in test
            // mode; it should only output a single value, the BOOST keycode.
            // What BOOST keycode does it produce?
            // Answer: 2662308295
            var program        = GetDay9Input();
            var inputProvider  = new StaticValueInputProvider(1);
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            computer.RunProgram();
            return(outputListener.Values[0]);
        }
Beispiel #11
0
        public void RunDay9Tests()
        {
            // Test cases taken from here:
            // https://adventofcode.com/2019/day/9
            // 109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99 takes no input and produces a copy of itself as output.
            var program1        = new BigInteger[] { 109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99 };
            var outputListener1 = new ListOutputListener();
            var computer1       = new IntcodeComputer(new ConsoleInputProvider(), outputListener1);

            computer1.LoadProgram(program1);
            var status1 = computer1.RunProgram();

            Assert.Equal(IntcodeProgramStatus.Completed, status1);
            Assert.Equal(program1, outputListener1.Values);

            // 1102,34915192,34915192,7,4,7,99,0 should output a 16 - digit number.
            var program2        = new BigInteger[] { 1102, 34915192, 34915192, 7, 4, 7, 99, 0 };
            var outputListener2 = new ListOutputListener();
            var computer2       = new IntcodeComputer(new ConsoleInputProvider(), outputListener2);

            computer2.LoadProgram(program2);
            var status2 = computer2.RunProgram();

            Assert.Equal(IntcodeProgramStatus.Completed, status2);
            Assert.Single(outputListener2.Values);
            Assert.Equal(16, outputListener2.Values[0].ToString().Length);

            // 104,1125899906842624,99 should output the large number in the middle.
            var program3        = new BigInteger[] { 104, 1125899906842624, 99 };
            var outputListener3 = new ListOutputListener();
            var computer3       = new IntcodeComputer(new ConsoleInputProvider(), outputListener3);

            computer3.LoadProgram(program3);
            var status3 = computer3.RunProgram();

            Assert.Equal(IntcodeProgramStatus.Completed, status3);
            Assert.Single(outputListener3.Values);
            Assert.Equal(BigInteger.Parse("1125899906842624"), outputListener3.Values[0]);
        }
Beispiel #12
0
        private void InitializeMap(BigInteger[] program, bool isAutomated)
        {
            ExploredPoints   = new Dictionary <string, ShipSectionInfo>();
            ExplorationTree  = new Tree <string>();
            UnexploredPoints = new HashSet <string>();
            ItemLocations    = new Dictionary <string, string>();
            RobotPosition    = "O";
            RobotInventory   = new HashSet <string>();
            IsAutomated      = isAutomated;
            ExplorationTree.Add(RobotPosition, null);
            UnexploredPoints.Add(RobotPosition);
            _inputProviderManual    = new ConsoleInputProvider();
            _inputProviderAutomated = new BufferedInputProvider();
            IInputProvider inputProviderToUse = _inputProviderAutomated;

            if (!IsAutomated)
            {
                inputProviderToUse = _inputProviderManual;
            }
            _outputListener = new ListOutputListener();
            _computer       = new IntcodeComputer(inputProviderToUse, _outputListener);
            _computer.LoadProgram(program);
        }
Beispiel #13
0
        public static int GetAmplifierOutput(
            int initialInput,
            int[] phaseSettings,
            BigInteger[] program,
            FeedbackMode feedbackMode)
        {
            // Initialize the amplifiers
            var numberOfAmplifiers = phaseSettings.Length;
            var amplifiers         = new List <Tuple <IntcodeComputer, BufferedInputProvider, ListOutputListener> >(numberOfAmplifiers);

            for (int i = 0; i < numberOfAmplifiers; i++)
            {
                var inputProvider = new BufferedInputProvider();
                inputProvider.AddInputValue(phaseSettings[i]);
                if (i == 0)
                {
                    inputProvider.AddInputValue(initialInput);
                }
                var outputListener = new ListOutputListener();
                var computer       = new IntcodeComputer(inputProvider, outputListener);
                computer.LoadProgram(program);
                amplifiers.Add(new Tuple <IntcodeComputer, BufferedInputProvider, ListOutputListener>(
                                   computer,
                                   inputProvider,
                                   outputListener));
            }

            int        currentAmplifierIndex = 0;
            int        round = 1;
            BigInteger output;

            while (true)
            {
                var currentAmplifier = amplifiers[currentAmplifierIndex];
                var computer         = currentAmplifier.Item1;
                var outputListener   = currentAmplifier.Item3;
                var status           = computer.RunProgram();
                if (!IntcodeProgramStatus.AwaitingInput.Equals(status) &&
                    !IntcodeProgramStatus.Completed.Equals(status))
                {
                    throw new Exception($"Program halted with invalid status: {status}");
                }
                if (outputListener.Values.Count == 0)
                {
                    throw new Exception("No output received");
                }
                output = outputListener.Values.Last();

                // The program has completed, break out
                if (currentAmplifierIndex == numberOfAmplifiers - 1 &&
                    IntcodeProgramStatus.Completed.Equals(status))
                {
                    break;
                }

                // The program hasn't finished...
                // Pass the output from this amplifier to the input of the next
                var nextAmplifierIndex = currentAmplifierIndex + 1;
                if (nextAmplifierIndex >= numberOfAmplifiers)
                {
                    nextAmplifierIndex = 0;
                }
                var nextAmplifier = amplifiers[nextAmplifierIndex];
                var nextAmplifierInputProvider = nextAmplifier.Item2;
                nextAmplifierInputProvider.AddInputValue(output);

                currentAmplifierIndex++;
                if (currentAmplifierIndex == numberOfAmplifiers)
                {
                    if (FeedbackMode.Normal.Equals(feedbackMode))
                    {
                        break;
                    }
                    else if (FeedbackMode.Loop.Equals(feedbackMode))
                    {
                        currentAmplifierIndex = 0;
                        round++;
                    }
                }
            }

            return((int)output);
        }
Beispiel #14
0
        public static BigInteger RunNetwork(int part)
        {
            var program               = GetDay23Input();
            var computers             = new Dictionary <int, IntcodeComputer>();
            var programStatuses       = new Dictionary <int, IntcodeProgramStatus>();
            var inputProviders        = new Dictionary <int, BufferedInputProvider>();
            var outputListeners       = new Dictionary <int, ListOutputListener>();
            var outputListenerAddress = new Dictionary <int, int>();
            var natYValues            = new Stack <BigInteger>();

            for (int computerAddress = 0; computerAddress < 256; computerAddress++)
            {
                if (computerAddress >= 50 && computerAddress < 255)
                {
                    continue;
                }
                var inputProvider = new BufferedInputProvider();
                inputProvider.AddInputValue(computerAddress);
                var outputListener = new ListOutputListener();
                var computer       = new IntcodeComputer(inputProvider, outputListener);
                computer.LoadProgram(program);
                computers.Add(computerAddress, computer);
                programStatuses.Add(computerAddress, IntcodeProgramStatus.Running);
                inputProviders.Add(computerAddress, inputProvider);
                outputListeners.Add(computerAddress, outputListener);
                outputListenerAddress.Add(computerAddress, 0);
            }

            for (int loopCount = 1; ; loopCount++)
            {
                bool isIdle = true;
                for (int computerAddress = 0; computerAddress < 50; computerAddress++)
                {
                    var computer      = computers[computerAddress];
                    var currentStatus = programStatuses[computerAddress];
                    var inputProvider = inputProviders[computerAddress];
                    if (IntcodeProgramStatus.AwaitingInput.Equals(currentStatus))
                    {
                        if (inputProvider.HasInput())
                        {
                            isIdle = false;
                        }
                        else
                        {
                            inputProviders[computerAddress].AddInputValue(-1);
                        }
                    }
                    else if (IntcodeProgramStatus.Running.Equals(currentStatus))
                    {
                        isIdle = false;
                    }
                    var status = computer.RunProgram();
                    programStatuses[computerAddress] = status;

                    // Process output
                    var outputListener = outputListeners[computerAddress];
                    var currentOutputListenerAddress = outputListenerAddress[computerAddress];
                    while (currentOutputListenerAddress + 2 < outputListener.Values.Count)
                    {
                        isIdle = false;
                        var targetAddress = outputListener.Values[currentOutputListenerAddress];
                        var X             = outputListener.Values[currentOutputListenerAddress + 1];
                        var Y             = outputListener.Values[currentOutputListenerAddress + 2];
                        currentOutputListenerAddress += 3;
                        if (targetAddress < 50 || targetAddress == 255)
                        {
                            var targetInputProvider = inputProviders[(int)targetAddress];
                            targetInputProvider.AddInputValue(X);
                            targetInputProvider.AddInputValue(Y);
                            if (targetAddress == 255)
                            {
                                var targetOutputListener = outputListeners[255];
                                targetOutputListener.Values.Add(X);
                                targetOutputListener.Values.Add(Y);
                                outputListenerAddress[255] = targetOutputListener.Values.Count - 2;
                                if (part == 1)
                                {
                                    return(Y);
                                }
                            }
                        }
                        else
                        {
                            throw new Exception($"targetAddress out of range: {targetAddress}");
                        }
                    }
                    outputListenerAddress[computerAddress] = currentOutputListenerAddress;
                }
                if (isIdle)
                {
                    // Get the last packet sent to the NAT and send it to
                    // address 0
                    var outputListener = outputListeners[255];
                    var address        = outputListenerAddress[255];
                    if (address + 1 >= outputListener.Values.Count)
                    {
                        throw new Exception("Invalid state");
                    }
                    var X = outputListener.Values[address];
                    var Y = outputListener.Values[address + 1];
                    inputProviders[0].AddInputValue(X);
                    inputProviders[0].AddInputValue(Y);
                    if (natYValues.Count > 0)
                    {
                        var previousYValue = natYValues.Peek();
                        if (part == 2 && Y == previousYValue)
                        {
                            return(Y);
                        }
                    }
                    natYValues.Push(Y);
                }
            }
        }
Beispiel #15
0
        public static BigInteger GetDay21Part2Answer()
        {
            // Successfully survey the rest of the hull by ending your program
            // with RUN. What amount of hull damage does the springdroid now
            // report?
            // Answer: 1140450681
            BigInteger result = 0;

            Console.WriteLine("Starting Day 21 - Part 2...");
            var program        = GetDay21Input();
            var inputProvider  = new BufferedInputProvider();
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);

            // Define the robot instructions
            // Note - a jump will still land 4 spaces ahead
            // Jump if:
            // There is a hole in A, B, or C
            // And D is not a hole
            // And (H OR (E AND (I OR F)))
            // OR A J  |\
            // AND B J | | A, B, or C is a hole: !(A AND B AND C)
            // AND C J | |
            // NOT J J |/
            // AND D J | AND D is a block
            // OR F T  |\ (I OR F)
            // OR I T  |/
            // AND E T | E AND (I OR F)
            // OR H T  | H OR (E AND (I OR F))
            // AND T J | final
            var robotInstructions = new List <string>()
            {
                "OR A J ",
                "AND B J",
                "AND C J",
                "NOT J J",
                "AND D J",
                "OR F T ",
                "OR I T ",
                "AND E T",
                "OR H T ",
                "AND T J",
                "RUN"
            };
            var robotInstructionAsciiInput = GetRobotInstructionAsciiInputValues(robotInstructions);

            inputProvider.Values.AddRange(robotInstructionAsciiInput);

            computer.RunProgram();
            // If the robot successfully made it across, then the last output
            // value will be a large non-ascii character
            if (outputListener.Values.Count > 0 && outputListener.Values.Last() > 255)
            {
                result = outputListener.Values.Last();
                outputListener.Values.RemoveAt(outputListener.Values.Count - 1);
            }
            IntcodeComputerHelper.DrawAsciiOutput(outputListener.Values);
            return(result);
        }
Beispiel #16
0
        public static Dictionary <GridPoint, HullCellType> MapHull(
            BigInteger[] program,
            out GridPoint robotPosition)
        {
            // Initialize the hull map
            robotPosition = new GridPoint(0, 0);
            var exploredPoints = new Dictionary <GridPoint, HullCellType>()
            {
                { robotPosition, HullCellType.Empty }
            };
            var unexploredPoints    = new Tree <GridPoint>();
            var newUnexploredPoints = GetNewUnexploredPoints(
                robotPosition,
                exploredPoints,
                unexploredPoints);

            unexploredPoints.Add(newUnexploredPoints, null);

            // Setup the computer
            var inputProvider  = new BufferedInputProvider();
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);
            var programStatus = IntcodeProgramStatus.Running;

            // Initialize the target
            SetNextTargetUnexploredPoint(
                exploredPoints,
                unexploredPoints,
                null,
                out GridPoint targetUnexploredPoint);

            var pathToTargetMovementCommands = GetMovementCommandsForPath(
                robotPosition,
                GetPathToPoint(
                    robotPosition,
                    targetUnexploredPoint,
                    exploredPoints));
            int loopCount = 0;

            while (!IntcodeProgramStatus.Completed.Equals(programStatus) &&
                   targetUnexploredPoint != null)
            {
                loopCount++;
                // Take the next step in the path
                int movementCommand = pathToTargetMovementCommands.Dequeue();
                inputProvider.AddInputValue(movementCommand);

                programStatus = computer.RunProgram();

                // Process output:
                // 1) Set the type of the next cell based on the status code
                // 2a) Remove the next cell from the unexplored cells
                // 2b) Add the next cell to the map
                // 3) Move the robot
                // 4) Add new unexplored cells
                var nextPoint     = GetNextPoint(robotPosition, movementCommand);
                var statusCode    = outputListener.Values.Last();
                var nextPointType = ParseHullCellType((int)statusCode);
                if (!exploredPoints.ContainsKey(nextPoint))
                {
                    exploredPoints.Add(nextPoint, nextPointType);
                }
                if (!HullCellType.Wall.Equals(nextPointType))
                {
                    robotPosition = nextPoint;
                }
                newUnexploredPoints = GetNewUnexploredPoints(
                    robotPosition,
                    exploredPoints,
                    unexploredPoints);
                unexploredPoints.Add(newUnexploredPoints, robotPosition);

                // Update the target if necessary
                if (exploredPoints.ContainsKey(targetUnexploredPoint))
                {
                    var currentTargetUnexploredPoint = targetUnexploredPoint;
                    SetNextTargetUnexploredPoint(
                        exploredPoints,
                        unexploredPoints,
                        currentTargetUnexploredPoint,
                        out targetUnexploredPoint);
                    pathToTargetMovementCommands = GetMovementCommandsForPath(
                        robotPosition,
                        GetPathToPoint(
                            robotPosition,
                            targetUnexploredPoint,
                            exploredPoints));
                }
            }
            return(exploredPoints);
        }
Beispiel #17
0
        /// <summary>
        /// Runs the given input program and returns a dictionary containing
        /// the set of points painted at least once and their final paint color.
        /// once, and
        /// </summary>
        /// <param name="program"></param>
        /// <returns></returns>
        public static Dictionary <GridPoint, int> RunEmergencyHullPaintingRobot(
            IList <BigInteger> program,
            int firstPanelColor = 0)
        {
            var gridPaintColors   = new Dictionary <GridPoint, int>();
            int defaultPaintColor = 0;

            var inputProvider  = new BufferedInputProvider();
            var outputListener = new ListOutputListener();
            var computer       = new IntcodeComputer(inputProvider, outputListener);

            computer.LoadProgram(program);

            var            currentGridPoint      = new GridPoint(0, 0);
            int            currentOutputCount    = 0;
            int            loopCount             = 0;
            bool           isInitialInput        = true;
            RobotDirection currentRobotDirection = RobotDirection.Up;
            var            programStatus         = IntcodeProgramStatus.Running;

            while (IntcodeProgramStatus.Running.Equals(programStatus) ||
                   IntcodeProgramStatus.AwaitingInput.Equals(programStatus))
            {
                loopCount++;
                // Provide input value for the current grid
                int inputValue = gridPaintColors.ContainsKey(currentGridPoint) ?
                                 gridPaintColors[currentGridPoint] :
                                 defaultPaintColor;
                if (isInitialInput)
                {
                    inputValue     = firstPanelColor;
                    isInitialInput = false;
                }
                inputProvider.AddInputValue(inputValue);

                // Run the program, given the input
                programStatus = computer.RunProgram();

                // Process new output values
                int numberOfNewValues = outputListener.Values.Count - currentOutputCount;
                currentOutputCount = outputListener.Values.Count;
                if (numberOfNewValues == 0 || numberOfNewValues > 2)
                {
                    throw new Exception($"Program output invalid number of new values during input loop {numberOfNewValues}");
                }
                BigInteger paintCommand = outputListener.Values[currentOutputCount - 2];
                BigInteger turnCommand  = outputListener.Values[currentOutputCount - 1];

                // Paint the current cell
                if (paintCommand != 0 && paintCommand != 1)
                {
                    throw new Exception($"Invalid paint command {paintCommand}");
                }
                if (!gridPaintColors.ContainsKey(currentGridPoint))
                {
                    gridPaintColors.Add(currentGridPoint, defaultPaintColor);
                }
                gridPaintColors[currentGridPoint] = (int)paintCommand;

                // Turn the robot
                if (turnCommand != 0 && turnCommand != 1)
                {
                    throw new Exception($"Invalid turn command {turnCommand}");
                }
                currentRobotDirection = GetNewRobotDirection(currentRobotDirection, (int)turnCommand);

                // Move the robot
                currentGridPoint = MoveRobot(currentGridPoint, currentRobotDirection);
            }

            return(gridPaintColors);
        }