diff --git a/include/aoc/DiskFragmenter.hpp b/include/aoc/DiskFragmenter.hpp
new file mode 100644
index 0000000..64d538f
--- /dev/null
+++ b/include/aoc/DiskFragmenter.hpp
@@ -0,0 +1,31 @@
+// 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
+
+class DiskFragmenter
+ : public Solver
+{
+public:
+ virtual const std::string getPuzzleName() const override;
+ virtual const std::string getInputFileName() const override;
+ virtual void processDataLine(const std::string& line) override;
+ virtual void finish() override;
+private:
+ int getDigit(const std::string& line, const size_t index) const;
+ long long int calcChecksumPart(const size_t idNumber, const int nBlocks, size_t& position) const;
+};
diff --git a/src/DiskFragmenter.cpp b/src/DiskFragmenter.cpp
new file mode 100644
index 0000000..793a326
--- /dev/null
+++ b/src/DiskFragmenter.cpp
@@ -0,0 +1,103 @@
+// 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
+
+const std::string DiskFragmenter::getPuzzleName() const
+{
+ return "Day 9: Disk Fragmenter";
+}
+
+const std::string DiskFragmenter::getInputFileName() const
+{
+ return "disk_fragmenter.txt";
+}
+
+void DiskFragmenter::processDataLine(const std::string& line)
+{
+ //size_t maxIdNumber{ line.size() / 2 };
+ // Index of the first unprocessed digit in the disk map.
+ size_t front{ 0 };
+ // ID number of the file 'front' refers to (when 'isFile == true'). Equivalent to 'front / 2', but calculated
+ // incrementally.
+ size_t frontIdNumber{ 0 };
+ // Index of the last unprocessed digit in the disk map.
+ size_t back{ line.size() - 1 };
+ // Number of remaining fragmented blocks in the file that 'back' refers to (when 'isFile == true').
+ int nRemainingBackBlocks{ getDigit(line, back) };
+ // ID number of the file 'back' refers to (when 'isFile == true'). Equivalent to 'back / 2', but calculated
+ // incrementally.
+ size_t backIdNumber{ line.size() / 2 };
+ // Current block position.
+ size_t position{ 0 };
+
+ bool isFile{ true };
+
+ while (front < back)
+ {
+ if (isFile)
+ {
+ // Adds the checksum for the file at 'front'.
+ int nFileBlocks = getDigit(line, front);
+ part1 += calcChecksumPart(frontIdNumber, nFileBlocks, position);
+ frontIdNumber++;
+ }
+ else
+ {
+ int nFreeBlocks = getDigit(line, front);
+ while (nFreeBlocks > 0)
+ {
+ if (nFreeBlocks >= nRemainingBackBlocks)
+ {
+ // Adds the checksum for all the blocks of the file at 'back'.
+ part1 += calcChecksumPart(backIdNumber, nRemainingBackBlocks, position);
+ backIdNumber--;
+
+ nFreeBlocks -= nRemainingBackBlocks;
+ back -= 2;
+ nRemainingBackBlocks = getDigit(line, back);
+ }
+ else
+ {
+ // Adds the checksum for the blocks of the file at 'back' that fit into the empty blocks at 'front'.
+ part1 += calcChecksumPart(backIdNumber, nFreeBlocks, position);
+
+ nRemainingBackBlocks -= nFreeBlocks;
+ nFreeBlocks = 0;
+ }
+ }
+ }
+ front++;
+ isFile = !isFile;
+ }
+
+ // Adds the checksum for the remaining blocks of the file at 'back'.
+ part1 += calcChecksumPart(backIdNumber, nRemainingBackBlocks, position);
+}
+
+void DiskFragmenter::finish()
+{
+}
+
+int DiskFragmenter::getDigit(const std::string& line, const size_t index) const
+{
+ return line[index] - '0';
+}
+
+long long int DiskFragmenter::calcChecksumPart(const size_t idNumber, const int nBlocks, size_t& position) const
+{
+ position += nBlocks;
+ return idNumber * ((nBlocks * (2 * position - nBlocks - 1)) / 2);
+}
diff --git a/src/Program.cpp b/src/Program.cpp
index a2358b0..8d3f1f1 100644
--- a/src/Program.cpp
+++ b/src/Program.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -57,6 +58,7 @@ void Program::runSolvers()
runSolver(solverEngine);
runSolver(solverEngine);
runSolver(solverEngine);
+ runSolver(solverEngine);
runSolver(solverEngine);
runSolver(solverEngine);
runSolver(solverEngine);
diff --git a/tests/src/TestCases.cpp b/tests/src/TestCases.cpp
index cb592a4..e0a875c 100644
--- a/tests/src/TestCases.cpp
+++ b/tests/src/TestCases.cpp
@@ -135,6 +135,19 @@ TEST_CASE("[ResonantCollinearityTests]")
}
}
+TEST_CASE("[DiskFragmenterTests]")
+{
+ TestContext test;
+ SECTION("FullData")
+ {
+ test.run(std::make_unique(), 6401092019345, 0, test.getInputPaths());
+ }
+ SECTION("ExampleData")
+ {
+ test.run(std::make_unique(), 1928, 0, test.getExampleInputPaths());
+ }
+}
+
TEST_CASE("[HoofItTests]")
{
TestContext test;