Add proper CMake setup and update project structure

This commit is contained in:
2024-12-06 20:16:01 +01:00
parent fdfdca84e4
commit 38bca1e549
56 changed files with 282 additions and 681 deletions

70
src/HistorianHysteria.cpp Normal file
View File

@@ -0,0 +1,70 @@
// 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/>.
#include <iostream>
#include <aoc/HistorianHysteria.h>
std::string HistorianHysteria::getPuzzleName() const
{
return "Day 1: Historian Hysteria";
}
std::string HistorianHysteria::getInputFileName() const
{
return "historian_hysteria.txt";
}
void HistorianHysteria::processDataLine(const std::string& line)
{
auto pos = line.find(" ");
left.insert(std::stoi(line.substr(0, pos)));
right.insert(std::stoi(line.substr(pos + 3)));
}
void HistorianHysteria::finish()
{
int prev{ 0 };
auto nSame{ 0 };
auto leftIterator = left.begin();
auto rightIterator = right.begin();
auto rightSameIterator = right.begin();
while (leftIterator != left.end())
{
part1 += abs(*leftIterator - *rightIterator);
if (prev != *leftIterator)
{
nSame = 0;
// Skips over numbers in the right list that are smaller than the current left number.
while (rightSameIterator != right.end() && *rightSameIterator < *leftIterator)
{
rightSameIterator++;
}
// Counts the occurrences of the current left number in the right list.
while (rightSameIterator != right.end() && *rightSameIterator == *leftIterator)
{
rightSameIterator++;
nSame++;
}
prev = *leftIterator;
}
part2 += *leftIterator * nSame;
leftIterator++;
rightIterator++;
}
}

37
src/MullCharState.cpp Normal file
View File

@@ -0,0 +1,37 @@
// 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/>.
#include <aoc/MullCharState.h>
MullCharState::MullCharState(const char expected)
: expected_{ expected }, successState_{}, failState_{} {}
void MullCharState::next(StringStateMachine* stateMachine)
{
if (stateMachine->getCurrent() == expected_)
{
stateMachine->setState(*successState_);
}
else
{
stateMachine->setState(*failState_);
}
}
void MullCharState::setTransitions(StringState& successState, StringState& failState)
{
successState_ = &successState;
failState_ = &failState;
}

66
src/MullData.cpp Normal file
View File

@@ -0,0 +1,66 @@
// 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/>.
#include <aoc/MullData.h>
MullData::MullData()
: isEnabled_{ true }, factor1_{ 0 }, factor2_{ 0 }, part1_{ 0 }, part2_{ 0 } {};
bool MullData::getIsEnabled()
{
return isEnabled_;
}
void MullData::setIsEnabled(const bool value)
{
isEnabled_ = value;
}
int MullData::getFactor(const int index)
{
return index == 1 ? factor1_ : factor2_;
}
void MullData::setFactor(const int index, const int value)
{
if (index == 1)
{
factor1_ = value;
}
else
{
factor2_ = value;
}
}
void MullData::updateResult()
{
auto product = factor1_ * factor2_;
part1_ += product;
if (isEnabled_)
{
part2_ += product;
}
}
long long int MullData::getResultPart1()
{
return part1_;
}
long long int MullData::getResultPart2()
{
return part2_;
}

21
src/MullDataState.cpp Normal file
View File

@@ -0,0 +1,21 @@
// 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/>.
#include <aoc/MullDataState.h>
void MullDataState::setData(MullData& data)
{
data_ = &data;
}

39
src/MullDoOpenState.cpp Normal file
View File

@@ -0,0 +1,39 @@
// 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/>.
#include <aoc/MullDoOpenState.h>
void MullDoOpenState::next(StringStateMachine* stateMachine)
{
if (stateMachine->getCurrent() == '(' && !data_->getIsEnabled())
{
stateMachine->setState(*doState_);
}
else if (stateMachine->getCurrent() == 'n' && data_->getIsEnabled())
{
stateMachine->setState(*dontState_);
}
else
{
stateMachine->setState(*failState_);
}
}
void MullDoOpenState::setTransitions(StringState& doState, StringState& dontState, StringState& failState)
{
doState_ = &doState;
dontState_ = &dontState;
failState_ = &failState;
}

39
src/MullEntryState.cpp Normal file
View File

@@ -0,0 +1,39 @@
// 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/>.
#include <aoc/MullEntryState.h>
void MullEntryState::enter(StringStateMachine* stateMachine)
{
next(stateMachine);
}
void MullEntryState::next(StringStateMachine* stateMachine)
{
if (stateMachine->getCurrent() == 'm')
{
stateMachine->setState(*mulState_);
}
else if (stateMachine->getCurrent() == 'd')
{
stateMachine->setState(*doState_);
}
}
void MullEntryState::setTransitions(StringState& mulState, StringState& doState)
{
mulState_ = &mulState;
doState_ = &doState;
}

58
src/MullFactorState.cpp Normal file
View File

@@ -0,0 +1,58 @@
// 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/>.
#include <aoc/MullFactorState.h>
MullFactorState::MullFactorState(const char expected, const int index)
: expected_{ expected }, index_{ index }, successState_{}, failState_{} {}
void MullFactorState::enter(StringStateMachine* stateMachine)
{
data_->setFactor(index_, 0);
}
void MullFactorState::next(StringStateMachine* stateMachine)
{
if (stateMachine->getCurrent() == expected_ && data_->getFactor(index_) > 0)
{
if (index_ == 2)
{
data_->updateResult();
}
stateMachine->setState(*successState_);
}
else
{
int x = stateMachine->getCurrent() - '0';
if (0 <= x && x <= 9)
{
data_->setFactor(index_, data_->getFactor(index_) * 10 + x);
if (data_->getFactor(index_) > 999)
{
stateMachine->setState(*failState_);
}
}
else
{
stateMachine->setState(*failState_);
}
}
}
void MullFactorState::setTransitions(StringState& successState, StringState& failState)
{
successState_ = &successState;
failState_ = &failState;
}

44
src/MullItOver.cpp Normal file
View File

@@ -0,0 +1,44 @@
// 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/>.
#include <aoc/MullItOver.h>
#include <aoc/StringStateMachine.h>
MullItOver::MullItOver()
: Solver{}, data_{}, states_ {
data_
} {}
std::string MullItOver::getPuzzleName() const
{
return "Day 3: Mull It Over";
}
std::string MullItOver::getInputFileName() const
{
return "mull_it_over.txt";
}
void MullItOver::processDataLine(const std::string& line)
{
StringStateMachine stateMachine{ line, states_.entryState };
stateMachine.run();
}
void MullItOver::finish()
{
part1 = data_.getResultPart1();
part2 = data_.getResultPart2();
}

38
src/MullStates.cpp Normal file
View File

@@ -0,0 +1,38 @@
// 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/>.
#include <aoc/MullStates.h>
MullStates::MullStates(MullData& data)
{
entryState.setTransitions(uState, oState);
uState.setTransitions(lState, entryState);
lState.setTransitions(mulOpenState, entryState);
mulOpenState.setTransitions(factor1State, entryState);
factor1State.setData(data);
factor1State.setTransitions(factor2State, entryState);
factor2State.setData(data);
factor2State.setTransitions(entryState, entryState);
oState.setTransitions(doOpenState, entryState);
doOpenState.setData(data);
doOpenState.setTransitions(doCloseState, apostropheState, entryState);
doCloseState.setData(data);
doCloseState.setTransitions(entryState);
apostropheState.setTransitions(tState, entryState);
tState.setTransitions(dontOpenState, entryState);
dontOpenState.setTransitions(dontCloseState, entryState);
dontCloseState.setData(data);
dontCloseState.setTransitions(entryState);
}

View File

@@ -0,0 +1,33 @@
// 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/>.
#include <aoc/MullToggleCloseState.h>
MullToggleCloseState::MullToggleCloseState(const bool isEnabler)
: isEnabler_{ isEnabler }, successState_{} {}
void MullToggleCloseState::next(StringStateMachine* stateMachine)
{
if (stateMachine->getCurrent() == ')')
{
data_->setIsEnabled(isEnabler_);
}
stateMachine->setState(*successState_);
}
void MullToggleCloseState::setTransitions(StringState& successState)
{
successState_ = &successState;
}

44
src/Program.cpp Normal file
View File

@@ -0,0 +1,44 @@
// 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/>.
#include <iostream>
#include <memory>
#include <aoc/Program.h>
#include <aoc/SolverEngine.h>
// Solver implementations in day order.
#include <aoc/HistorianHysteria.h>
#include <aoc/RedNosedReports.h>
#include <aoc/MullItOver.h>
void Program::run()
{
std::cout << "### Advent of Code 2024 ###\n";
runSolvers();
}
void Program::runSolvers()
{
SolverEngine solverEngine{ getInputPaths() };
solverEngine.run(*std::make_unique<HistorianHysteria>());
solverEngine.run(*std::make_unique<RedNosedReports>());
solverEngine.run(*std::make_unique<MullItOver>());
}
std::vector<std::string> Program::getInputPaths() const
{
return std::vector<std::string>{ "data", "../../../data", "../../../../data" };
}

176
src/RedNosedReports.cpp Normal file
View File

@@ -0,0 +1,176 @@
// 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/>.
#include <iostream>
#include <sstream>
#include <vector>
#include <aoc/RedNosedReports.h>
std::string RedNosedReports::getPuzzleName() const
{
return "Day 2: Red-Nosed Reports";
}
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)
{
RedNosedReportData data{};
std::stringstream stream{ line };
std::string token;
std::getline(stream, token, ' ');
data.levels.push_back(std::stoi(token));
while (data.isSafe && std::getline(stream, token, ' '))
{
do
{
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
{
checkLastLevel(Slope::Decreasing, Slope::Increasing, -delta, -1, data);
}
}
if (data.isSafe)
{
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;
}
}
}

29
src/Solver.cpp Normal file
View File

@@ -0,0 +1,29 @@
// 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/>.
#include <aoc/Solver.h>
Solver::Solver()
: part1{ 0 }, part2{ 0 } {}
long long int Solver::getResultPart1() const
{
return part1;
}
long long int Solver::getResultPart2() const
{
return part2;
}

76
src/SolverEngine.cpp Normal file
View File

@@ -0,0 +1,76 @@
// 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/>.
#include <fstream>
#include <iostream>
#include <aoc/SolverEngine.h>
SolverEngine::SolverEngine(const std::vector<std::string>& inputPaths)
: inputPaths_{ inputPaths } {}
void SolverEngine::run(Solver& solver)
{
std::cout << "\n--- " << solver.getPuzzleName() << " ---\n";
auto fullFilePath = tryGetValidFullInputFilePath(solver.getInputFileName());
if (fullFilePath != "")
{
std::string line;
std::ifstream inputFile{ fullFilePath };
while (std::getline(inputFile, line))
{
solver.processDataLine(line);
}
inputFile.close();
solver.finish();
std::cout << "Part 1: " << solver.getResultPart1()
<< "\nPart 2: " << solver.getResultPart2() << std::endl;
}
}
std::filesystem::path SolverEngine::tryGetValidFullInputFilePath(const std::string& inputFileName)
{
for (auto path : inputPaths_)
{
std::filesystem::path fullFilePath = path;
fullFilePath /= inputFileName;
if (std::filesystem::exists(fullFilePath))
{
return fullFilePath;
}
}
std::cout << "Cannot find puzzle input file '";
for (size_t i = 0; i < inputPaths_.size(); i++)
{
std::filesystem::path fullFilePath = inputPaths_[i];
fullFilePath /= inputFileName;
std::cout << std::filesystem::absolute(fullFilePath).string();
if (i + 2 < inputPaths_.size())
{
std::cout << "', '";
}
else if (i + 1 < inputPaths_.size())
{
std::cout << "', or '";
}
}
std::cout << "'. Please download the file content from https://adventofcode.com/2024/\n";
return "";
}

View File

@@ -0,0 +1,46 @@
// 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/>.
#include <aoc/StringStateMachine.h>
StringStateMachine::StringStateMachine(const std::string& line, StringState& entryState)
{
line_ = line;
entryState_ = &entryState;
currentState_ = entryState_;
current_ = ' ';
}
void StringStateMachine::run()
{
currentState_ = entryState_;
for (auto c : line_)
{
current_ = c;
currentState_->next(this);
}
}
char StringStateMachine::getCurrent() const
{
return current_;
}
void StringStateMachine::setState(StringState& state)
{
currentState_->exit(this);
currentState_ = &state;
currentState_->enter(this);
}