diff --git a/AdventOfCode2024/AdventOfCode2024.vcxproj b/AdventOfCode2024/AdventOfCode2024.vcxproj index 7b8c698..d648ef5 100644 --- a/AdventOfCode2024/AdventOfCode2024.vcxproj +++ b/AdventOfCode2024/AdventOfCode2024.vcxproj @@ -131,6 +131,7 @@ + @@ -138,7 +139,9 @@ + + diff --git a/AdventOfCode2024/AdventOfCode2024.vcxproj.filters b/AdventOfCode2024/AdventOfCode2024.vcxproj.filters index 399c5a9..56695fd 100644 --- a/AdventOfCode2024/AdventOfCode2024.vcxproj.filters +++ b/AdventOfCode2024/AdventOfCode2024.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + @@ -50,5 +53,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/AdventOfCode2024/RedNosedReportData.cpp b/AdventOfCode2024/RedNosedReportData.cpp new file mode 100644 index 0000000..f0010e5 --- /dev/null +++ b/AdventOfCode2024/RedNosedReportData.cpp @@ -0,0 +1 @@ +#include "RedNosedReportData.h" diff --git a/AdventOfCode2024/RedNosedReportData.h b/AdventOfCode2024/RedNosedReportData.h new file mode 100644 index 0000000..1da4240 --- /dev/null +++ b/AdventOfCode2024/RedNosedReportData.h @@ -0,0 +1,32 @@ +// Solutions to the Advent Of Code 2024. +// Copyright (C) 2024 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 "Slope.h" + +class RedNosedReportData +{ +public: + bool isSafe{ true }; + bool canUseDampener{ true }; + bool mustSkipPrevious{ false }; + bool mustCheckSlopeReversal{ false }; + bool mustAwaitFourLevels{ false }; + Slope slope{ Slope::Unknown }; + std::vector levels{}; +}; diff --git a/AdventOfCode2024/RedNosedReports.cpp b/AdventOfCode2024/RedNosedReports.cpp index 7587854..157f082 100644 --- a/AdventOfCode2024/RedNosedReports.cpp +++ b/AdventOfCode2024/RedNosedReports.cpp @@ -15,9 +15,9 @@ #include #include +#include #include "RedNosedReports.h" -#include std::string RedNosedReports::getPuzzleName() const { @@ -29,41 +29,148 @@ std::string RedNosedReports::getInputFileName() const return "red-nosed_reports.txt"; } +// 'X' in the comments here and below marks the level that must be ignored to +// make the report safe. +// 'first' means that this series starts at the beginning of the line. +// 'next' means that the level(s) from the next loop iteration(s) will determine +// which level to ignore. void RedNosedReports::processDataLine(const std::string& line) { - auto isSafe{ true }; - auto slope{ Slope::Unknown }; + RedNosedReportData data{}; std::stringstream stream{ line }; std::string token; std::getline(stream, token, ' '); - auto prev{ std::stoi(token) }; + data.levels.push_back(std::stoi(token)); - while (isSafe && std::getline(stream, token, ' ')) + while (data.isSafe && std::getline(stream, token, ' ')) { - auto next{ std::stoi(token) }; - auto delta{ next - prev }; - if (delta == 0 || delta > 3 || delta < -3 - || (delta > 0 && slope == Slope::Decreasing) - || (delta < 0 && slope == Slope::Increasing)) + do { - isSafe = false; + data.levels.push_back(std::stoi(token)); + } while (data.mustAwaitFourLevels && data.levels.size() < 4 + && std::getline(stream, token, ' ')); + + if (data.mustCheckSlopeReversal) + { + auto it = data.levels.rbegin(); + if (data.slope == Slope::Decreasing && *it > *(++it)) + { + // X + // first 3 2 6 7 + data.slope = Slope::Increasing; + } + else if (data.slope == Slope::Increasing && *it < *(++it)) + { + // X + // first 6 7 3 2 + data.slope = Slope::Decreasing; + } + else + { + // X + // first 3 2 6 1 + // first 6 7 3 8 + data.mustSkipPrevious = true; + } + } + data.mustCheckSlopeReversal = false; + + auto it = data.levels.rbegin(); + auto delta{ *it }; + delta -= *(++(data.mustSkipPrevious ? ++it : it)); + data.mustSkipPrevious = false; + + if (delta == 0) + { + // X + // 1 1 + data.isSafe = data.canUseDampener; + data.canUseDampener = false; + } + else if (delta > 0) + { + checkLastLevel(Slope::Increasing, Slope::Decreasing, delta, 1, data); } else { - prev = next; - if (slope == Slope::Unknown) - { - slope = delta > 0 ? Slope::Increasing : Slope::Decreasing; - } + checkLastLevel(Slope::Decreasing, Slope::Increasing, -delta, -1, data); } } - if (isSafe) + if (data.isSafe) { - part1++; + if (data.canUseDampener) + { + part1++; + } + part2++; } } void RedNosedReports::finish() { } + +void RedNosedReports::checkLastLevel(const Slope sameSlope, const Slope otherSlope, + const int delta, const int sign, RedNosedReportData& data) +{ + if (data.slope == sameSlope) + { + if (delta > 3) + { + // X X + // 1 2 6 8 7 3 + data.mustSkipPrevious = true; + data.isSafe = data.canUseDampener; + data.canUseDampener = false; + } + } + else if (data.slope == otherSlope) + { + if (data.levels.size() == 3 && sign * (data.levels[2] - data.levels[0]) <= 3) + { + // X X next X X next + // first 3 2 6 ??? first 6 7 3 ??? + data.mustCheckSlopeReversal = true; + } + else + { + // X X + // first 3 2 7 first 6 7 2 + // 3 2 1 4 6 7 8 5 + data.mustSkipPrevious = true; + } + data.isSafe = data.canUseDampener; + data.canUseDampener = false; + } + else // slope == Slope::Unknown + { + if (delta <= 3) + { + data.slope = sameSlope; + } + if (data.mustAwaitFourLevels) + { + if (delta <= 3 + && ((0 < sign * (data.levels[2] - data.levels[0]) && sign * (data.levels[2] - data.levels[0]) <= 3) + || (0 < sign * (data.levels[2] - data.levels[1]) && sign * (data.levels[2] - data.levels[1]) <= 3))) + { + // X X X X + // first 1 5 3 4 first 8 4 6 5 + data.mustAwaitFourLevels = false; + } + else + { + data.isSafe = false; + } + } + else if (delta > 3) + { + // X X next X X next + // first 1 5 ??? first 8 4 ??? + data.mustAwaitFourLevels = true; + data.isSafe = data.canUseDampener; + data.canUseDampener = false; + } + } +} diff --git a/AdventOfCode2024/RedNosedReports.h b/AdventOfCode2024/RedNosedReports.h index ea8cd0c..3386c7f 100644 --- a/AdventOfCode2024/RedNosedReports.h +++ b/AdventOfCode2024/RedNosedReports.h @@ -15,7 +15,9 @@ #pragma once +#include "Slope.h" #include "Solver.h" +#include "RedNosedReportData.h" class RedNosedReports : public Solver @@ -25,6 +27,7 @@ class RedNosedReports : std::string getInputFileName() const override; void processDataLine(const std::string& line) override; void finish() override; +private: + void checkLastLevel(const Slope sameSlope, const Slope otherSlope, + const int delta, const int sign, RedNosedReportData& data); }; - -enum class Slope { Unknown, Increasing, Decreasing }; diff --git a/AdventOfCode2024/Slope.h b/AdventOfCode2024/Slope.h new file mode 100644 index 0000000..3aef8e4 --- /dev/null +++ b/AdventOfCode2024/Slope.h @@ -0,0 +1,18 @@ +// Solutions to the Advent Of Code 2024. +// Copyright (C) 2024 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 Slope { Unknown, Increasing, Decreasing }; diff --git a/README.md b/README.md index 42536f0..df55d83 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ The solution contains a unit test project to help troubleshoot issues and preven I'm using a `std::multiset` to collect and sort the values for both lists. This allows to use a single iteration of the left list and two iterations of the right list simultaneously to solve both parts. Nice application of iterators. +### Day 2: Red-Nosed Reports + +:mag_right: Puzzle: , :white_check_mark: Solver: [`HistorianHysteria.cpp`](AdventOfCode2024/RedNosedReports.cpp) + +Here, we have a few conditionals to determine on the fly which of the numbers would make the report safe if dropped. The amount of cases is actually quite manageable. + ## License Copyright (C) 2024 Stefan Müller