diff --git a/include/aoc/RaceCondition.hpp b/include/aoc/RaceCondition.hpp new file mode 100644 index 0000000..cca4cd2 --- /dev/null +++ b/include/aoc/RaceCondition.hpp @@ -0,0 +1,37 @@ +// 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 RaceCondition + : public LinesSolver +{ +public: + RaceCondition(const int threshold = 100); + virtual const std::string getPuzzleName() const override; + virtual const int getPuzzleDay() const override; + virtual void finish() override; +private: + static constexpr char getStartChar(); + static constexpr char getWallChar(); + static constexpr int getCheatLength(); + const std::array doubleSteps_{ Point2::down * 2, Point2::downRight, Point2::right * 2, + Point2::upRight, Point2::up * 2, Point2::upLeft, Point2::left * 2, Point2::downLeft }; + int threshold_; + void checkCheat(const Point2& position, Grid& times); +}; diff --git a/src/Program.cpp b/src/Program.cpp index 0284db3..79e8586 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include void Program::run() @@ -77,6 +78,7 @@ void Program::runSolvers() runSolver(solverEngine); runSolver(solverEngine); runSolver(solverEngine); + runSolver(solverEngine); runSolver(solverEngine); } diff --git a/src/RaceCondition.cpp b/src/RaceCondition.cpp new file mode 100644 index 0000000..dcb26cd --- /dev/null +++ b/src/RaceCondition.cpp @@ -0,0 +1,91 @@ +// 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 + +RaceCondition::RaceCondition(const int threshold) + : threshold_{ threshold } +{ +} + +const std::string RaceCondition::getPuzzleName() const +{ + return "Race Condition"; +} + +const int RaceCondition::getPuzzleDay() const +{ + return 20; +} + +void RaceCondition::finish() +{ + int time{ 0 }; + Grid times{ lines.size(), lines[0].size() }; + // Fills the grid with a number that is guaranteed to be greater than the length of the path. + times.fill(static_cast(times.getNColumns() * times.getNRows())); + + Point2 position{ findChar(getStartChar()) }; + Point2 previous{ -1, -1 }; + while (position != previous) + { + // Tracks time for current position. + times.cell(position) = time++; + + // Checks if there is a cheat leading to the current position. + checkCheat(position, times); + + // Progresses the race path. + auto oldPosition = position; + for (const auto& direction : Point2::cardinalDirections) + { + auto next = position + direction; + if (next != previous && getCharAt(next) != getWallChar()) + { + position = next; + break; + } + } + previous = oldPosition; + } +} + +constexpr char RaceCondition::getStartChar() +{ + return 'S'; +} + +constexpr char RaceCondition::getWallChar() +{ + return '#'; +} + +constexpr int RaceCondition::getCheatLength() +{ + return 2; +} + +void RaceCondition::checkCheat(const Point2& position, Grid& times) +{ + auto time = times.cell(position); + for (auto& direction : doubleSteps_) + { + auto other = position + direction; + if (isInBounds(other) && time >= threshold_ + times.cell(other) + getCheatLength()) + { + part1++; + } + } +} diff --git a/tests/src/TestCases.cpp b/tests/src/TestCases.cpp index 4ac4211..322d5ed 100644 --- a/tests/src/TestCases.cpp +++ b/tests/src/TestCases.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); } @@ -354,6 +355,19 @@ TEST_CASE("[LinenLayoutTests]") } } +TEST_CASE("[RaceConditionTests]") +{ + TestContext test; + SECTION("FullData") + { + test.runFull(std::make_unique(), 1448, 0); + } + SECTION("ExampleData") + { + test.runExample(std::make_unique(2), 44, 0); + } +} + TEST_CASE("[LanPartyTests]") { TestContext test;