Merge branch 'cmake'

This commit is contained in:
2024-12-08 10:50:06 +01:00
67 changed files with 357 additions and 925 deletions

80
src/CeresSearch.cpp Normal file
View File

@@ -0,0 +1,80 @@
// 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/CeresSearch.h>
std::string CeresSearch::getPuzzleName() const
{
return "Day 4: Ceres Search";
}
std::string CeresSearch::getInputFileName() const
{
return "ceres_search.txt";
}
void CeresSearch::finish()
{
for (int j = 0; j < lines.size(); j++)
{
for (int i = 0; i < lines[j].size(); i++)
{
if (lines[j][i] == xmas[0])
{
Point2 start{ i, j };
computeXmasCount(start);
}
else if (lines[j][i] == xmas[2])
{
Point2 start{ i, j };
computeX_MasCount(start);
}
}
}
}
void CeresSearch::computeXmasCount(const Point2& start)
{
for (auto d : Point2::directions)
{
auto p{ start + d };
auto i{ 1 };
while (i < 4 && isInBounds(p) && xmas[i] == getPosition(p))
{
p += d;
i++;
}
if (i == 4)
{
part1++;
}
}
}
void CeresSearch::computeX_MasCount(const Point2& start)
{
auto pUL{ start + Point2::upLeft };
auto pDR{ start + Point2::downRight };
auto pUR{ start + Point2::upRight };
auto pDL{ start + Point2::downLeft };
if (isInBounds(pUL) && isInBounds(pDR)
&& ((getPosition(pUL) == xmas[1] && getPosition(pDR) == xmas[3])
|| (getPosition(pUL) == xmas[3] && getPosition(pDR) == xmas[1]))
&& ((getPosition(pUR) == xmas[1] && getPosition(pDL) == xmas[3])
|| (getPosition(pUR) == xmas[3] && getPosition(pDL) == xmas[1])))
{
part2++;
}
}

91
src/GuardGallivant.cpp Normal file
View File

@@ -0,0 +1,91 @@
// 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/GuardGallivant.h>
std::string GuardGallivant::getPuzzleName() const
{
return "Day 6: Guard Gallivant";
}
std::string GuardGallivant::getInputFileName() const
{
return "guard_gallivant.txt";
}
void GuardGallivant::processDataLine(const std::string& line)
{
LinesSolver::processDataLine(line);
auto pos{ line.find(getStartChar()) };
if (pos != std::string::npos)
{
start_ = Point2{ static_cast<int>(pos), static_cast<int>(lines.size() - 1) };
}
}
void GuardGallivant::finish()
{
auto dirIndex{ getStartDirectionIndex() };
auto current{ start_ };
visitPosition(current);
auto next{ current + Point2::cardinalDirections[dirIndex] };
while (isInBounds(next))
{
if (getPosition(next) == getObstructionChar())
{
dirIndex = turnDirection(dirIndex);
}
else
{
current = next;
visitPosition(current);
}
next = current + Point2::cardinalDirections[dirIndex];
}
}
void GuardGallivant::visitPosition(const Point2& current)
{
if (getPosition(current) != getVisitedChar())
{
setPosition(current, getVisitedChar());
part1++;
}
}
size_t GuardGallivant::turnDirection(const size_t current) const
{
return current == 0 ? 3 : current - 1;
}
size_t GuardGallivant::getStartDirectionIndex() const
{
return 2;
}
char GuardGallivant::getStartChar() const
{
return '^';
}
char GuardGallivant::getVisitedChar() const
{
return 'X';
}
char GuardGallivant::getObstructionChar() const
{
return '#';
}

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/LinesSolver.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/LinesSolver.h>
void LinesSolver::processDataLine(const std::string& line)
{
lines.push_back(line);
}
bool LinesSolver::isInBounds(const Point2& point) const
{
return 0 <= point.y && point.y < lines.size()
&& 0 <= point.x && point.x < lines[point.y].size();
}
char LinesSolver::getPosition(const Point2& point) const
{
return lines[point.y][point.x];
}
void LinesSolver::setPosition(const Point2& point, const char value)
{
lines[point.y][point.x] = value;
}

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;
}

83
src/Point2.cpp Normal file
View File

@@ -0,0 +1,83 @@
// 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/Point2.h>
const Point2 Point2::left{ -1, 0 };
const Point2 Point2::right{ 1, 0 };
const Point2 Point2::up{ 0, -1 };
const Point2 Point2::down{ 0, 1 };
const Point2 Point2::upLeft{ -1, -1 };
const Point2 Point2::upRight{ 1, -1 };
const Point2 Point2::downLeft{ -1, 1 };
const Point2 Point2::downRight{ 1, 1 };
const Point2 Point2::directions[] = { Point2::down, Point2::downRight, Point2::right,
Point2::upRight, Point2::up, Point2::upLeft, Point2::left, Point2::downLeft };
const Point2 Point2::cardinalDirections[] = { Point2::down, Point2::right, Point2::up,
Point2::left};
Point2::Point2()
: Point2{ 0, 0 } {}
Point2::Point2(const int x, const int y)
: x{ x }, y{ y } {}
bool Point2::operator==(const Point2& rhs) const
{
return x == rhs.x && y == rhs.y;
}
bool Point2::operator!=(const Point2& rhs) const
{
return !(x == y);
}
Point2 Point2::operator+(const Point2& rhs) const
{
return Point2(x + rhs.x, y + rhs.y);
}
Point2 Point2::operator-(const Point2& rhs) const
{
return Point2(x - rhs.x, y - rhs.y);
}
Point2 Point2::operator*(const int rhs) const
{
return Point2(x * rhs, y * rhs);
}
Point2 Point2::operator-() const
{
return Point2(-x, -y);
}
Point2& Point2::operator+=(const Point2& rhs)
{
*this = *this + rhs;
return *this;
}
Point2& Point2::operator-=(const Point2& rhs)
{
*this = *this - rhs;
return *this;
}
Point2& Point2::operator*=(const int rhs)
{
*this = *this * rhs;
return *this;
}

120
src/PrintQueue.cpp Normal file
View File

@@ -0,0 +1,120 @@
// 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 <algorithm>
#include <sstream>
#include <vector>
#include <aoc/PrintQueue.h>
PrintQueue::PrintQueue()
: Solver{}, pageNoMapIndex_{ 0 }, isProcessingOrderingRules_{ true }, orderingRules_{}
{
for (size_t i = 0; i <= maxPageNo_; i++)
{
pageNoMap_[i] = -1;
}
for (size_t i = 0; i < nPages_; i++)
{
for (size_t j = 0; j < nPages_; j++)
{
orderingRules_[i][j] = false;
}
}
}
std::string PrintQueue::getPuzzleName() const
{
return "Day 5: Print Queue";
}
std::string PrintQueue::getInputFileName() const
{
return "print_queue.txt";
}
void PrintQueue::processDataLine(const std::string& line)
{
if (isProcessingOrderingRules_)
{
if (line.empty())
{
isProcessingOrderingRules_ = false;
}
else
{
processOrderingRule(line);
}
}
else
{
processUpdatePages(line);
}
}
void PrintQueue::finish()
{
}
size_t PrintQueue::getMapped(const int pageNo)
{
if (pageNoMap_[pageNo] < 0)
{
pageNoMap_[pageNo] = pageNoMapIndex_++;
}
return pageNoMap_[pageNo];
}
void PrintQueue::processOrderingRule(const std::string& line)
{
auto pos{ line.find("|") };
auto before{ std::stoi(line.substr(0, pos)) };
auto after{ std::stoi(line.substr(pos + 1)) };
orderingRules_[getMapped(before)][getMapped(after)] = true;
}
void PrintQueue::processUpdatePages(const std::string& line)
{
std::vector<size_t> pages{};
std::stringstream stream{ line };
std::string token;
auto isCorrectOrder{ true };
// We completely construct 'pages' for part 2, even if the ordering is not correct.
while (std::getline(stream, token, ','))
{
size_t page = std::stoi(token);
size_t i{ 0 };
while (isCorrectOrder && i < pages.size())
{
isCorrectOrder = !orderingRules_[getMapped(page)][getMapped(pages[i])];
i++;
}
pages.push_back(page);
}
if (isCorrectOrder)
{
part1 += pages[pages.size() / 2];
}
else
{
// This works because the input defines a complete ordering on the occurring
// page numbers.
std::sort(pages.begin(), pages.end(),
[&](int const& a, int const& b) { return orderingRules_[getMapped(a)][getMapped(b)]; });
part2 += pages[pages.size() / 2];
}
}

50
src/Program.cpp Normal file
View File

@@ -0,0 +1,50 @@
// 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>
#include <aoc/CeresSearch.h>
#include <aoc/PrintQueue.h>
#include <aoc/GuardGallivant.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>());
solverEngine.run(*std::make_unique<CeresSearch>());
solverEngine.run(*std::make_unique<PrintQueue>());
solverEngine.run(*std::make_unique<GuardGallivant>());
}
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);
}