Add solution for "Day 2: Red-Nosed Reports", part 2

This commit is contained in:
Stefan Müller 2024-12-03 17:58:36 +01:00
parent fe67687bf7
commit 50fd4efc75
8 changed files with 199 additions and 20 deletions

View File

@ -131,6 +131,7 @@
<ClCompile Include="AdventOfCode2024.cpp" /> <ClCompile Include="AdventOfCode2024.cpp" />
<ClCompile Include="HistorianHysteria.cpp" /> <ClCompile Include="HistorianHysteria.cpp" />
<ClCompile Include="Program.cpp" /> <ClCompile Include="Program.cpp" />
<ClCompile Include="RedNosedReportData.cpp" />
<ClCompile Include="RedNosedReports.cpp" /> <ClCompile Include="RedNosedReports.cpp" />
<ClCompile Include="Solver.cpp" /> <ClCompile Include="Solver.cpp" />
<ClCompile Include="SolverEngine.cpp" /> <ClCompile Include="SolverEngine.cpp" />
@ -138,7 +139,9 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="HistorianHysteria.h" /> <ClInclude Include="HistorianHysteria.h" />
<ClInclude Include="Program.h" /> <ClInclude Include="Program.h" />
<ClInclude Include="RedNosedReportData.h" />
<ClInclude Include="RedNosedReports.h" /> <ClInclude Include="RedNosedReports.h" />
<ClInclude Include="Slope.h" />
<ClInclude Include="Solver.h" /> <ClInclude Include="Solver.h" />
<ClInclude Include="SolverEngine.h" /> <ClInclude Include="SolverEngine.h" />
</ItemGroup> </ItemGroup>

View File

@ -33,6 +33,9 @@
<ClCompile Include="RedNosedReports.cpp"> <ClCompile Include="RedNosedReports.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RedNosedReportData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="SolverEngine.h"> <ClInclude Include="SolverEngine.h">
@ -50,5 +53,11 @@
<ClInclude Include="RedNosedReports.h"> <ClInclude Include="RedNosedReports.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="RedNosedReportData.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Slope.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1 @@
#include "RedNosedReportData.h"

View File

@ -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 <http://www.gnu.org/licenses/>.
#pragma once
#include<vector>
#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<int> levels{};
};

View File

@ -15,9 +15,9 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <vector>
#include "RedNosedReports.h" #include "RedNosedReports.h"
#include <iomanip>
std::string RedNosedReports::getPuzzleName() const std::string RedNosedReports::getPuzzleName() const
{ {
@ -29,41 +29,148 @@ std::string RedNosedReports::getInputFileName() const
return "red-nosed_reports.txt"; 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) void RedNosedReports::processDataLine(const std::string& line)
{ {
auto isSafe{ true }; RedNosedReportData data{};
auto slope{ Slope::Unknown };
std::stringstream stream{ line }; std::stringstream stream{ line };
std::string token; std::string token;
std::getline(stream, 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) }; do
auto delta{ next - prev };
if (delta == 0 || delta > 3 || delta < -3
|| (delta > 0 && slope == Slope::Decreasing)
|| (delta < 0 && slope == Slope::Increasing))
{ {
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 else
{ {
prev = next; // X
if (slope == Slope::Unknown) // 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)
{ {
slope = delta > 0 ? Slope::Increasing : Slope::Decreasing; // X
// 1 1
data.isSafe = data.canUseDampener;
data.canUseDampener = false;
}
else if (delta > 0)
{
checkLastLevel(Slope::Increasing, Slope::Decreasing, delta, 1, data);
}
else
{
checkLastLevel(Slope::Decreasing, Slope::Increasing, -delta, -1, data);
} }
} }
} if (data.isSafe)
if (isSafe) {
if (data.canUseDampener)
{ {
part1++; part1++;
} }
part2++;
}
} }
void RedNosedReports::finish() 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;
}
}
}

View File

@ -15,7 +15,9 @@
#pragma once #pragma once
#include "Slope.h"
#include "Solver.h" #include "Solver.h"
#include "RedNosedReportData.h"
class RedNosedReports : class RedNosedReports :
public Solver public Solver
@ -25,6 +27,7 @@ class RedNosedReports :
std::string getInputFileName() const override; std::string getInputFileName() const override;
void processDataLine(const std::string& line) override; void processDataLine(const std::string& line) override;
void finish() 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 };

18
AdventOfCode2024/Slope.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#pragma once
enum class Slope { Unknown, Increasing, Decreasing };

View File

@ -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. 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: <https://adventofcode.com/2024/day/2>, :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 ## License
Copyright (C) 2024 Stefan Müller Copyright (C) 2024 Stefan Müller