From 54204766ece8b2b10c6da24c3d494fbf1c4c3a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Tue, 4 Feb 2025 17:44:06 +0100 Subject: [PATCH] Add solution for "Day 9: Disk Fragmenter", part 1 --- include/aoc/DiskFragmenter.hpp | 31 ++++++++++ src/DiskFragmenter.cpp | 103 +++++++++++++++++++++++++++++++++ src/Program.cpp | 2 + tests/src/TestCases.cpp | 13 +++++ 4 files changed, 149 insertions(+) create mode 100644 include/aoc/DiskFragmenter.hpp create mode 100644 src/DiskFragmenter.cpp 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;