diff --git a/advent-of-code-2022.csproj b/advent-of-code-2022.csproj
index 00bfd8a..c89e8f2 100644
--- a/advent-of-code-2022.csproj
+++ b/advent-of-code-2022.csproj
@@ -63,6 +63,7 @@
+
diff --git a/inputs/14.txt b/inputs/14.txt
index 30b0a84..6c9d4e9 100644
--- a/inputs/14.txt
+++ b/inputs/14.txt
@@ -1,102 +1,115 @@
-OKSBBKHFBPVNOBKHBPCO
-
-CB -> P
-VH -> S
-CF -> P
-OV -> B
-CH -> N
-PB -> F
-KF -> O
-BC -> K
-FB -> F
-SN -> F
-FV -> B
-PN -> K
-SF -> V
-FN -> F
-SS -> K
-VP -> F
-VB -> B
-OS -> N
-HP -> O
-NF -> S
-SK -> H
-OO -> S
-PF -> C
-CC -> P
-BP -> F
-OB -> C
-CS -> N
-BV -> F
-VV -> B
-HO -> F
-KN -> P
-VC -> K
-KK -> N
-BO -> V
-NH -> O
-HC -> S
-SB -> F
-NN -> V
-OF -> V
-FK -> S
-OP -> S
-NS -> C
-HV -> O
-PC -> C
-FO -> H
-OH -> F
-BF -> S
-SO -> O
-HB -> P
-NK -> H
-NV -> C
-NB -> B
-FF -> B
-BH -> C
-SV -> B
-BK -> K
-NO -> C
-VN -> P
-FC -> B
-PH -> V
-HH -> C
-VO -> O
-SP -> P
-VK -> N
-CP -> H
-SC -> C
-KV -> H
-CO -> C
-OK -> V
-ON -> C
-KS -> S
-NP -> O
-CK -> C
-BS -> F
-VS -> B
-KH -> O
-KC -> C
-KB -> N
-OC -> F
-PP -> S
-HK -> H
-BN -> S
-KO -> K
-NC -> B
-PK -> K
-CV -> H
-PO -> O
-BB -> C
-HS -> F
-SH -> K
-CN -> S
-HN -> S
-KP -> O
-FP -> H
-HF -> F
-PS -> B
-FH -> K
-PV -> O
-FS -> N
-VF -> V
\ No newline at end of file
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+514,69 -> 519,69
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+510,67 -> 515,67
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+515,104 -> 520,104
+514,86 -> 514,87 -> 530,87 -> 530,86
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+497,71 -> 502,71
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+568,158 -> 573,158
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+556,152 -> 561,152
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+548,127 -> 553,127
+524,107 -> 538,107 -> 538,106
+544,125 -> 549,125
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+534,127 -> 539,127
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+537,125 -> 542,125
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+514,86 -> 514,87 -> 530,87 -> 530,86
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+518,71 -> 523,71
+551,131 -> 556,131
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+522,104 -> 527,104
+556,135 -> 561,135 -> 561,134
+560,154 -> 565,154
+564,156 -> 569,156
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+508,104 -> 513,104
+541,127 -> 546,127
+507,69 -> 512,69
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+511,102 -> 516,102
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+554,158 -> 559,158
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+506,65 -> 511,65
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+550,156 -> 555,156
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+561,158 -> 566,158
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+540,123 -> 545,123
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+514,86 -> 514,87 -> 530,87 -> 530,86
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+500,69 -> 505,69
+514,100 -> 519,100
+518,102 -> 523,102
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+553,154 -> 558,154
+503,67 -> 508,67
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+504,62 -> 504,58 -> 504,62 -> 506,62 -> 506,54 -> 506,62 -> 508,62 -> 508,55 -> 508,62
+556,135 -> 561,135 -> 561,134
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+557,156 -> 562,156
+553,138 -> 553,141 -> 546,141 -> 546,149 -> 558,149 -> 558,141 -> 557,141 -> 557,138
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+521,84 -> 521,82 -> 521,84 -> 523,84 -> 523,82 -> 523,84 -> 525,84 -> 525,77 -> 525,84
+511,71 -> 516,71
+489,36 -> 489,29 -> 489,36 -> 491,36 -> 491,34 -> 491,36 -> 493,36 -> 493,26 -> 493,36 -> 495,36 -> 495,35 -> 495,36 -> 497,36 -> 497,29 -> 497,36 -> 499,36 -> 499,31 -> 499,36
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+534,120 -> 534,110 -> 534,120 -> 536,120 -> 536,115 -> 536,120 -> 538,120 -> 538,117 -> 538,120 -> 540,120 -> 540,119 -> 540,120 -> 542,120 -> 542,116 -> 542,120
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+524,107 -> 538,107 -> 538,106
+547,158 -> 552,158
+497,13 -> 497,16 -> 496,16 -> 496,23 -> 511,23 -> 511,16 -> 503,16 -> 503,13
+510,90 -> 510,92 -> 502,92 -> 502,97 -> 516,97 -> 516,92 -> 515,92 -> 515,90
+497,39 -> 497,43 -> 493,43 -> 493,49 -> 506,49 -> 506,43 -> 501,43 -> 501,39
+504,71 -> 509,71
\ No newline at end of file
diff --git a/inputs/14a.txt b/inputs/14a.txt
new file mode 100644
index 0000000..0bc3f3d
--- /dev/null
+++ b/inputs/14a.txt
@@ -0,0 +1,2 @@
+498,4 -> 498,6 -> 496,6
+503,4 -> 502,4 -> 502,9 -> 494,9
\ No newline at end of file
diff --git a/src/14.cs b/src/14.cs
new file mode 100644
index 0000000..8585875
--- /dev/null
+++ b/src/14.cs
@@ -0,0 +1,163 @@
+namespace aoc2022;
+
+internal class Day14 : Day
+{
+ private record point(int x, int y);
+ // Parses a string in the form "x,y" into a point
+ private static point ParsePoint(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
+ {
+ sand,
+ wall,
+ }
+
+ private readonly Dictionary grid = new();
+
+ internal override void Parse()
+ {
+ foreach (var line in Util.Parsing.ReadAllLines("14"))
+ {
+ point? lastPoint = null;
+ var parts = line.Split(" -> ");
+ foreach (var part in parts)
+ {
+ var p = ParsePoint(part);
+ if (lastPoint == null)
+ {
+ lastPoint = p;
+ continue;
+ }
+
+ if (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;
+ }
+ }
+ else if (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[p] = cellType.wall;
+ lastPoint = p;
+ }
+ }
+ }
+
+ internal override string Part1()
+ {
+ var g = new Dictionary(grid);
+ int lowestY = g.MaxBy(pair => pair.Key.y).Key.y;
+
+ point dropPoint = new point(500, 0);
+ bool hitVoid = false;
+ int numDroppedSand = 0;
+ while (!hitVoid)
+ {
+ bool atRest = false;
+ point sandLoc = dropPoint with {y = dropPoint.y + 1};
+ while (!atRest)
+ {
+ var nextPoint = sandLoc with {y = sandLoc.y + 1};
+ if (g.ContainsKey(nextPoint))
+ {
+ nextPoint = nextPoint with {x = sandLoc.x - 1};
+ if (g.ContainsKey(nextPoint))
+ {
+ nextPoint = nextPoint with {x = sandLoc.x + 1};
+ if (g.ContainsKey(nextPoint))
+ {
+ atRest = true;
+ }
+ }
+ }
+
+ if (!atRest)
+ {
+ sandLoc = nextPoint;
+ }
+
+ if (nextPoint.y > lowestY)
+ {
+ hitVoid = true;
+ break;
+ }
+ }
+
+ if (!hitVoid)
+ {
+ numDroppedSand++;
+ g[sandLoc] = cellType.sand;
+ }
+ }
+
+ return $"Sand dropped before hitting the void: <+white>{numDroppedSand}";
+ }
+
+ internal override string Part2()
+ {
+ var g = new Dictionary(grid);
+ int lowestY = g.MaxBy(pair => pair.Key.y).Key.y;
+ int floor = 2 + lowestY;
+
+ point dropPoint = new point(500, 0);
+ int numDroppedSand = 0;
+ while (true)
+ {
+ bool atRest = false;
+ point sandLoc = dropPoint;
+ while (!atRest)
+ {
+ var nextPoint = sandLoc with {y = sandLoc.y + 1};
+ if (nextPoint.y == floor)
+ {
+ break;
+ }
+
+ if (g.ContainsKey(nextPoint))
+ {
+ nextPoint = nextPoint with {x = sandLoc.x - 1};
+ if (g.ContainsKey(nextPoint))
+ {
+ nextPoint = nextPoint with {x = sandLoc.x + 1};
+ if (g.ContainsKey(nextPoint))
+ {
+ atRest = true;
+ }
+ }
+ }
+
+ if (!atRest)
+ {
+ sandLoc = nextPoint;
+ }
+ }
+
+ g[sandLoc] = cellType.sand;
+ numDroppedSand++;
+
+ if (sandLoc == dropPoint)
+ {
+ break;
+ }
+ }
+
+ return $"Sand dropped before filling the space: <+white>{numDroppedSand}";
+ }
+}