// 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 .
#include
#include
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();
}
}
}
}