161 lines
4.7 KiB
C++
161 lines
4.7 KiB
C++
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#include <aoc/RamRun.hpp>
|
|
|
|
#include <sstream>
|
|
|
|
RamRun::RamRun(const size_t memorySize, const int maxBytes)
|
|
: memorySize_{ memorySize }, maxBytes_{ maxBytes }, nBytes_{ 0 }, vertexReferences_{ memorySize, memorySize }
|
|
{
|
|
vertexReferences_.fill(getUnknownVertexReference());
|
|
}
|
|
|
|
const std::string RamRun::getPuzzleName() const
|
|
{
|
|
return "RAM Run";
|
|
}
|
|
|
|
const int RamRun::getPuzzleDay() const
|
|
{
|
|
return 18;
|
|
}
|
|
|
|
void RamRun::processDataLine(const std::string& line)
|
|
{
|
|
if (part2 == "")
|
|
{
|
|
int corrupted{ -1 };
|
|
if (!tryMarkCorrupted(line, corrupted))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (maxBytes_ == ++nBytes_)
|
|
{
|
|
// Calculates initial distances.
|
|
auto graph = buildGraph();
|
|
dijkstraResult_ = graph.dijkstra(vertexReferences_[0][0]);
|
|
part1 = dijkstraResult_.distances[vertexReferences_[memorySize_ - 1][memorySize_ - 1]];
|
|
}
|
|
else if (maxBytes_ < nBytes_)
|
|
{
|
|
int pathVertex = vertexReferences_[memorySize_ - 1][memorySize_ - 1];
|
|
while (pathVertex >= 0 && pathVertex != corrupted)
|
|
{
|
|
pathVertex = dijkstraResult_.predecessors[pathVertex];
|
|
}
|
|
if (pathVertex == corrupted)
|
|
{
|
|
// Calculates new paths and distances after path was interruped by corrupted position, and checks if path
|
|
// is now blocked.
|
|
resetVertexReferences();
|
|
auto graph = buildGraph();
|
|
dijkstraResult_ = graph.dijkstra(vertexReferences_[0][0]);
|
|
if (dijkstraResult_.distances[vertexReferences_[memorySize_ - 1][memorySize_ - 1]]
|
|
== WeightedEdgeGraph::getInfiniteDistance())
|
|
{
|
|
// Path is blocked.
|
|
part2 = line;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RamRun::finish()
|
|
{
|
|
}
|
|
|
|
constexpr char RamRun::getUnknownVertexReference()
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
constexpr char RamRun::getNoVertexReference()
|
|
{
|
|
return -2;
|
|
}
|
|
|
|
// Marks the position extracted from the 'line' as corrupted in the vertex reference grid.
|
|
bool RamRun::tryMarkCorrupted(const std::string& line, int& corruptedVertex)
|
|
{
|
|
std::istringstream stream{ line };
|
|
Point2 position;
|
|
char c;
|
|
if (stream >> position.x >> c >> position.y)
|
|
{
|
|
corruptedVertex = vertexReferences_.cell(position);
|
|
vertexReferences_.cell(position) = getNoVertexReference();
|
|
return true;
|
|
}
|
|
corruptedVertex = -1;
|
|
return false;
|
|
}
|
|
|
|
WeightedEdgeGraph RamRun::buildGraph()
|
|
{
|
|
WeightedEdgeGraph graph;
|
|
for (size_t j = 0; j < vertexReferences_.getNRows(); j++)
|
|
{
|
|
for (size_t i = 0; i < vertexReferences_.getNColumns(); i++)
|
|
{
|
|
if (vertexReferences_[j][i] != getNoVertexReference())
|
|
{
|
|
int v{ getVertex(graph, i, j) };
|
|
if (i != 0)
|
|
{
|
|
if (vertexReferences_[j][i - 1] != getNoVertexReference())
|
|
{
|
|
graph.addEdge(getVertex(graph, i - 1, j), v, 1);
|
|
}
|
|
}
|
|
if (j != 0)
|
|
{
|
|
if (vertexReferences_[j - 1][i] != getNoVertexReference())
|
|
{
|
|
graph.addEdge(getVertex(graph, i, j - 1), v, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return graph;
|
|
}
|
|
|
|
int RamRun::getVertex(WeightedEdgeGraph& graph, const size_t x, const size_t y)
|
|
{
|
|
if (vertexReferences_[y][x] == getUnknownVertexReference())
|
|
{
|
|
vertexReferences_[y][x] = graph.addVertex();
|
|
}
|
|
return vertexReferences_[y][x];
|
|
}
|
|
|
|
void RamRun::resetVertexReferences()
|
|
{
|
|
for (size_t j = 0; j < vertexReferences_.getNRows(); j++)
|
|
{
|
|
for (size_t i = 0; i < vertexReferences_.getNColumns(); i++)
|
|
{
|
|
if (vertexReferences_[j][i] != getNoVertexReference())
|
|
{
|
|
vertexReferences_[j][i] = getUnknownVertexReference();
|
|
}
|
|
}
|
|
}
|
|
}
|