mirror of
https://github.com/parnic/advent-of-code-2022.git
synced 2025-06-16 13:40:13 -05:00
Dramatic speedup for day 12 part 2
This enables a flood-fill of distances from the goal location to every other location on the grid. With that, we only have to locate the node with the lowest distance value. Technically this also solves part 1, but I wanted to leave the forward search in place as a test of sorts that the algorithm works both ways. Now if I can just get the parse sped up...
This commit is contained in:
64
src/12.cs
64
src/12.cs
@ -35,9 +35,7 @@ internal class Day12 : Day
|
|||||||
{
|
{
|
||||||
if (ReferenceEquals(null, other)) return false;
|
if (ReferenceEquals(null, other)) return false;
|
||||||
if (ReferenceEquals(this, other)) return true;
|
if (ReferenceEquals(this, other)) return true;
|
||||||
return neighbors.Equals(other.neighbors)
|
return location.Equals(other.location);
|
||||||
&& distance == other.distance
|
|
||||||
&& location.Equals(other.location);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
@ -67,7 +65,7 @@ internal class Day12 : Day
|
|||||||
location = loc;
|
location = loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(neighbors, location);
|
public override int GetHashCode() => location.GetHashCode();
|
||||||
public override string ToString() => $"{location}, {neighbors.Count} neighbor{(neighbors.Count == 1 ? "" : "s")}, dist: {distance ?? -1}";
|
public override string ToString() => $"{location}, {neighbors.Count} neighbor{(neighbors.Count == 1 ? "" : "s")}, dist: {distance ?? -1}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,17 +109,16 @@ internal class Day12 : Day
|
|||||||
}
|
}
|
||||||
|
|
||||||
heights[x][y] = ch - 'a';
|
heights[x][y] = ch - 'a';
|
||||||
|
allNodes.Add(new DNode(new point(x, y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startNode = new DNode(start!);
|
startNode = new DNode(start!);
|
||||||
allNodes.Add(startNode);
|
|
||||||
|
|
||||||
var unvisited = new HashSet<DNode>(allNodes);
|
var unvisited = new HashSet<DNode>(allNodes);
|
||||||
DNode? current = startNode;
|
DNode? current = startNode;
|
||||||
while (current != null)
|
while (current != null)
|
||||||
{
|
{
|
||||||
var currHeight = heights[current.location.x][current.location.y];
|
|
||||||
foreach (var offset in offsets)
|
foreach (var offset in offsets)
|
||||||
{
|
{
|
||||||
var test = current.location + offset;
|
var test = current.location + offset;
|
||||||
@ -130,18 +127,8 @@ internal class Day12 : Day
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var testHeight = heights[test.x][test.y];
|
var found = allNodes.First(n => n.location == test);
|
||||||
if (testHeight <= currHeight + 1)
|
current.neighbors.Add(found);
|
||||||
{
|
|
||||||
var found = allNodes.FirstOrDefault(n => n.location == test);
|
|
||||||
if (found == null)
|
|
||||||
{
|
|
||||||
found = new DNode(test);
|
|
||||||
allNodes.Add(found);
|
|
||||||
unvisited.Add(found);
|
|
||||||
}
|
|
||||||
current.neighbors.Add(found);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unvisited.Remove(current);
|
unvisited.Remove(current);
|
||||||
@ -151,10 +138,8 @@ internal class Day12 : Day
|
|||||||
goalNode = allNodes.First(n => n.location == goal!);
|
goalNode = allNodes.First(n => n.location == goal!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long? FindDistance(DNode from, DNode to)
|
private void DijkstraFlood(DNode from, DNode to, bool reverse = false)
|
||||||
{
|
{
|
||||||
long? distance = null;
|
|
||||||
|
|
||||||
allNodes.ForEach(n =>
|
allNodes.ForEach(n =>
|
||||||
{
|
{
|
||||||
n.distance = null;
|
n.distance = null;
|
||||||
@ -165,7 +150,19 @@ internal class Day12 : Day
|
|||||||
DNode? current = from;
|
DNode? current = from;
|
||||||
while (current != null)
|
while (current != null)
|
||||||
{
|
{
|
||||||
foreach (var n in current.neighbors.Where(n => unvisited.Contains(n)))
|
var currentHeight = heights![current.location.x][current.location.y];
|
||||||
|
var unvisitedNeighbors = current.neighbors.Where(n => unvisited.Contains(n));
|
||||||
|
if (!reverse)
|
||||||
|
{
|
||||||
|
unvisitedNeighbors =
|
||||||
|
unvisitedNeighbors.Where(n => heights[n.location.x][n.location.y] <= currentHeight + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unvisitedNeighbors =
|
||||||
|
unvisitedNeighbors.Where(n => currentHeight <= heights[n.location.x][n.location.y] + 1);
|
||||||
|
}
|
||||||
|
foreach (var n in unvisitedNeighbors)
|
||||||
{
|
{
|
||||||
if (n.distance == null || n.distance > current.distance + 1)
|
if (n.distance == null || n.distance > current.distance + 1)
|
||||||
{
|
{
|
||||||
@ -176,36 +173,23 @@ internal class Day12 : Day
|
|||||||
unvisited.Remove(current);
|
unvisited.Remove(current);
|
||||||
if (current == to)
|
if (current == to)
|
||||||
{
|
{
|
||||||
distance = current.distance;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = unvisited.MinBy(n => n.distance);
|
current = unvisited.MinBy(n => n.distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
return distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override string Part1()
|
internal override string Part1()
|
||||||
{
|
{
|
||||||
var dist = FindDistance(startNode!, goalNode!);
|
DijkstraFlood(startNode!, goalNode!);
|
||||||
|
return $"Shortest distance from start to end: <+white>{goalNode!.distance}";
|
||||||
return $"Shortest distance from start to end: <+white>{dist ?? -1}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override string Part2()
|
internal override string Part2()
|
||||||
{
|
{
|
||||||
long? shortestDist = null;
|
DijkstraFlood(goalNode!, startNode!, true);
|
||||||
var aNodes = allNodes.Where(n => heights![n.location.x][n.location.y] == 0);
|
var shortest = allNodes.Where(n => n.distance != null && heights![n.location.x][n.location.y] == 0).MinBy(n => n.distance);
|
||||||
foreach (var n in aNodes)
|
return $"Shortest distance from any minimum-height point to end: <+white>{shortest!.distance}";
|
||||||
{
|
|
||||||
var dist = FindDistance(n, goalNode!);
|
|
||||||
if (shortestDist == null || dist < shortestDist)
|
|
||||||
{
|
|
||||||
shortestDist = dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"Shortest distance from any minimum-height point to end: <+white>{shortestDist}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user