diff --git a/include/aoc/ChronospatialComputer.hpp b/include/aoc/ChronospatialComputer.hpp
new file mode 100644
index 0000000..86b7eb0
--- /dev/null
+++ b/include/aoc/ChronospatialComputer.hpp
@@ -0,0 +1,40 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+class ChronospatialComputer
+ : public Solver
+{
+public:
+ ChronospatialComputer();
+ virtual const std::string getPuzzleName() const override;
+ virtual const int getPuzzleDay() const override;
+ virtual void processDataLine(const std::string& line) override;
+ virtual void finish() override;
+ void runProgram(const std::vector& program, ChronospatialComputerState& state) const;
+private:
+ std::array, 8> instructions_;
+ std::vector program_;
+ ChronospatialComputerState state_;
+};
diff --git a/include/aoc/extra/ChronospatialComputerInstruction.hpp b/include/aoc/extra/ChronospatialComputerInstruction.hpp
new file mode 100644
index 0000000..fa695bf
--- /dev/null
+++ b/include/aoc/extra/ChronospatialComputerInstruction.hpp
@@ -0,0 +1,120 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+class ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerInstruction(const ChronospatialComputerOperandType type);
+ virtual ~ChronospatialComputerInstruction() = default;
+ void run(ChronospatialComputerState& state, const int operand) const;
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const = 0;
+private:
+ std::function&, const int)> operandFunctor_;
+};
+
+#pragma region ChronospatialComputerDivisionInstruction
+
+// Represents instruction "adv" (opcode 0), "bdv" (opcode 6), or "cdv" (opcode 7).
+class ChronospatialComputerDivisionInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerDivisionInstruction(const size_t destination);
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+private:
+ size_t destination_;
+};
+
+#pragma endregion
+
+#pragma region ChronospatialComputerXorLiteralInstruction
+
+// Represents instruction "bxl" (opcode 1).
+class ChronospatialComputerXorLiteralInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerXorLiteralInstruction();
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+};
+
+#pragma endregion
+
+#pragma region ChronospatialComputerModuloInstruction
+
+// Represents instruction "bst" (opcode 2).
+class ChronospatialComputerModuloInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerModuloInstruction();
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+};
+
+#pragma endregion
+
+#pragma region ChronospatialComputerJumpInstruction
+
+// Represents instruction "jnz" (opcode 3).
+class ChronospatialComputerJumpInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerJumpInstruction();
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+};
+
+#pragma endregion
+
+#pragma region ChronospatialComputerXorRegisterInstruction
+
+// Represents instruction "bxc" (opcode 4).
+class ChronospatialComputerXorRegisterInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerXorRegisterInstruction();
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+};
+
+#pragma endregion
+
+#pragma region ChronospatialComputerOutInstruction
+
+// Represents instruction "out" (opcode 5).
+class ChronospatialComputerOutInstruction
+ : public ChronospatialComputerInstruction
+{
+public:
+ ChronospatialComputerOutInstruction();
+protected:
+ virtual void runValue(ChronospatialComputerState& state, const int operandValue) const override;
+};
+
+#pragma endregion
diff --git a/include/aoc/extra/ChronospatialComputerOperandType.hpp b/include/aoc/extra/ChronospatialComputerOperandType.hpp
new file mode 100644
index 0000000..5a0d78e
--- /dev/null
+++ b/include/aoc/extra/ChronospatialComputerOperandType.hpp
@@ -0,0 +1,22 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#pragma once
+
+enum class ChronospatialComputerOperandType
+{
+ Literal,
+ Combo
+};
diff --git a/include/aoc/extra/ChronospatialComputerState.hpp b/include/aoc/extra/ChronospatialComputerState.hpp
new file mode 100644
index 0000000..5aef12c
--- /dev/null
+++ b/include/aoc/extra/ChronospatialComputerState.hpp
@@ -0,0 +1,27 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#pragma once
+
+#include
+#include
+
+class ChronospatialComputerState
+{
+public:
+ size_t instructionPointer{ 0 };
+ std::array registers{};
+ std::ostringstream output{};
+};
diff --git a/src/ChronospatialComputer.cpp b/src/ChronospatialComputer.cpp
new file mode 100644
index 0000000..73b154f
--- /dev/null
+++ b/src/ChronospatialComputer.cpp
@@ -0,0 +1,85 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#include
+
+#include
+#include
+
+ChronospatialComputer::ChronospatialComputer()
+ : state_{}, program_{}, instructions_{
+ std::make_unique(0), // adv
+ std::make_unique(), // bxl
+ std::make_unique(), // bst
+ std::make_unique(), // jnz
+ std::make_unique(), // bxc
+ std::make_unique(), // out
+ std::make_unique(1), // bdv
+ std::make_unique(2) // cdv
+ }
+{
+}
+
+const std::string ChronospatialComputer::getPuzzleName() const
+{
+ return "Chronospatial Computer";
+}
+
+const int ChronospatialComputer::getPuzzleDay() const
+{
+ return 17;
+}
+
+void ChronospatialComputer::processDataLine(const std::string& line)
+{
+ std::istringstream stream{ line };
+ std::string token{};
+ char c;
+ int value;
+ if (stream >> token)
+ {
+ if (token == "Register")
+ {
+ stream >> c >> token >> value;
+ // c must be 'A', 'B', or 'C'.
+ size_t regIndex{ static_cast(c - 65) };
+ state_.registers[regIndex] = value;
+ }
+ else
+ {
+ while (stream >> value)
+ {
+ program_.push_back(value);
+ // Streams a comma from between values.
+ stream >> c;
+ }
+ }
+ }
+}
+
+void ChronospatialComputer::finish()
+{
+ runProgram(program_, state_);
+ part1 = state_.output.str();
+}
+
+void ChronospatialComputer::runProgram(const std::vector& program, ChronospatialComputerState& state) const
+{
+ state.instructionPointer = 0;
+ while (state.instructionPointer < program.size())
+ {
+ instructions_[program[state.instructionPointer]]->run(state, program[state.instructionPointer + 1]);
+ }
+}
diff --git a/src/Program.cpp b/src/Program.cpp
index 7aa7b44..98d42a2 100644
--- a/src/Program.cpp
+++ b/src/Program.cpp
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include
void Program::run()
@@ -71,6 +72,7 @@ void Program::runSolvers()
runSolver(solverEngine);
runSolver(solverEngine);
runSolver(solverEngine);
+ runSolver(solverEngine);
runSolver(solverEngine);
}
diff --git a/src/extra/ChronospatialComputerInstruction.cpp b/src/extra/ChronospatialComputerInstruction.cpp
new file mode 100644
index 0000000..6053f9b
--- /dev/null
+++ b/src/extra/ChronospatialComputerInstruction.cpp
@@ -0,0 +1,132 @@
+// Solutions to the Advent Of Code 2024.
+// Copyright (C) 2025 Stefan Müller
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+
+#include
+
+#include
+
+ChronospatialComputerInstruction::ChronospatialComputerInstruction(const ChronospatialComputerOperandType type)
+{
+ switch (type)
+ {
+ case ChronospatialComputerOperandType::Literal :
+ operandFunctor_ = [](const std::array& registers, const int operand) { return operand; };
+ break;
+ case ChronospatialComputerOperandType::Combo :
+ operandFunctor_ = [](const std::array& registers, const int operand)
+ { return operand < 4 ? operand : registers[static_cast(operand - 4)]; };
+ break;
+ }
+}
+
+void ChronospatialComputerInstruction::run(ChronospatialComputerState& state, const int operand) const
+{
+ runValue(state, operandFunctor_(state.registers, operand));
+}
+
+#pragma region ChronospatialComputerDivisionInstruction
+
+ChronospatialComputerDivisionInstruction::ChronospatialComputerDivisionInstruction(const size_t destination)
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Combo), destination_{ destination }
+{
+}
+
+void ChronospatialComputerDivisionInstruction::runValue(ChronospatialComputerState& state, const int operandValue) const
+{
+ state.registers[destination_] = state.registers[0] / Math::ipow(2, operandValue);
+ state.instructionPointer += 2;
+}
+
+#pragma endregion
+
+#pragma region ChronospatialComputerXorLiteralInstruction
+
+ChronospatialComputerXorLiteralInstruction::ChronospatialComputerXorLiteralInstruction()
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Literal)
+{
+}
+
+void ChronospatialComputerXorLiteralInstruction::runValue(ChronospatialComputerState& state,
+ const int operandValue) const
+{
+ state.registers[1] = state.registers[1] ^ operandValue;
+ state.instructionPointer += 2;
+}
+
+#pragma endregion
+
+#pragma region ChronospatialComputerModuloInstruction
+
+ChronospatialComputerModuloInstruction::ChronospatialComputerModuloInstruction()
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Combo)
+{
+}
+
+void ChronospatialComputerModuloInstruction::runValue(ChronospatialComputerState& state, const int operandValue) const
+{
+ state.registers[1] = operandValue & 0b111;
+ state.instructionPointer += 2;
+}
+
+#pragma endregion
+
+#pragma region ChronospatialComputerJumpInstruction
+
+ChronospatialComputerJumpInstruction::ChronospatialComputerJumpInstruction()
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Literal)
+{
+}
+
+void ChronospatialComputerJumpInstruction::runValue(ChronospatialComputerState& state, const int operandValue) const
+{
+ state.instructionPointer = state.registers[0] == 0 ? state.instructionPointer + 2 : operandValue;
+}
+
+#pragma endregion
+
+#pragma region ChronospatialComputerXorRegisterInstruction
+
+ChronospatialComputerXorRegisterInstruction::ChronospatialComputerXorRegisterInstruction()
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Literal)
+{
+}
+
+void ChronospatialComputerXorRegisterInstruction::runValue(ChronospatialComputerState& state,
+ const int operandValue) const
+{
+ state.registers[1] = state.registers[1] ^ state.registers[2];
+ state.instructionPointer += 2;
+}
+
+#pragma endregion
+
+#pragma region ChronospatialComputerOutInstruction
+
+ChronospatialComputerOutInstruction::ChronospatialComputerOutInstruction()
+ : ChronospatialComputerInstruction(ChronospatialComputerOperandType::Combo)
+{
+}
+
+void ChronospatialComputerOutInstruction::runValue(ChronospatialComputerState& state, const int operandValue) const
+{
+ if (state.output.tellp() != std::streampos(0))
+ {
+ state.output << ',';
+ }
+ state.output << (operandValue & 0b111);
+ state.instructionPointer += 2;
+}
+
+#pragma endregion
diff --git a/tests/include/aocTests/TestContext.hpp b/tests/include/aocTests/TestContext.hpp
index eb1a8ff..4ebf650 100644
--- a/tests/include/aocTests/TestContext.hpp
+++ b/tests/include/aocTests/TestContext.hpp
@@ -28,6 +28,8 @@ class TestContext
const long long expected2, const std::vector& inputPaths);
void run(const std::unique_ptr>&& solver, const long long expected1,
const std::string expected2, const std::vector& inputPaths);
+ void run(const std::unique_ptr>&& solver, const std::string expected1,
+ const long long expected2, const std::vector& inputPaths);
void runPart1(const std::unique_ptr>&& solver, const long long expected,
const std::vector& inputPaths);
void runPart2(const std::unique_ptr>&& solver, const long long expected,
diff --git a/tests/src/TestCases.cpp b/tests/src/TestCases.cpp
index c1c62d1..6d49696 100644
--- a/tests/src/TestCases.cpp
+++ b/tests/src/TestCases.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); }
@@ -270,6 +271,61 @@ TEST_CASE("[ReindeerMazeTests]")
}
}
+TEST_CASE("[ChronospatialComputerTests]")
+{
+ TestContext test;
+ SECTION("FullData")
+ {
+ test.run(std::make_unique(), "5,0,3,5,7,6,1,5,4", 0, test.getInputPaths());
+ }
+ SECTION("ExampleData")
+ {
+ test.run(std::make_unique(), "4,6,3,5,6,3,5,2,1,0", 0, test.getExampleInputPaths());
+ }
+ SECTION("ExampleInstruction1")
+ {
+ auto solver = std::make_unique();
+ ChronospatialComputerState state{};
+ state.registers[2] = 9;
+ solver->runProgram({ 2, 6 }, state);
+ REQUIRE(1 == state.registers[1]);
+ }
+ SECTION("ExampleInstruction2")
+ {
+ auto solver = std::make_unique();
+ ChronospatialComputerState state{};
+ state.registers[0] = 10;
+ solver->runProgram({ 5, 0, 5, 1, 5, 4 }, state);
+ REQUIRE("0,1,2" == state.output.str());
+ }
+ SECTION("ExampleInstruction3")
+ {
+ auto solver = std::make_unique();
+ ChronospatialComputerState state{};
+ state.registers[0] = 2024;
+ solver->runProgram({ 0, 1, 5, 4, 3, 0 }, state);
+ REQUIRE(0 == state.registers[0]);
+ REQUIRE("4,2,5,6,7,7,7,7,3,1,0" == state.output.str());
+ }
+ SECTION("ExampleInstruction4")
+ {
+ auto solver = std::make_unique();
+ ChronospatialComputerState state{};
+ state.registers[1] = 29;
+ solver->runProgram({ 1, 7 }, state);
+ REQUIRE(26 == state.registers[1]);
+ }
+ SECTION("ExampleInstruction5")
+ {
+ auto solver = std::make_unique();
+ ChronospatialComputerState state{};
+ state.registers[1] = 2024;
+ state.registers[2] = 43690;
+ solver->runProgram({ 4, 0 }, state);
+ REQUIRE(44354 == state.registers[1]);
+ }
+}
+
TEST_CASE("[LanPartyTests]")
{
TestContext test;
diff --git a/tests/src/TestContext.cpp b/tests/src/TestContext.cpp
index 9bbf0a1..2170e71 100644
--- a/tests/src/TestContext.cpp
+++ b/tests/src/TestContext.cpp
@@ -39,6 +39,16 @@ void TestContext::run(const std::unique_ptr>&& so
REQUIRE(expected2 == solver->getResultPart2());
}
+void TestContext::run(const std::unique_ptr>&& solver, const std::string expected1,
+ const long long expected2, const std::vector& inputPaths)
+{
+ SolverEngine solverEngine{ inputPaths };
+ solverEngine.run(*solver);
+
+ REQUIRE(expected1 == solver->getResultPart1());
+ REQUIRE(expected2 == solver->getResultPart2());
+}
+
void TestContext::runPart1(const std::unique_ptr>&& solver, const long long expected,
const std::vector& inputPaths)
{