feat: solved day 17 part 1
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
namespace ChronospatialComputer.Tests;
|
||||||
|
|
||||||
|
public class ComputerTests
|
||||||
|
{
|
||||||
|
private readonly string _exampleInput = $"Register A: 729{Environment.NewLine}Register B: 0{Environment.NewLine}Register C: 0{Environment.NewLine}{Environment.NewLine}Program: 0,1,5,4,3,0";
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RunProgram_WhenCalledWithExampleInput_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
var result = Computer.From(_exampleInput).RunProgram();
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo("4,6,3,5,6,3,5,2,1,0");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,160 @@ if (File.Exists(args[0]) is false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isPart2 = args.Length is 2 && args[1] is "part2";
|
var isPart2 = args.Length is 2 && args[1] is "part2";
|
||||||
var input = await File.ReadAllLinesAsync(args[0]);
|
var input = await File.ReadAllTextAsync(args[0]);
|
||||||
|
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
// TODO: Implement solution
|
var result = Computer.From(input).RunProgram();
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)");
|
Console.WriteLine($"The output of the program is {result}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||||
|
|
||||||
|
class Computer
|
||||||
|
{
|
||||||
|
private readonly int[] _program;
|
||||||
|
private readonly Dictionary<int, Func<int, bool>> _instructions;
|
||||||
|
|
||||||
|
private int _aRegister;
|
||||||
|
private int _bRegister;
|
||||||
|
private int _cRegister;
|
||||||
|
private int _instructionPointer;
|
||||||
|
private readonly List<int> _output = [];
|
||||||
|
|
||||||
|
private Computer(int a, int b, int c, int[] program)
|
||||||
|
{
|
||||||
|
_aRegister = a;
|
||||||
|
_bRegister = b;
|
||||||
|
_cRegister = c;
|
||||||
|
_program = program;
|
||||||
|
|
||||||
|
_instructions = new()
|
||||||
|
{
|
||||||
|
{ 0, Adv },
|
||||||
|
{ 1, Bxl },
|
||||||
|
{ 2, Bst },
|
||||||
|
{ 3, Jnz },
|
||||||
|
{ 4, Bxc },
|
||||||
|
{ 5, Out },
|
||||||
|
{ 6, Bdv },
|
||||||
|
{ 7, Cdv },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Computer From(string input)
|
||||||
|
{
|
||||||
|
var parts = input.Split($"{Environment.NewLine}{Environment.NewLine}");
|
||||||
|
|
||||||
|
if (parts.Length is not 2)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The computer input has more than 2 parts");
|
||||||
|
}
|
||||||
|
|
||||||
|
var registersPart = parts[0];
|
||||||
|
var programPart = parts[1];
|
||||||
|
|
||||||
|
var registers = registersPart.Split(Environment.NewLine);
|
||||||
|
|
||||||
|
if (registers.Length is not 3)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"There were only {registers.Length} registers given");
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerA = int.Parse(registers[0].Split(':')[1].Trim());
|
||||||
|
var registerB = int.Parse(registers[1].Split(':')[1].Trim());
|
||||||
|
var registerC = int.Parse(registers[2].Split(':')[1].Trim());
|
||||||
|
|
||||||
|
var program = programPart.Split(':')[1].Trim().Split(',').Select(int.Parse).ToArray();
|
||||||
|
|
||||||
|
return new(registerA, registerB, registerC, program);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RunProgram()
|
||||||
|
{
|
||||||
|
while (_instructionPointer < _program.Length)
|
||||||
|
{
|
||||||
|
var opcode = _program[_instructionPointer];
|
||||||
|
var operand = _program[_instructionPointer + 1];
|
||||||
|
|
||||||
|
if (_instructions.TryGetValue(opcode, out var instruction) is false)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{nameof(opcode)} is unknown: {opcode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var shouldAdvance = instruction(operand);
|
||||||
|
|
||||||
|
if (shouldAdvance is false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_instructionPointer += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(',', _output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetComboOperand(int operand) => operand switch
|
||||||
|
{
|
||||||
|
0 or 1 or 2 or 3 => operand,
|
||||||
|
4 => _aRegister,
|
||||||
|
5 => _bRegister,
|
||||||
|
6 => _cRegister,
|
||||||
|
_ => throw new ArgumentException($"{nameof(operand)} is not a valid operand: {operand}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool Adv(int operand)
|
||||||
|
{
|
||||||
|
_aRegister /= (int)Math.Pow(2, GetComboOperand(operand));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Bxl(int operand)
|
||||||
|
{
|
||||||
|
_bRegister ^= operand;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Bst(int operand)
|
||||||
|
{
|
||||||
|
_bRegister = GetComboOperand(operand) % 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Jnz(int operand)
|
||||||
|
{
|
||||||
|
if (_aRegister is 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_instructionPointer = operand;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Bxc(int operand)
|
||||||
|
{
|
||||||
|
_bRegister ^= _cRegister;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Out(int operand)
|
||||||
|
{
|
||||||
|
_output.Add(GetComboOperand(operand) % 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Bdv(int operand)
|
||||||
|
{
|
||||||
|
_bRegister = _aRegister / (int)Math.Pow(2, GetComboOperand(operand));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Cdv(int operand)
|
||||||
|
{
|
||||||
|
_cRegister = _aRegister / (int)Math.Pow(2, GetComboOperand(operand));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user