Add solution for "Day 17: Chronospatial Computer", part 2
This commit is contained in:
@@ -73,6 +73,7 @@ void ChronospatialComputer::finish()
|
||||
{
|
||||
runProgram(program_, state_);
|
||||
part1 = state_.output.str();
|
||||
part2 = findQuineState();
|
||||
}
|
||||
|
||||
void ChronospatialComputer::runProgram(const std::vector<int>& program, ChronospatialComputerState& state) const
|
||||
@@ -83,3 +84,80 @@ void ChronospatialComputer::runProgram(const std::vector<int>& program, Chronosp
|
||||
instructions_[program[state.instructionPointer]]->run(state, program[state.instructionPointer + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
long long ChronospatialComputer::findQuineState()
|
||||
{
|
||||
// The following masks and output patterns are specific to a single program and have been precalculated manually.
|
||||
// The given Chronospatial Computer program essentially does the following calculations.
|
||||
//
|
||||
// A' = A >> 3
|
||||
// OUT = (((A mod 8) xor 4) xor (A shr ((A mod 8) xor 1))) mod 8,
|
||||
//
|
||||
// where A is the initial value of register A, A' is the value of register A when program flow reaches the jump
|
||||
// instruction at the end of the program, and OUT is the single value written to the output when program flow reaches
|
||||
// that same jump instruction.
|
||||
//
|
||||
// So given a desired output OUT, the number to be appended to the accumulated result can be found by matching the
|
||||
// output patterns below against the masked trailing bits of the accumulated result, see the calculations below.
|
||||
|
||||
// Array index corresponds to number to append.
|
||||
std::array<int, 8> masks{ 0b1, 0b0, 0b111, 0b11, 0b11100, 0b1110, 0b1110000, 0b111000 };
|
||||
|
||||
// Array index is the output number.
|
||||
// First pair element is the number appended to register A.
|
||||
// Second pair element is the pattern to match against register A.
|
||||
std::array<std::vector<std::pair<int, int>>, 8> outputPatterns
|
||||
{ {
|
||||
// output 0
|
||||
{ { 0, 0b1 }, { 2, 0b110 }, { 4, 0b00000 }, { 5, 0b0010 }, { 6, 0b0100000 }, { 7, 0b0110000 } },
|
||||
// output 1
|
||||
{ { 2, 0b111 }, { 3, 0b11 }, { 4, 0b00100 }, { 5, 0b0000 }, { 6, 0b0110000 }, { 7, 0b010000 } },
|
||||
// output 2
|
||||
{ { 2, 0b100 }, { 4, 0b01000 }, { 5, 0b0110 }, { 6, 0b0000000 }, { 7, 0b001000 } },
|
||||
// output 3
|
||||
{ { 2, 0b101 }, { 3, 0b10 }, { 4, 0b01100 }, { 5, 0b0100 }, { 6, 0b0010000 }, { 7, 0b000000 } },
|
||||
// output 4
|
||||
{ { 0, 0b0 }, { 1, 0b0 }, { 2, 0b010 }, { 4, 0b10000 }, { 5, 0b1010 }, { 6, 0b1100000 }, { 7, 0b111000 } },
|
||||
// output 5
|
||||
{ { 2, 0b011 }, { 3, 0b01 }, { 4, 0b10100 }, { 5, 0b1000 }, { 6, 0b1110000 }, { 7, 0b110000 } },
|
||||
// output 6
|
||||
{ { 2, 0b000 }, { 4, 0b11000 }, { 5, 0b1110 }, { 6, 0b1000000 }, { 7, 0b101000 } },
|
||||
// output 7
|
||||
{ { 2, 0b001 }, { 3, 0b00 }, { 4, 0b11100 }, { 5, 0b1100 }, { 6, 0b1010000 }, { 7, 0b100000 } }
|
||||
} };
|
||||
|
||||
long long result{ 0 };
|
||||
size_t i{ program_.size() };
|
||||
int lastAppend{ -1 };
|
||||
|
||||
// Appends 3-digit binary numbers to the end of 'result' that will cause the program to output the next desired
|
||||
// number (from 'program_'). The target output numbers are considered in reverse order.
|
||||
while (i > 0)
|
||||
{
|
||||
auto patterns = outputPatterns[program_[i - 1]];
|
||||
auto it = std::find_if(patterns.begin(), patterns.end(),
|
||||
[&lastAppend, &result, &masks](auto& x) {
|
||||
return lastAppend < x.first && (result & masks[x.first]) == x.second; });
|
||||
if (it != patterns.end())
|
||||
{
|
||||
// Appends the next number 'it->first' that will result in the desired output 'program_[i - 1]'.
|
||||
lastAppend = -1;
|
||||
result = (result << 3) + it->first;
|
||||
i--;
|
||||
}
|
||||
else if (i < program_.size())
|
||||
{
|
||||
// Backtrack because no 3-digit number can be appended to yield the desired output.
|
||||
lastAppend = result & 0b111;
|
||||
result >>= 3;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should not execute, it's a safeguard against an infinite loop in case of unexpected input.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ ChronospatialComputerInstruction::ChronospatialComputerInstruction(const Chronos
|
||||
switch (type)
|
||||
{
|
||||
case ChronospatialComputerOperandType::Literal :
|
||||
operandFunctor_ = [](const std::array<int, 3>& registers, const int operand) { return operand; };
|
||||
operandFunctor_ = [](const std::array<long long, 3>& registers, const int operand) { return operand; };
|
||||
break;
|
||||
case ChronospatialComputerOperandType::Combo :
|
||||
operandFunctor_ = [](const std::array<int, 3>& registers, const int operand)
|
||||
operandFunctor_ = [](const std::array<long long, 3>& registers, const int operand)
|
||||
{ return operand < 4 ? operand : registers[static_cast<size_t>(operand - 4)]; };
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user