mirror of
https://github.com/parnic/advent-of-code-2022.git
synced 2025-06-16 13:40:13 -05:00
Cut day 14 runtime in half
This is mostly from reusing the same object instead of creating a new one each time we test a new point, but there's also a minor amount of speedup from using HashSet instead of Dictionary. I originally thought I would need to care about why each spot was blocked (wall vs sand) but it turns out that's not important for this problem.
This commit is contained in:
132
src/14.cs
132
src/14.cs
@ -2,38 +2,72 @@
|
|||||||
|
|
||||||
internal class Day14 : Day
|
internal class Day14 : Day
|
||||||
{
|
{
|
||||||
private record point(int x, int y);
|
class point : IEquatable<point>
|
||||||
// Parses a string in the form "x,y" into a point
|
|
||||||
private static point ParsePoint(string str)
|
|
||||||
{
|
{
|
||||||
var parts = str.Trim().Split(',');
|
public bool Equals(point? other)
|
||||||
if (parts.Length != 2)
|
|
||||||
{
|
{
|
||||||
throw new Exception($"found {parts.Length} pieces of input string, expected 2");
|
return x == other?.x && y == other.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = int.Parse(parts[0].Trim());
|
public override bool Equals(object? obj)
|
||||||
var y = int.Parse(parts[1].Trim());
|
{
|
||||||
return new point(x, y);
|
return Equals((point?) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(point? left, point? right)
|
||||||
|
{
|
||||||
|
return Equals(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(point? left, point? right)
|
||||||
|
{
|
||||||
|
return !Equals(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public point(int _x, int _y)
|
||||||
|
{
|
||||||
|
x = _x;
|
||||||
|
y = _y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{x},{y}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
|
||||||
|
// Parses a string in the form "x,y" into a point
|
||||||
|
public static point Parse(string str)
|
||||||
|
{
|
||||||
|
var parts = str.Trim().Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"found {parts.Length} pieces of input string, expected 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = int.Parse(parts[0].Trim());
|
||||||
|
var y = int.Parse(parts[1].Trim());
|
||||||
|
return new point(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum cellType
|
private readonly HashSet<point> grid = new();
|
||||||
{
|
|
||||||
sand,
|
|
||||||
wall,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<point, cellType> grid = new();
|
|
||||||
|
|
||||||
internal override void Parse()
|
internal override void Parse()
|
||||||
{
|
{
|
||||||
foreach (var line in Util.Parsing.ReadAllLines("14"))
|
foreach (var line in Util.Parsing.ReadAllLines("14"))
|
||||||
{
|
{
|
||||||
point? lastPoint = null;
|
point? lastPoint = null;
|
||||||
var parts = line.Split(" -> ");
|
var parts = line.Split(" -> ").Select(point.Parse);
|
||||||
foreach (var part in parts)
|
foreach (var p in parts)
|
||||||
{
|
{
|
||||||
var p = ParsePoint(part);
|
|
||||||
if (lastPoint == null)
|
if (lastPoint == null)
|
||||||
{
|
{
|
||||||
lastPoint = p;
|
lastPoint = p;
|
||||||
@ -44,17 +78,16 @@ internal class Day14 : Day
|
|||||||
{
|
{
|
||||||
for (int i = lastPoint.x; i != p.x; i += Math.Sign(p.x - lastPoint.x))
|
for (int i = lastPoint.x; i != p.x; i += Math.Sign(p.x - lastPoint.x))
|
||||||
{
|
{
|
||||||
grid[p with {x = i}] = cellType.wall;
|
grid.Add(new point(i, p.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (p.y != lastPoint.y)
|
else if (p.y != lastPoint.y)
|
||||||
{
|
{
|
||||||
for (int i = lastPoint.y; i != p.y; i += Math.Sign(p.y - lastPoint.y))
|
for (int i = lastPoint.y; i != p.y; i += Math.Sign(p.y - lastPoint.y))
|
||||||
{
|
{
|
||||||
grid[p with {y = i}] = cellType.wall;
|
grid.Add(new point(p.x, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
grid[p] = cellType.wall;
|
|
||||||
lastPoint = p;
|
lastPoint = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,26 +95,30 @@ internal class Day14 : Day
|
|||||||
|
|
||||||
internal override string Part1()
|
internal override string Part1()
|
||||||
{
|
{
|
||||||
var g = new Dictionary<point, cellType>(grid);
|
var g = new HashSet<point>(grid);
|
||||||
int lowestY = g.MaxBy(pair => pair.Key.y).Key.y;
|
int lowestY = g.MaxBy(p => p.y)!.y;
|
||||||
|
|
||||||
point dropPoint = new point(500, 0);
|
point dropPoint = new point(500, 0);
|
||||||
bool hitVoid = false;
|
bool hitVoid = false;
|
||||||
int numDroppedSand = 0;
|
int numDroppedSand = 0;
|
||||||
|
point sandLoc = new point(dropPoint.x, dropPoint.y);
|
||||||
|
point nextPoint = new point(sandLoc.x, sandLoc.y + 1);
|
||||||
while (!hitVoid)
|
while (!hitVoid)
|
||||||
{
|
{
|
||||||
bool atRest = false;
|
bool atRest = false;
|
||||||
point sandLoc = dropPoint with {y = dropPoint.y + 1};
|
sandLoc.x = dropPoint.x;
|
||||||
|
sandLoc.y = dropPoint.y;
|
||||||
while (!atRest)
|
while (!atRest)
|
||||||
{
|
{
|
||||||
var nextPoint = sandLoc with {y = sandLoc.y + 1};
|
nextPoint.x = sandLoc.x;
|
||||||
if (g.ContainsKey(nextPoint))
|
nextPoint.y = sandLoc.y + 1;
|
||||||
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
nextPoint = nextPoint with {x = sandLoc.x - 1};
|
nextPoint.x = sandLoc.x - 1;
|
||||||
if (g.ContainsKey(nextPoint))
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
nextPoint = nextPoint with {x = sandLoc.x + 1};
|
nextPoint.x = sandLoc.x + 1;
|
||||||
if (g.ContainsKey(nextPoint))
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
atRest = true;
|
atRest = true;
|
||||||
}
|
}
|
||||||
@ -90,7 +127,8 @@ internal class Day14 : Day
|
|||||||
|
|
||||||
if (!atRest)
|
if (!atRest)
|
||||||
{
|
{
|
||||||
sandLoc = nextPoint;
|
sandLoc.x = nextPoint.x;
|
||||||
|
sandLoc.y = nextPoint.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextPoint.y > lowestY)
|
if (nextPoint.y > lowestY)
|
||||||
@ -103,7 +141,7 @@ internal class Day14 : Day
|
|||||||
if (!hitVoid)
|
if (!hitVoid)
|
||||||
{
|
{
|
||||||
numDroppedSand++;
|
numDroppedSand++;
|
||||||
g[sandLoc] = cellType.sand;
|
g.Add(new point(sandLoc.x, sandLoc.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,31 +150,36 @@ internal class Day14 : Day
|
|||||||
|
|
||||||
internal override string Part2()
|
internal override string Part2()
|
||||||
{
|
{
|
||||||
var g = new Dictionary<point, cellType>(grid);
|
var g = new HashSet<point>(grid);
|
||||||
int lowestY = g.MaxBy(pair => pair.Key.y).Key.y;
|
int lowestY = g.MaxBy(p => p.y)!.y;
|
||||||
int floor = 2 + lowestY;
|
int floor = 2 + lowestY;
|
||||||
|
|
||||||
point dropPoint = new point(500, 0);
|
point dropPoint = new point(500, 0);
|
||||||
int numDroppedSand = 0;
|
int numDroppedSand = 0;
|
||||||
|
point sandLoc = new point(dropPoint.x, dropPoint.y);
|
||||||
|
point nextPoint = new point(sandLoc.x, sandLoc.y + 1);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool atRest = false;
|
bool atRest = false;
|
||||||
point sandLoc = dropPoint;
|
sandLoc.x = dropPoint.x;
|
||||||
|
sandLoc.y = dropPoint.y;
|
||||||
while (!atRest)
|
while (!atRest)
|
||||||
{
|
{
|
||||||
var nextPoint = sandLoc with {y = sandLoc.y + 1};
|
nextPoint.x = sandLoc.x;
|
||||||
|
nextPoint.y = sandLoc.y + 1;
|
||||||
|
|
||||||
if (nextPoint.y == floor)
|
if (nextPoint.y == floor)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g.ContainsKey(nextPoint))
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
nextPoint = nextPoint with {x = sandLoc.x - 1};
|
nextPoint.x = sandLoc.x - 1;
|
||||||
if (g.ContainsKey(nextPoint))
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
nextPoint = nextPoint with {x = sandLoc.x + 1};
|
nextPoint.x = sandLoc.x + 1;
|
||||||
if (g.ContainsKey(nextPoint))
|
if (g.Contains(nextPoint))
|
||||||
{
|
{
|
||||||
atRest = true;
|
atRest = true;
|
||||||
}
|
}
|
||||||
@ -145,11 +188,12 @@ internal class Day14 : Day
|
|||||||
|
|
||||||
if (!atRest)
|
if (!atRest)
|
||||||
{
|
{
|
||||||
sandLoc = nextPoint;
|
sandLoc.x = nextPoint.x;
|
||||||
|
sandLoc.y = nextPoint.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g[sandLoc] = cellType.sand;
|
g.Add(new point(sandLoc.x, sandLoc.y));
|
||||||
numDroppedSand++;
|
numDroppedSand++;
|
||||||
|
|
||||||
if (sandLoc == dropPoint)
|
if (sandLoc == dropPoint)
|
||||||
|
Reference in New Issue
Block a user