Add solution for "Day 18: RAM Run", part 2

This commit is contained in:
2025-05-25 21:15:11 +02:00
parent bb1dab33e9
commit f8f431b61a
7 changed files with 113 additions and 27 deletions

View File

@@ -35,22 +35,42 @@ const int RamRun::getPuzzleDay() const
void RamRun::processDataLine(const std::string& line)
{
if (maxBytes_ > nBytes_++)
if (part2 == "")
{
std::istringstream stream{ line };
Point2 position;
char c;
if (stream >> position.x >> c >> position.y)
int corrupted{ -1 };
if (!tryMarkCorrupted(line, corrupted))
{
vertexReferences_.cell(position) = getNoVertexReference();
return;
}
if (maxBytes_ == nBytes_)
if (maxBytes_ == ++nBytes_)
{
WeightedEdgeGraph graph{};
buildGraph(graph);
auto distances = graph.dijkstra(vertexReferences_[0][0]);
part1 = distances[vertexReferences_[memorySize_ - 1][memorySize_ - 1]];
// 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;
}
}
}
}
}
@@ -69,8 +89,25 @@ constexpr char RamRun::getNoVertexReference()
return -2;
}
void RamRun::buildGraph(WeightedEdgeGraph& graph)
// 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++)
@@ -95,6 +132,8 @@ void RamRun::buildGraph(WeightedEdgeGraph& graph)
}
}
}
return graph;
}
int RamRun::getVertex(WeightedEdgeGraph& graph, const size_t x, const size_t y)
@@ -105,3 +144,17 @@ int RamRun::getVertex(WeightedEdgeGraph& graph, const size_t x, const size_t y)
}
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();
}
}
}
}

View File

@@ -45,9 +45,9 @@ void ReindeerMaze::finish()
auto exit = graph.addVertex(0);
buildPathSegmentGraph(graph, vertexAttachedPositions, entry, exit);
auto shortestDistances = graph.dijkstra(exit);
part1 = shortestDistances[entry] / 2;
part2 = calcShortestPaths(graph, vertexAttachedPositions, entry, exit, shortestDistances);
auto result = graph.dijkstra(exit);
part1 = result.distances[entry] / 2;
part2 = calcShortestPaths(graph, vertexAttachedPositions, entry, exit, result.distances);
}
constexpr char ReindeerMaze::getStartChar()

View File

@@ -49,13 +49,13 @@ int WeightedEdgeGraph::getEdgeWeight(const int edge) const
return edgeWeights_[edge];
}
std::vector<int> WeightedEdgeGraph::dijkstra(const int source) const
WeightedEdgeGraph::PathsResult WeightedEdgeGraph::dijkstra(const int source) const
{
std::vector<int> distances(firstVertexIncidences_.size(), std::numeric_limits<int>::max());
auto compare = [&distances](int left, int right) { return distances[left] > distances[right]; };
PathsResult result(firstVertexIncidences_.size(), getInfiniteDistance(), -1);
auto compare = [&result](int left, int right) { return result.distances[left] > result.distances[right]; };
std::priority_queue<int, std::vector<int>, decltype(compare)> queue{ compare };
distances[source] = 0;
result.distances[source] = 0;
queue.push(source);
while (!queue.empty())
@@ -65,16 +65,22 @@ std::vector<int> WeightedEdgeGraph::dijkstra(const int source) const
for (auto neighbor = begin(v); neighbor != end(); ++neighbor)
{
int newDistance{ distances[v] + edgeWeights_[neighbor->edge] };
if (distances[neighbor->vertex] > newDistance)
int newDistance{ result.distances[v] + edgeWeights_[neighbor->edge] };
if (result.distances[neighbor->vertex] > newDistance)
{
distances[neighbor->vertex] = newDistance;
result.distances[neighbor->vertex] = newDistance;
result.predecessors[neighbor->vertex] = v;
queue.push(neighbor->vertex);
}
}
}
return distances;
return result;
}
constexpr int WeightedEdgeGraph::getInfiniteDistance()
{
return std::numeric_limits<int>::max();
}
WeightedEdgeGraph::NeighborIterator WeightedEdgeGraph::begin(const int vertex) const