about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.drone.yml2
-rw-r--r--aoc2019.test/Tests.cs100
-rw-r--r--aoc2019.test/aoc2019.test.csproj2
-rw-r--r--aoc2019/Day.cs85
-rw-r--r--aoc2019/Day01.cs60
-rw-r--r--aoc2019/Day02.cs72
-rw-r--r--aoc2019/Day03.cs85
-rw-r--r--aoc2019/Day04.cs73
-rw-r--r--aoc2019/Day05.cs124
-rw-r--r--aoc2019/Day06.cs58
-rw-r--r--aoc2019/Day07.cs93
-rw-r--r--aoc2019/Day08.cs55
-rw-r--r--aoc2019/Day09.cs42
-rw-r--r--aoc2019/Day10.cs114
-rw-r--r--aoc2019/Day11.cs179
-rw-r--r--aoc2019/Day12.cs194
-rw-r--r--aoc2019/Day13.cs130
-rw-r--r--aoc2019/Day14.cs153
-rw-r--r--aoc2019/Day15.cs330
-rw-r--r--aoc2019/Day16.cs96
-rw-r--r--aoc2019/Day17.cs70
-rw-r--r--aoc2019/Day18.cs18
-rw-r--r--aoc2019/Day19.cs58
-rw-r--r--aoc2019/Day20.cs18
-rw-r--r--aoc2019/Day21.cs38
-rw-r--r--aoc2019/Day22.cs18
-rw-r--r--aoc2019/Day23.cs132
-rw-r--r--aoc2019/Day24.cs18
-rw-r--r--aoc2019/Day25.cs18
-rw-r--r--aoc2019/Extensions.cs45
-rw-r--r--aoc2019/IntCodeVM.cs155
-rw-r--r--aoc2019/Program.cs45
-rw-r--r--aoc2019/aoc2019.csproj11
-rw-r--r--aoc2019/lib/Extensions.cs48
-rw-r--r--aoc2019/lib/IntCodeVM.cs160
35 files changed, 1438 insertions, 1461 deletions
diff --git a/.drone.yml b/.drone.yml
index 09bd08f..1502452 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -4,7 +4,7 @@ name: run
 
 steps:
   - name: run
-    image: mcr.microsoft.com/dotnet/sdk:latest
+    image: mcr.microsoft.com/dotnet/sdk:6.0
     commands:
       - dotnet test
       - dotnet run --project aoc2019/aoc2019.csproj
diff --git a/aoc2019.test/Tests.cs b/aoc2019.test/Tests.cs
index acfb08d..22566e0 100644
--- a/aoc2019.test/Tests.cs
+++ b/aoc2019.test/Tests.cs
@@ -1,60 +1,58 @@
 using System;
 using System.Diagnostics;
-using aoc2019.lib;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-namespace aoc2019.test
+namespace aoc2019.test;
+
+[TestClass]
+public class Tests
 {
-    [TestClass]
-    public class Tests
+    [DataTestMethod]
+    [DataRow(typeof(Day01), "3394106", "5088280")]
+    [DataRow(typeof(Day02), "3085697", "9425")]
+    [DataRow(typeof(Day03), "1195", "91518")]
+    [DataRow(typeof(Day04), "1079", "699")]
+    [DataRow(typeof(Day05), "7692125", "14340395")]
+    [DataRow(typeof(Day06), "145250", "274")]
+    [DataRow(typeof(Day07), "19650", "35961106")]
+    [DataRow(typeof(Day08), "2413",
+        "\nxxx   xx  xxx  xxxx xxx  \nx  x x  x x  x    x x  x \nxxx  x    x  x   x  xxx  \nx  x x    xxx   x   x  x \nx  x x  x x    x    x  x \nxxx   xx  x    xxxx xxx  ")]
+    [DataRow(typeof(Day09), "3409270027", "82760")]
+    [DataRow(typeof(Day10), "260", "608")]
+    [DataRow(typeof(Day11), "2054",
+        "\n #  # ###  #### ####  ##    ## #  # ###    \n # #  #  #    # #    #  #    # #  # #  #   \n ##   #  #   #  ###  #  #    # #### ###    \n # #  ###   #   #    ####    # #  # #  #   \n # #  # #  #    #    #  # #  # #  # #  #   \n #  # #  # #### #### #  #  ##  #  # ###    ")]
+    [DataRow(typeof(Day12), "10635", "583523031727256")]
+    //[DataRow(typeof(Day13), "361", "after 7133 moves, the score is: 17590")]
+    [DataRow(typeof(Day14), "397771", "3126714")]
+    [DataRow(typeof(Day15), "280", "400")]
+    [DataRow(typeof(Day16), "90744714", "82994322")]
+    [DataRow(typeof(Day17), "2804", "")]
+    [DataRow(typeof(Day19), "114", "10671712")]
+    [DataRow(typeof(Day21), "", "")]
+    [DataRow(typeof(Day23), "23626", "19019")]
+    public void TestAllDays(Type dayType, string part1, string part2)
     {
-        [DataTestMethod]
-        [DataRow(typeof(Day01), "3394106", "5088280")]
-        [DataRow(typeof(Day02), "3085697", "9425")]
-        [DataRow(typeof(Day03), "1195", "91518")]
-        [DataRow(typeof(Day04), "1079", "699")]
-        [DataRow(typeof(Day05), "7692125", "14340395")]
-        [DataRow(typeof(Day06), "145250", "274")]
-        [DataRow(typeof(Day07), "19650", "35961106")]
-        [DataRow(typeof(Day08), "2413",
-            "\nxxx   xx  xxx  xxxx xxx  \nx  x x  x x  x    x x  x \nxxx  x    x  x   x  xxx  \nx  x x    xxx   x   x  x \nx  x x  x x    x    x  x \nxxx   xx  x    xxxx xxx  ")]
-        [DataRow(typeof(Day09), "3409270027", "82760")]
-        [DataRow(typeof(Day10), "260", "608")]
-        [DataRow(typeof(Day11), "2054",
-            "\n #  # ###  #### ####  ##    ## #  # ###    \n # #  #  #    # #    #  #    # #  # #  #   \n ##   #  #   #  ###  #  #    # #### ###    \n # #  ###   #   #    ####    # #  # #  #   \n # #  # #  #    #    #  # #  # #  # #  #   \n #  # #  # #### #### #  #  ##  #  # ###    ")]
-        [DataRow(typeof(Day12), "10635", "583523031727256")]
-        //[DataRow(typeof(Day13), "361", "after 7133 moves, the score is: 17590")]
-        [DataRow(typeof(Day14), "397771", "3126714")]
-        [DataRow(typeof(Day15), "280", "400")]
-        [DataRow(typeof(Day16), "90744714", "82994322")]
-        [DataRow(typeof(Day17), "2804", "")]
-        [DataRow(typeof(Day19), "114", "10671712")]
-        [DataRow(typeof(Day21), "", "")]
-        [DataRow(typeof(Day23), "23626", "19019")]
-        public void TestAllDays(Type dayType, string part1, string part2)
-        {
-            // create day instance
-            var s = Stopwatch.StartNew();
-            var day = (Day) Activator.CreateInstance(dayType);
-            s.Stop();
-            Assert.IsNotNull(day, "failed to create day object");
-            Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in constructor");
+        // create day instance
+        var s = Stopwatch.StartNew();
+        var day = (Day)Activator.CreateInstance(dayType);
+        s.Stop();
+        Assert.IsNotNull(day, "failed to create day object");
+        Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in constructor");
 
-            // part 1
-            s.Reset();
-            s.Start();
-            var part1Actual = day.Part1();
-            s.Stop();
-            Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1");
-            Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1");
+        // part 1
+        s.Reset();
+        s.Start();
+        var part1Actual = day.Part1();
+        s.Stop();
+        Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part1");
+        Assert.AreEqual(part1, part1Actual, $"Incorrect answer for Day {day.DayNumber} Part1");
 
-            // part 2
-            s.Reset();
-            s.Start();
-            var part2Actual = day.Part2();
-            s.Stop();
-            Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part2");
-            Assert.AreEqual(part2, part2Actual, $"Incorrect answer for Day {day.DayNumber} Part2");
-        }
+        // part 2
+        s.Reset();
+        s.Start();
+        var part2Actual = day.Part2();
+        s.Stop();
+        Console.WriteLine($"{s.ScaleMilliseconds()}ms elapsed in part2");
+        Assert.AreEqual(part2, part2Actual, $"Incorrect answer for Day {day.DayNumber} Part2");
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019.test/aoc2019.test.csproj b/aoc2019.test/aoc2019.test.csproj
index f3b9de8..656cbb3 100644
--- a/aoc2019.test/aoc2019.test.csproj
+++ b/aoc2019.test/aoc2019.test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net6.0</TargetFramework>
 
     <IsPackable>false</IsPackable>
   </PropertyGroup>
diff --git a/aoc2019/Day.cs b/aoc2019/Day.cs
index e1bdb25..6bff284 100644
--- a/aoc2019/Day.cs
+++ b/aoc2019/Day.cs
@@ -1,49 +1,44 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using aoc2019.lib;
+using System.Diagnostics;
 
-namespace aoc2019
+namespace aoc2019;
+
+public abstract class Day
 {
-    public abstract class Day
+    protected Day(int dayNumber, string puzzleName)
+    {
+        DayNumber = dayNumber;
+        PuzzleName = puzzleName;
+    }
+
+    public int DayNumber { get; }
+    public string PuzzleName { get; }
+
+    protected virtual IEnumerable<string> Input =>
+        File.ReadLines(FileName);
+
+    protected string FileName =>
+        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"input/day{DayNumber,2:00}.in");
+
+    public void AllParts(bool verbose = true)
     {
-        protected Day(int dayNumber, string puzzleName)
-        {
-            DayNumber = dayNumber;
-            PuzzleName = puzzleName;
-        }
-
-        public int DayNumber { get; }
-        public string PuzzleName { get; }
-
-        protected virtual IEnumerable<string> Input =>
-            File.ReadLines(FileName);
-
-        protected string FileName =>
-            Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"input/day{DayNumber,2:00}.in");
-
-        public void AllParts(bool verbose = true)
-        {
-            Console.WriteLine($"Day {DayNumber,2}: {PuzzleName}");
-            var s = Stopwatch.StartNew();
-            var part1 = Part1();
-            s.Stop();
-            Console.Write($"Part1: {part1,-15} ");
-            Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
-
-            s.Reset();
-
-            s.Start();
-            var part2 = Part2();
-            s.Stop();
-            Console.Write($"Part2: {part2,-15} ");
-            Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
-
-            Console.WriteLine();
-        }
-
-        public abstract string Part1();
-        public abstract string Part2();
+        Console.WriteLine($"Day {DayNumber,2}: {PuzzleName}");
+        var s = Stopwatch.StartNew();
+        var part1 = Part1();
+        s.Stop();
+        Console.Write($"Part1: {part1,-15} ");
+        Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
+
+        s.Reset();
+
+        s.Start();
+        var part2 = Part2();
+        s.Stop();
+        Console.Write($"Part2: {part2,-15} ");
+        Console.WriteLine(verbose ? $"{s.ScaleMilliseconds()}ms elapsed" : "");
+
+        Console.WriteLine();
     }
-}
\ No newline at end of file
+
+    public abstract string Part1();
+    public abstract string Part2();
+}
diff --git a/aoc2019/Day01.cs b/aoc2019/Day01.cs
index 6ebdce5..aa2bc8e 100644
--- a/aoc2019/Day01.cs
+++ b/aoc2019/Day01.cs
@@ -1,43 +1,39 @@
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day01 : Day
 {
-    public sealed class Day01 : Day
+    private readonly IEnumerable<int> masses;
+
+    public Day01() : base(1, "The Tyranny of the Rocket Equation")
     {
-        private readonly IEnumerable<int> masses;
+        masses = Input.Select(int.Parse);
+    }
 
-        public Day01() : base(1, "The Tyranny of the Rocket Equation")
-        {
-            masses = Input.Select(int.Parse);
-        }
+    private static int FuelCost(int weight)
+    {
+        return weight / 3 - 2;
+    }
 
-        private static int FuelCost(int weight)
-        {
-            return weight / 3 - 2;
-        }
+    private static int FullCost(int cost)
+    {
+        int total = 0, newcost, tmp = cost;
 
-        private static int FullCost(int cost)
+        while ((newcost = FuelCost(tmp)) >= 0)
         {
-            int total = 0, newcost, tmp = cost;
-
-            while ((newcost = FuelCost(tmp)) >= 0)
-            {
-                total += newcost;
-                tmp = newcost;
-            }
-
-            return total;
+            total += newcost;
+            tmp = newcost;
         }
 
-        public override string Part1()
-        {
-            return $"{masses.Sum(FuelCost)}";
-        }
+        return total;
+    }
 
-        public override string Part2()
-        {
-            return $"{masses.Sum(FullCost)}";
-        }
+    public override string Part1()
+    {
+        return $"{masses.Sum(FuelCost)}";
+    }
+
+    public override string Part2()
+    {
+        return $"{masses.Sum(FullCost)}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day02.cs b/aoc2019/Day02.cs
index ce99a0a..89d349e 100644
--- a/aoc2019/Day02.cs
+++ b/aoc2019/Day02.cs
@@ -1,46 +1,42 @@
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day02 : Day
 {
-    public sealed class Day02 : Day
+    private readonly IEnumerable<int> input;
+
+    public Day02() : base(2, "1202 Program Alarm")
+    {
+        input = Input.First().Split(',').Select(int.Parse);
+    }
+
+    public int RunIntCode(int noun, int verb)
+    {
+        var v = input.ToList();
+        v[1] = noun;
+        v[2] = verb;
+
+        for (var i = 0; v[i] != 99; i += 4)
+            v[v[i + 3]] = v[i] switch
+            {
+                1 => v[v[i + 1]] + v[v[i + 2]],
+                2 => v[v[i + 1]] * v[v[i + 2]]
+            };
+
+        return v[0];
+    }
+
+    public override string Part1()
+    {
+        return $"{RunIntCode(12, 2)}";
+    }
+
+    public override string Part2()
     {
-        private readonly IEnumerable<int> input;
-
-        public Day02() : base(2, "1202 Program Alarm")
-        {
-            input = Input.First().Split(',').Select(int.Parse);
-        }
-
-        public int RunIntCode(int noun, int verb)
-        {
-            var v = input.ToList();
-            v[1] = noun;
-            v[2] = verb;
-
-            for (var i = 0; v[i] != 99; i += 4)
-                v[v[i + 3]] = v[i] switch
-                {
-                    1 => v[v[i + 1]] + v[v[i + 2]],
-                    2 => v[v[i + 1]] * v[v[i + 2]]
-                };
-
-            return v[0];
-        }
-
-        public override string Part1()
-        {
-            return $"{RunIntCode(12, 2)}";
-        }
-
-        public override string Part2()
-        {
-            for (var i = 0; i < 100; i++)
+        for (var i = 0; i < 100; i++)
             for (var j = 0; j < 100; j++)
                 if (RunIntCode(i, j) == 19690720)
                     return $"{100 * i + j}";
 
-            return string.Empty;
-        }
+        return string.Empty;
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day03.cs b/aoc2019/Day03.cs
index bf32fb3..8b997f5 100644
--- a/aoc2019/Day03.cs
+++ b/aoc2019/Day03.cs
@@ -1,57 +1,52 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day03 : Day
 {
-    public sealed class Day03 : Day
+    private readonly IEnumerable<(int, int)> intersections;
+    private readonly List<Dictionary<(int, int), int>> wires;
+
+    public Day03() : base(3, "Crossed Wires")
     {
-        private readonly IEnumerable<(int, int)> intersections;
-        private readonly List<Dictionary<(int, int), int>> wires;
+        wires = Input.Select(ParseWire).ToList();
+        intersections = wires[0].Keys.Intersect(wires[1].Keys);
+    }
 
-        public Day03() : base(3, "Crossed Wires")
-        {
-            wires = Input.Select(ParseWire).ToList();
-            intersections = wires[0].Keys.Intersect(wires[1].Keys);
-        }
+    public override string Part1()
+    {
+        return $"{intersections.Min(x => Math.Abs(x.Item1) + Math.Abs(x.Item2))}";
+    }
 
-        public override string Part1()
-        {
-            return $"{intersections.Min(x => Math.Abs(x.Item1) + Math.Abs(x.Item2))}";
-        }
+    public override string Part2()
+    {
+        // add 2 to count (0, 0) on both lines
+        return $"{intersections.Min(x => wires[0][x] + wires[1][x]) + 2}";
+    }
 
-        public override string Part2()
-        {
-            // add 2 to count (0, 0) on both lines
-            return $"{intersections.Min(x => wires[0][x] + wires[1][x]) + 2}";
-        }
+    private static Dictionary<(int, int), int> ParseWire(string line)
+    {
+        var r = new Dictionary<(int, int), int>();
+        int x = 0, y = 0, c = 0, i;
 
-        private static Dictionary<(int, int), int> ParseWire(string line)
+        foreach (var step in line.Split(','))
         {
-            var r = new Dictionary<(int, int), int>();
-            int x = 0, y = 0, c = 0, i;
-
-            foreach (var step in line.Split(','))
+            var d = int.Parse(step.Substring(1));
+            switch (step[0])
             {
-                var d = int.Parse(step.Substring(1));
-                switch (step[0])
-                {
-                    case 'U':
-                        for (i = 0; i < d; i++) r.TryAdd((x, ++y), c++);
-                        break;
-                    case 'D':
-                        for (i = 0; i < d; i++) r.TryAdd((x, --y), c++);
-                        break;
-                    case 'R':
-                        for (i = 0; i < d; i++) r.TryAdd((++x, y), c++);
-                        break;
-                    case 'L':
-                        for (i = 0; i < d; i++) r.TryAdd((--x, y), c++);
-                        break;
-                }
+                case 'U':
+                    for (i = 0; i < d; i++) r.TryAdd((x, ++y), c++);
+                    break;
+                case 'D':
+                    for (i = 0; i < d; i++) r.TryAdd((x, --y), c++);
+                    break;
+                case 'R':
+                    for (i = 0; i < d; i++) r.TryAdd((++x, y), c++);
+                    break;
+                case 'L':
+                    for (i = 0; i < d; i++) r.TryAdd((--x, y), c++);
+                    break;
             }
-
-            return r;
         }
+
+        return r;
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day04.cs b/aoc2019/Day04.cs
index 808eb64..dcf6eb7 100644
--- a/aoc2019/Day04.cs
+++ b/aoc2019/Day04.cs
@@ -1,49 +1,46 @@
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day04 : Day
 {
-    public sealed class Day04 : Day
-    {
-        private readonly int end;
+    private readonly int end;
 
-        private readonly int start;
+    private readonly int start;
 
-        public Day04() : base(4, "Secure Container")
-        {
-            var range = Input.First().Split('-').Select(int.Parse).ToList();
-            start = range[0];
-            end = range[1];
-        }
+    public Day04() : base(4, "Secure Container")
+    {
+        var range = Input.First().Split('-').Select(int.Parse).ToList();
+        start = range[0];
+        end = range[1];
+    }
 
-        private bool IsValid(int i)
+    private bool IsValid(int i)
+    {
+        var prev = 0;
+        var hasDup = false;
+        foreach (var c in i.ToString())
         {
-            var prev = 0;
-            var hasDup = false;
-            foreach (var c in i.ToString())
-            {
-                var curr = c - '0';
-                if (curr < prev) return false;
-                if (curr == prev) hasDup = true;
-                prev = curr;
-            }
-
-            return i >= start && i <= end && hasDup;
+            var curr = c - '0';
+            if (curr < prev) return false;
+            if (curr == prev) hasDup = true;
+            prev = curr;
         }
 
-        private bool HasOnePair(int i)
-        {
-            var s = i.ToString();
-            return IsValid(i) && s.Select(c => s.Count(j => j == c)).Any(c => c == 2);
-        }
+        return i >= start && i <= end && hasDup;
+    }
 
-        public override string Part1()
-        {
-            return $"{Enumerable.Range(start, end).Count(IsValid)}";
-        }
+    private bool HasOnePair(int i)
+    {
+        var s = i.ToString();
+        return IsValid(i) && s.Select(c => s.Count(j => j == c)).Any(c => c == 2);
+    }
 
-        public override string Part2()
-        {
-            return $"{Enumerable.Range(start, end).Count(HasOnePair)}";
-        }
+    public override string Part1()
+    {
+        return $"{Enumerable.Range(start, end).Count(IsValid)}";
+    }
+
+    public override string Part2()
+    {
+        return $"{Enumerable.Range(start, end).Count(HasOnePair)}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day05.cs b/aoc2019/Day05.cs
index 2020627..b91089e 100644
--- a/aoc2019/Day05.cs
+++ b/aoc2019/Day05.cs
@@ -1,78 +1,74 @@
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day05 : Day
 {
-    public sealed class Day05 : Day
-    {
-        private readonly IEnumerable<int> tape;
+    private readonly IEnumerable<int> tape;
 
-        private int output;
+    private int output;
 
-        public Day05() : base(5, "Sunny with a Chance of Asteroids")
-        {
-            tape = Input.First().Split(',').Select(int.Parse);
-        }
+    public Day05() : base(5, "Sunny with a Chance of Asteroids")
+    {
+        tape = Input.First().Split(',').Select(int.Parse);
+    }
 
-        public void RunIntCode(List<int> v, int input)
+    public void RunIntCode(List<int> v, int input)
+    {
+        var i = 0;
+        while (i < v.Count && v[i] != 99)
         {
-            var i = 0;
-            while (i < v.Count && v[i] != 99)
+            int Val(int mode, int val)
             {
-                int Val(int mode, int val)
-                {
-                    return mode != 0 ? val : v[val];
-                }
+                return mode != 0 ? val : v[val];
+            }
 
-                var mode1 = v[i] / 100 % 10;
-                var mode2 = v[i] / 1000;
+            var mode1 = v[i] / 100 % 10;
+            var mode2 = v[i] / 1000;
 
-                switch (v[i] % 100)
-                {
-                    case 1:
-                        v[v[i + 3]] = Val(mode1, v[i + 1]) + Val(mode2, v[i + 2]);
-                        i += 4;
-                        break;
-                    case 2:
-                        v[v[i + 3]] = Val(mode1, v[i + 1]) * Val(mode2, v[i + 2]);
-                        i += 4;
-                        break;
-                    case 3:
-                        v[v[i + 1]] = input;
-                        i += 2;
-                        break;
-                    case 4:
-                        output = Val(mode1, v[i + 1]);
-                        i += 2;
-                        break;
-                    case 5:
-                        i = Val(mode1, v[i + 1]) == 0 ? i + 3 : Val(mode2, v[i + 2]);
-                        break;
-                    case 6:
-                        i = Val(mode1, v[i + 1]) != 0 ? i + 3 : Val(mode2, v[i + 2]);
-                        break;
-                    case 7:
-                        v[v[i + 3]] = Val(mode1, v[i + 1]) < Val(mode2, v[i + 2]) ? 1 : 0;
-                        i += 4;
-                        break;
-                    case 8:
-                        v[v[i + 3]] = Val(mode1, v[i + 1]) == Val(mode2, v[i + 2]) ? 1 : 0;
-                        i += 4;
-                        break;
-                }
+            switch (v[i] % 100)
+            {
+                case 1:
+                    v[v[i + 3]] = Val(mode1, v[i + 1]) + Val(mode2, v[i + 2]);
+                    i += 4;
+                    break;
+                case 2:
+                    v[v[i + 3]] = Val(mode1, v[i + 1]) * Val(mode2, v[i + 2]);
+                    i += 4;
+                    break;
+                case 3:
+                    v[v[i + 1]] = input;
+                    i += 2;
+                    break;
+                case 4:
+                    output = Val(mode1, v[i + 1]);
+                    i += 2;
+                    break;
+                case 5:
+                    i = Val(mode1, v[i + 1]) == 0 ? i + 3 : Val(mode2, v[i + 2]);
+                    break;
+                case 6:
+                    i = Val(mode1, v[i + 1]) != 0 ? i + 3 : Val(mode2, v[i + 2]);
+                    break;
+                case 7:
+                    v[v[i + 3]] = Val(mode1, v[i + 1]) < Val(mode2, v[i + 2]) ? 1 : 0;
+                    i += 4;
+                    break;
+                case 8:
+                    v[v[i + 3]] = Val(mode1, v[i + 1]) == Val(mode2, v[i + 2]) ? 1 : 0;
+                    i += 4;
+                    break;
             }
         }
+    }
 
-        public override string Part1()
-        {
-            RunIntCode(tape.ToList(), 1);
-            return $"{output}";
-        }
+    public override string Part1()
+    {
+        RunIntCode(tape.ToList(), 1);
+        return $"{output}";
+    }
 
-        public override string Part2()
-        {
-            RunIntCode(tape.ToList(), 5);
-            return $"{output}";
-        }
+    public override string Part2()
+    {
+        RunIntCode(tape.ToList(), 5);
+        return $"{output}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day06.cs b/aoc2019/Day06.cs
index ede02da..1e7e3be 100644
--- a/aoc2019/Day06.cs
+++ b/aoc2019/Day06.cs
@@ -1,38 +1,34 @@
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day06 : Day
 {
-    public sealed class Day06 : Day
-    {
-        private readonly Dictionary<string, string> input;
+    private readonly Dictionary<string, string> input;
 
-        public Day06() : base(6, "Universal Orbit Map")
-        {
-            input = Input.ToDictionary(i => i.Split(')')[1], i => i.Split(')')[0]);
-        }
+    public Day06() : base(6, "Universal Orbit Map")
+    {
+        input = Input.ToDictionary(i => i.Split(')')[1], i => i.Split(')')[0]);
+    }
 
-        private List<string> GetParents(string obj)
-        {
-            var res = new List<string>();
-            for (var curr = obj; curr != "COM"; curr = input[curr])
-                res.Add(curr);
-            res.Add("COM");
-            return res;
-        }
+    private List<string> GetParents(string obj)
+    {
+        var res = new List<string>();
+        for (var curr = obj; curr != "COM"; curr = input[curr])
+            res.Add(curr);
+        res.Add("COM");
+        return res;
+    }
 
-        public override string Part1()
-        {
-            return $"{input.Keys.Sum(o => GetParents(o).Count - 1)}";
-        }
+    public override string Part1()
+    {
+        return $"{input.Keys.Sum(o => GetParents(o).Count - 1)}";
+    }
 
-        public override string Part2()
-        {
-            var you = GetParents("YOU");
-            var san = GetParents("SAN");
-            var common = 1;
-            for (; you[^common] == san[^common]; common++) ;
-            return $"{you.Count + san.Count - common * 2}";
-        }
+    public override string Part2()
+    {
+        var you = GetParents("YOU");
+        var san = GetParents("SAN");
+        var common = 1;
+        for (; you[^common] == san[^common]; common++) ;
+        return $"{you.Count + san.Count - common * 2}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day07.cs b/aoc2019/Day07.cs
index 10684b9..4a45842 100644
--- a/aoc2019/Day07.cs
+++ b/aoc2019/Day07.cs
@@ -1,67 +1,62 @@
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day07 : Day
 {
-    public sealed class Day07 : Day
+    private readonly IntCodeVM[] Amplifiers = new IntCodeVM[5];
+
+    public Day07() : base(7, "Amplification Circuit")
     {
-        private readonly IntCodeVM[] Amplifiers = new IntCodeVM[5];
+        for (var i = 0; i < 5; i++) Amplifiers[i] = new IntCodeVM(Input.First());
+    }
 
-        public Day07() : base(7, "Amplification Circuit")
-        {
-            for (var i = 0; i < 5; i++) Amplifiers[i] = new IntCodeVM(Input.First());
-        }
+    public override string Part1()
+    {
+        long i, largest = 0;
 
-        public override string Part1()
+        foreach (var phaseSeq in Enumerable.Range(0, 5).Permute())
         {
-            long i, largest = 0;
-
-            foreach (var phaseSeq in Enumerable.Range(0, 5).Permute())
+            i = 0;
+            foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq))
             {
-                i = 0;
-                foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq))
-                {
-                    vm.Reset();
-                    vm.Run(phase, i);
-                    i = vm.Result;
-                }
-
-                if (i > largest)
-                    largest = i;
+                vm.Reset();
+                vm.Run(phase, i);
+                i = vm.Result;
             }
 
-            return $"{largest}";
+            if (i > largest)
+                largest = i;
         }
 
-        public override string Part2()
-        {
-            long i, largest = 0;
+        return $"{largest}";
+    }
 
-            foreach (var phaseSeq in Enumerable.Range(5, 5).Permute())
-            {
-                i = 0;
-                foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq))
-                {
-                    vm.Reset();
-                    vm.AddInput(phase);
-                }
+    public override string Part2()
+    {
+        long i, largest = 0;
 
-                var vms = new Queue<IntCodeVM>(Amplifiers);
-                while (vms.Count > 0)
-                {
-                    var vm = vms.Dequeue();
-                    var haltType = vm.Run(i);
-                    if (haltType == IntCodeVM.HaltType.Waiting)
-                        vms.Enqueue(vm);
-                    i = vm.Result;
-                }
+        foreach (var phaseSeq in Enumerable.Range(5, 5).Permute())
+        {
+            i = 0;
+            foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq))
+            {
+                vm.Reset();
+                vm.AddInput(phase);
+            }
 
-                if (i > largest)
-                    largest = i;
+            var vms = new Queue<IntCodeVM>(Amplifiers);
+            while (vms.Count > 0)
+            {
+                var vm = vms.Dequeue();
+                var haltType = vm.Run(i);
+                if (haltType == IntCodeVM.HaltType.Waiting)
+                    vms.Enqueue(vm);
+                i = vm.Result;
             }
 
-            return $"{largest}";
+            if (i > largest)
+                largest = i;
         }
+
+        return $"{largest}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day08.cs b/aoc2019/Day08.cs
index 6a7bba4..9ca3321 100644
--- a/aoc2019/Day08.cs
+++ b/aoc2019/Day08.cs
@@ -1,37 +1,32 @@
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day08 : Day
 {
-    public sealed class Day08 : Day
-    {
-        private readonly List<List<char>> photo;
+    private readonly List<List<char>> photo;
 
-        public Day08() : base(8, "Space Image Format")
-        {
-            photo = Input.First().Chunk(25 * 6).Select(s => s.ToList()).ToList();
-        }
+    public Day08() : base(8, "Space Image Format")
+    {
+        photo = Input.First().Chunk(25 * 6).Select(s => s.ToList()).ToList();
+    }
 
-        public override string Part1()
-        {
-            var l = photo.OrderBy(layer => layer.Count(pixel => pixel == '0')).First();
-            return $"{l.Count(p => p == '1') * l.Count(p => p == '2')}";
-        }
+    public override string Part1()
+    {
+        var l = photo.OrderBy(layer => layer.Count(pixel => pixel == '0')).First();
+        return $"{l.Count(p => p == '1') * l.Count(p => p == '2')}";
+    }
 
-        public override string Part2()
-        {
-            return "\n" + Enumerable.Range(0, 25 * 6)
-                .Select(p => Enumerable.Range(0, photo.Count)
-                    .Select(l => photo[l][p])
-                    .Aggregate('2', (acc, next) =>
-                        acc != '2' ? acc : next == '0' ? ' ' : next
-                    )
+    public override string Part2()
+    {
+        return "\n" + Enumerable.Range(0, 25 * 6)
+            .Select(p => Enumerable.Range(0, photo.Count)
+                .Select(l => photo[l][p])
+                .Aggregate('2', (acc, next) =>
+                    acc != '2' ? acc : next == '0' ? ' ' : next
                 )
-                .ToDelimitedString()
-                .Chunk(25)
-                .ToDelimitedString("\n")
-                .Replace('1', 'x');
-        }
+            )
+            .ToDelimitedString()
+            .Chunk(25)
+            .ToDelimitedString("\n")
+            .Replace('1', 'x');
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day09.cs b/aoc2019/Day09.cs
index d5edd0a..9e57ab2 100644
--- a/aoc2019/Day09.cs
+++ b/aoc2019/Day09.cs
@@ -1,29 +1,25 @@
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day09 : Day
 {
-    public sealed class Day09 : Day
-    {
-        private readonly IntCodeVM vm;
+    private readonly IntCodeVM vm;
 
-        public Day09() : base(9, "Sensor Boost")
-        {
-            vm = new IntCodeVM(Input.First());
-        }
+    public Day09() : base(9, "Sensor Boost")
+    {
+        vm = new IntCodeVM(Input.First());
+    }
 
-        public override string Part1()
-        {
-            vm.Reset();
-            vm.Run(1);
-            return $"{vm.output.ToDelimitedString(",")}";
-        }
+    public override string Part1()
+    {
+        vm.Reset();
+        vm.Run(1);
+        return $"{vm.output.ToDelimitedString(",")}";
+    }
 
-        public override string Part2()
-        {
-            vm.Reset();
-            vm.Run(2);
-            return $"{vm.output.ToDelimitedString(",")}";
-        }
+    public override string Part2()
+    {
+        vm.Reset();
+        vm.Run(2);
+        return $"{vm.output.ToDelimitedString(",")}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day10.cs b/aoc2019/Day10.cs
index 6151e54..b12c551 100644
--- a/aoc2019/Day10.cs
+++ b/aoc2019/Day10.cs
@@ -1,73 +1,67 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day10 : Day
 {
-    public sealed class Day10 : Day
+    private readonly HashSet<(int x, int y)> asteroids;
+    private (int x, int y) best = (x: -1, y: -1);
+    private int bestCanSee;
+
+    public Day10() : base(10, "Monitoring Station")
     {
-        private readonly HashSet<(int x, int y)> asteroids;
-        private (int x, int y) best = (x: -1, y: -1);
-        private int bestCanSee;
+        asteroids = Input
+            .Select((r, y) => r.Select((c, x) => (x, y, isAsteroid: c == '#')).ToArray())
+            .SelectMany(r => r)
+            .Where(a => a.isAsteroid)
+            .Select(a => (a.x, a.y))
+            .ToHashSet();
+    }
 
-        public Day10() : base(10, "Monitoring Station")
+    public override string Part1()
+    {
+        foreach (var asteroid in asteroids)
         {
-            asteroids = Input
-                .Select((r, y) => r.Select((c, x) => (x, y, isAsteroid: c == '#')).ToArray())
-                .SelectMany(r => r)
-                .Where(a => a.isAsteroid)
-                .Select(a => (a.x, a.y))
-                .ToHashSet();
-        }
+            var canSee = asteroids
+                .Except(new[] { asteroid })
+                .Select(a => (x: a.x - asteroid.x, y: a.y - asteroid.y))
+                .GroupBy(a => Math.Atan2(a.y, a.x))
+                .Count();
 
-        public override string Part1()
-        {
-            foreach (var asteroid in asteroids)
+            if (canSee > bestCanSee)
             {
-                var canSee = asteroids
-                    .Except(new[] {asteroid})
-                    .Select(a => (x: a.x - asteroid.x, y: a.y - asteroid.y))
-                    .GroupBy(a => Math.Atan2(a.y, a.x))
-                    .Count();
-
-                if (canSee > bestCanSee)
-                {
-                    best = asteroid;
-                    bestCanSee = canSee;
-                }
+                best = asteroid;
+                bestCanSee = canSee;
             }
-
-            return $"{bestCanSee}";
         }
 
-        public override string Part2()
-        {
-            static IEnumerable<(int x, int y, double angle, double dist)> GetValue(
-                Queue<(int x, int y, double angle, double dist)> q)
-            {
-                if (q.Count > 0) yield return q.Dequeue();
-            }
+        return $"{bestCanSee}";
+    }
 
-            return asteroids
-                .Where(a => a != best)
-                .Select(a =>
-                {
-                    var xDist = a.x - best.x;
-                    var yDist = a.y - best.y;
-                    var angle = Math.Atan2(xDist, yDist);
-                    return (a.x, a.y, angle, dist: Math.Sqrt(xDist * xDist + yDist * yDist));
-                })
-                .ToLookup(a => a.angle)
-                .OrderByDescending(a => a.Key)
-                .Select(a => new Queue<(int x, int y, double angle, double dist)>(a.OrderBy(b => b.dist)))
-                .Repeat()
-                .SelectMany(GetValue)
-                .Skip(199)
-                .Take(1)
-                .Select(a => a.x * 100 + a.y)
-                .Single()
-                .ToString();
+    public override string Part2()
+    {
+        static IEnumerable<(int x, int y, double angle, double dist)> GetValue(
+            Queue<(int x, int y, double angle, double dist)> q)
+        {
+            if (q.Count > 0) yield return q.Dequeue();
         }
+
+        return asteroids
+            .Where(a => a != best)
+            .Select(a =>
+            {
+                var xDist = a.x - best.x;
+                var yDist = a.y - best.y;
+                var angle = Math.Atan2(xDist, yDist);
+                return (a.x, a.y, angle, dist: Math.Sqrt(xDist * xDist + yDist * yDist));
+            })
+            .ToLookup(a => a.angle)
+            .OrderByDescending(a => a.Key)
+            .Select(a => new Queue<(int x, int y, double angle, double dist)>(a.OrderBy(b => b.dist)))
+            .Repeat()
+            .SelectMany(GetValue)
+            .Skip(199)
+            .Take(1)
+            .Select(a => a.x * 100 + a.y)
+            .Single()
+            .ToString();
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day11.cs b/aoc2019/Day11.cs
index 2a299cb..fe86a4c 100644
--- a/aoc2019/Day11.cs
+++ b/aoc2019/Day11.cs
@@ -1,111 +1,106 @@
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day11 : Day
 {
-    public sealed class Day11 : Day
+    private readonly IntCodeVM vm;
+    private Direction heading;
+    private long x, y;
+
+    public Day11() : base(11, "Space Police")
     {
-        private readonly IntCodeVM vm;
-        private Direction heading;
-        private long x, y;
+        vm = new IntCodeVM(Input.First());
+    }
 
-        public Day11() : base(11, "Space Police")
+    private void Move()
+    {
+        switch (heading)
         {
-            vm = new IntCodeVM(Input.First());
+            case Direction.Up:
+                y++;
+                break;
+            case Direction.Down:
+                y--;
+                break;
+            case Direction.Left:
+                x--;
+                break;
+            case Direction.Right:
+                x++;
+                break;
         }
 
-        private void Move()
-        {
-            switch (heading)
-            {
-                case Direction.Up:
-                    y++;
-                    break;
-                case Direction.Down:
-                    y--;
-                    break;
-                case Direction.Left:
-                    x--;
-                    break;
-                case Direction.Right:
-                    x++;
-                    break;
-            }
-
-            ;
-        }
+        ;
+    }
 
-        private void Turn(long direction)
+    private void Turn(long direction)
+    {
+        switch (heading)
         {
-            switch (heading)
-            {
-                case Direction.Up:
-                    heading = direction == 0 ? Direction.Left : Direction.Right;
-                    break;
-                case Direction.Down:
-                    heading = direction == 0 ? Direction.Right : Direction.Left;
-                    break;
-                case Direction.Left:
-                    heading = direction == 0 ? Direction.Down : Direction.Up;
-                    break;
-                case Direction.Right:
-                    heading = direction == 0 ? Direction.Up : Direction.Down;
-                    break;
-            }
-
-            Move();
+            case Direction.Up:
+                heading = direction == 0 ? Direction.Left : Direction.Right;
+                break;
+            case Direction.Down:
+                heading = direction == 0 ? Direction.Right : Direction.Left;
+                break;
+            case Direction.Left:
+                heading = direction == 0 ? Direction.Down : Direction.Up;
+                break;
+            case Direction.Right:
+                heading = direction == 0 ? Direction.Up : Direction.Down;
+                break;
         }
 
-        private Dictionary<(long x, long y), long> PaintShip(int initialVal)
-        {
-            var map = new Dictionary<(long, long), long>();
-            vm.Reset();
-            heading = Direction.Up;
-            x = 0;
-            y = 0;
-            map[(x, y)] = initialVal;
-
-            var haltType = IntCodeVM.HaltType.Waiting;
-            while (haltType == IntCodeVM.HaltType.Waiting)
-            {
-                haltType = vm.Run(map.GetValueOrDefault((x, y)));
-                map[(x, y)] = vm.Result;
-                Turn(vm.Result);
-            }
+        Move();
+    }
 
-            return map;
-        }
+    private Dictionary<(long x, long y), long> PaintShip(int initialVal)
+    {
+        var map = new Dictionary<(long, long), long>();
+        vm.Reset();
+        heading = Direction.Up;
+        x = 0;
+        y = 0;
+        map[(x, y)] = initialVal;
 
-        public override string Part1()
+        var haltType = IntCodeVM.HaltType.Waiting;
+        while (haltType == IntCodeVM.HaltType.Waiting)
         {
-            return $"{PaintShip(0).Count}";
+            haltType = vm.Run(map.GetValueOrDefault((x, y)));
+            map[(x, y)] = vm.Result;
+            Turn(vm.Result);
         }
 
-        public override string Part2()
-        {
-            var map = PaintShip(1);
-            var minX = (int) map.Keys.Select(i => i.x).Min();
-            var maxX = (int) map.Keys.Select(i => i.x).Max();
-            var minY = (int) map.Keys.Select(i => i.y).Min();
-            var maxY = (int) map.Keys.Select(i => i.y).Max();
+        return map;
+    }
 
-            return "\n" + Enumerable.Range(minY, maxY - minY + 1)
-                .Select(j =>
-                    Enumerable.Range(minX, maxX - minX + 1)
-                        .Select(i => map.GetValueOrDefault((x: i, y: j)) == 0 ? ' ' : '#')
-                        .ToDelimitedString()
-                )
-                .Reverse()
-                .ToDelimitedString("\n");
-        }
+    public override string Part1()
+    {
+        return $"{PaintShip(0).Count}";
+    }
 
-        private enum Direction
-        {
-            Up,
-            Down,
-            Left,
-            Right
-        }
+    public override string Part2()
+    {
+        var map = PaintShip(1);
+        var minX = (int)map.Keys.Select(i => i.x).Min();
+        var maxX = (int)map.Keys.Select(i => i.x).Max();
+        var minY = (int)map.Keys.Select(i => i.y).Min();
+        var maxY = (int)map.Keys.Select(i => i.y).Max();
+
+        return "\n" + Enumerable.Range(minY, maxY - minY + 1)
+            .Select(j =>
+                Enumerable.Range(minX, maxX - minX + 1)
+                    .Select(i => map.GetValueOrDefault((x: i, y: j)) == 0 ? ' ' : '#')
+                    .ToDelimitedString()
+            )
+            .Reverse()
+            .ToDelimitedString("\n");
+    }
+
+    private enum Direction
+    {
+        Up,
+        Down,
+        Left,
+        Right
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day12.cs b/aoc2019/Day12.cs
index 04e215e..79b6a11 100644
--- a/aoc2019/Day12.cs
+++ b/aoc2019/Day12.cs
@@ -1,127 +1,123 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day12 : Day
 {
-    public sealed class Day12 : Day
+    private readonly List<Position> moons;
+    private int step;
+
+    public Day12() : base(12, "The N-Body Problem")
     {
-        private readonly List<Position> moons;
-        private int step;
+        moons = Input
+            .Select(moon =>
+                moon
+                    .TrimStart('<')
+                    .TrimEnd('>')
+                    .Split(",")
+                    .Select(val => int.Parse(val.Split("=").Last()))
+            )
+            .Select(moon => new Position(moon.ToList()))
+            .ToList();
+
+        foreach (var moon in moons)
+            moon.SetSiblings(moons);
+    }
 
-        public Day12() : base(12, "The N-Body Problem")
-        {
-            moons = Input
-                .Select(moon =>
-                    moon
-                        .TrimStart('<')
-                        .TrimEnd('>')
-                        .Split(",")
-                        .Select(val => int.Parse(val.Split("=").Last()))
-                )
-                .Select(moon => new Position(moon.ToList()))
-                .ToList();
-
-            foreach (var moon in moons)
-                moon.SetSiblings(moons);
-        }
+    public static long LCM(long a, long b)
+    {
+        return a * b / GCD(a, b);
+    }
 
-        public static long LCM(long a, long b)
-        {
-            return a * b / GCD(a, b);
-        }
+    public static long GCD(long a, long b)
+    {
+        if (b == 0) return a;
+        return GCD(b, a % b);
+    }
 
-        public static long GCD(long a, long b)
-        {
-            if (b == 0) return a;
-            return GCD(b, a % b);
-        }
+    private void Step()
+    {
+        foreach (var moon in moons)
+            moon.Gravitate();
 
-        private void Step()
-        {
-            foreach (var moon in moons)
-                moon.Gravitate();
+        foreach (var moon in moons)
+            moon.Move();
 
-            foreach (var moon in moons)
-                moon.Move();
+        step++;
+    }
 
-            step++;
-        }
+    public override string Part1()
+    {
+        while (step < 1000)
+            Step();
 
-        public override string Part1()
-        {
-            while (step < 1000)
-                Step();
+        return $"{moons.Sum(p => p.TotalEnergy)}";
+    }
 
-            return $"{moons.Sum(p => p.TotalEnergy)}";
-        }
+    public override string Part2()
+    {
+        int cycleX = 0, cycleY = 0, cycleZ = 0;
 
-        public override string Part2()
+        while (cycleX == 0 || cycleY == 0 || cycleZ == 0)
         {
-            int cycleX = 0, cycleY = 0, cycleZ = 0;
+            Step();
+            if (cycleX == 0 && moons.All(m => m.dx == 0)) cycleX = step * 2;
+            if (cycleY == 0 && moons.All(m => m.dy == 0)) cycleY = step * 2;
+            if (cycleZ == 0 && moons.All(m => m.dz == 0)) cycleZ = step * 2;
+        }
 
-            while (cycleX == 0 || cycleY == 0 || cycleZ == 0)
-            {
-                Step();
-                if (cycleX == 0 && moons.All(m => m.dx == 0)) cycleX = step * 2;
-                if (cycleY == 0 && moons.All(m => m.dy == 0)) cycleY = step * 2;
-                if (cycleZ == 0 && moons.All(m => m.dz == 0)) cycleZ = step * 2;
-            }
+        return $"{LCM(cycleX, LCM(cycleY, cycleZ))}";
+    }
 
-            return $"{LCM(cycleX, LCM(cycleY, cycleZ))}";
-        }
+    public class Position
+    {
+        public int dx, dy, dz;
+        private List<Position> siblings;
+        public int x, y, z;
 
-        public class Position
+        public Position(IList<int> moon)
         {
-            public int dx, dy, dz;
-            private List<Position> siblings;
-            public int x, y, z;
-
-            public Position(IList<int> moon)
-            {
-                x = moon[0];
-                y = moon[1];
-                z = moon[2];
-                dx = 0;
-                dy = 0;
-                dz = 0;
-            }
+            x = moon[0];
+            y = moon[1];
+            z = moon[2];
+            dx = 0;
+            dy = 0;
+            dz = 0;
+            siblings = new();
+        }
 
-            internal int KineticEnergy =>
-                Math.Abs(x) + Math.Abs(y) + Math.Abs(z);
+        internal int KineticEnergy =>
+            Math.Abs(x) + Math.Abs(y) + Math.Abs(z);
 
-            internal int PotentialEnergy =>
-                Math.Abs(dx) + Math.Abs(dy) + Math.Abs(dz);
+        internal int PotentialEnergy =>
+            Math.Abs(dx) + Math.Abs(dy) + Math.Abs(dz);
 
-            internal int TotalEnergy =>
-                KineticEnergy * PotentialEnergy;
+        internal int TotalEnergy =>
+            KineticEnergy * PotentialEnergy;
 
-            public void SetSiblings(List<Position> positions)
-            {
-                siblings = positions.Where(p => p != this).ToList();
-            }
+        public void SetSiblings(List<Position> positions)
+        {
+            siblings = positions.Where(p => p != this).ToList();
+        }
 
-            public override string ToString()
-            {
-                return $"pos=<x={x}, y={y}, z={z}> vel=<x={dx}, y={dy}, z={dz}>";
-            }
+        public override string ToString()
+        {
+            return $"pos=<x={x}, y={y}, z={z}> vel=<x={dx}, y={dy}, z={dz}>";
+        }
 
-            internal void Gravitate()
+        internal void Gravitate()
+        {
+            foreach (var m in siblings)
             {
-                foreach (var m in siblings)
-                {
-                    if (x != m.x) dx += x > m.x ? -1 : 1;
-                    if (y != m.y) dy += y > m.y ? -1 : 1;
-                    if (z != m.z) dz += z > m.z ? -1 : 1;
-                }
+                if (x != m.x) dx += x > m.x ? -1 : 1;
+                if (y != m.y) dy += y > m.y ? -1 : 1;
+                if (z != m.z) dz += z > m.z ? -1 : 1;
             }
+        }
 
-            internal void Move()
-            {
-                x += dx;
-                y += dy;
-                z += dz;
-            }
+        internal void Move()
+        {
+            x += dx;
+            y += dy;
+            z += dz;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day13.cs b/aoc2019/Day13.cs
index 4d919e7..11af0a3 100644
--- a/aoc2019/Day13.cs
+++ b/aoc2019/Day13.cs
@@ -1,87 +1,81 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day13 : Day
 {
-    public sealed class Day13 : Day
-    {
-        private readonly Dictionary<(int x, int y), int> board;
+    private readonly Dictionary<(int x, int y), int> board;
 
-        private readonly IntCodeVM vm;
+    private readonly IntCodeVM vm;
 
-        public Day13() : base(13, "Care Package")
-        {
-            vm = new IntCodeVM(Input.First());
-            board = new Dictionary<(int, int), int>();
-        }
+    public Day13() : base(13, "Care Package")
+    {
+        vm = new IntCodeVM(Input.First());
+        board = new Dictionary<(int, int), int>();
+    }
 
-        private void UpdateTiles(IEnumerable<long> queue)
-        {
-            var input = queue.Select(i => (int) i).ToList();
+    private void UpdateTiles(IEnumerable<long> queue)
+    {
+        var input = queue.Select(i => (int)i).ToList();
 
-            for (var i = 0; i < input.Count - 2; i += 3)
-            {
-                var x = input[i];
-                var y = input[i + 1];
-                var val = input[i + 2];
+        for (var i = 0; i < input.Count - 2; i += 3)
+        {
+            var x = input[i];
+            var y = input[i + 1];
+            var val = input[i + 2];
 
-                if (board.ContainsKey((x, y)))
-                    board[(x, y)] = val;
-                else
-                    board.Add((x, y), val);
-            }
+            if (board.ContainsKey((x, y)))
+                board[(x, y)] = val;
+            else
+                board.Add((x, y), val);
         }
+    }
 
-        private void PrintBoard()
+    private void PrintBoard()
+    {
+        foreach (var ((x, y), value) in board)
         {
-            foreach (var ((x, y), value) in board)
+            if (x < 0 || y < 0) continue;
+            Console.SetCursorPosition(x, y);
+            Console.Write(value switch
             {
-                if (x < 0 || y < 0) continue;
-                Console.SetCursorPosition(x, y);
-                Console.Write(value switch
-                {
-                    0 => " ",
-                    1 => "|",
-                    2 => "B",
-                    3 => "_",
-                    4 => ".",
-                    _ => value
-                });
-            }
-        }
-
-        public override string Part1()
-        {
-            vm.Reset();
-            vm.Run();
-            return $"{vm.output.Where((v, i) => (i + 1) % 3 == 0 && v == 2).Count()}";
+                0 => " ",
+                1 => "|",
+                2 => "B",
+                3 => "_",
+                4 => ".",
+                _ => value
+            });
         }
+    }
 
-        public override string Part2()
-        {
-            vm.Reset();
-            vm.memory[0] = 2;
-            var printBoard = false;
-            var gameTicks = 0;
-            if (printBoard) Console.Clear();
+    public override string Part1()
+    {
+        vm.Reset();
+        vm.Run();
+        return $"{vm.output.Where((v, i) => (i + 1) % 3 == 0 && v == 2).Count()}";
+    }
 
-            var haltType = IntCodeVM.HaltType.Waiting;
-            while (haltType == IntCodeVM.HaltType.Waiting)
-            {
-                haltType = vm.Run();
-                UpdateTiles(vm.output);
+    public override string Part2()
+    {
+        vm.Reset();
+        vm.memory[0] = 2;
+        var printBoard = false;
+        var gameTicks = 0;
+        if (printBoard) Console.Clear();
 
-                var (ball, _) = board.First(t => t.Value == 4).Key;
-                var (paddle, _) = board.First(t => t.Value == 3).Key;
-                vm.AddInput(ball > paddle ? 1 : ball < paddle ? -1 : 0);
+        var haltType = IntCodeVM.HaltType.Waiting;
+        while (haltType == IntCodeVM.HaltType.Waiting)
+        {
+            haltType = vm.Run();
+            UpdateTiles(vm.output);
 
-                gameTicks++;
-                if (printBoard) PrintBoard();
-            }
+            var (ball, _) = board.First(t => t.Value == 4).Key;
+            var (paddle, _) = board.First(t => t.Value == 3).Key;
+            vm.AddInput(ball > paddle ? 1 : ball < paddle ? -1 : 0);
 
-            return $"after {gameTicks} moves, the score is: {board[(-1, 0)]}";
+            gameTicks++;
+            if (printBoard) PrintBoard();
         }
+
+        return $"after {gameTicks} moves, the score is: {board[(-1, 0)]}";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day14.cs b/aoc2019/Day14.cs
index af7af42..9a34702 100644
--- a/aoc2019/Day14.cs
+++ b/aoc2019/Day14.cs
@@ -1,110 +1,107 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day14 : Day
 {
-    public sealed class Day14 : Day
+    private readonly Dictionary<string, Reaction> reactions;
+
+    private Dictionary<string, long> available;
+
+    public Day14() : base(14, "Space Stoichiometry")
     {
-        private readonly Dictionary<string, Reaction> reactions;
+        reactions = Input
+            .Select(Reaction.Parse)
+            .ToDictionary(r => r.product.Name);
+        
+        available = new();
+    }
 
-        private Dictionary<string, long> available;
+    private bool Consume(string chem, long quantity)
+    {
+        if (quantity <= 0)
+            throw new ArgumentOutOfRangeException(nameof(quantity));
 
-        public Day14() : base(14, "Space Stoichiometry")
-        {
-            reactions = Input
-                .Select(Reaction.Parse)
-                .ToDictionary(r => r.product.Name);
-        }
+        if (!available.ContainsKey(chem))
+            available[chem] = 0;
 
-        private bool Consume(string chem, long quantity)
-        {
-            if (quantity <= 0)
-                throw new ArgumentOutOfRangeException(nameof(quantity));
+        if (available[chem] < quantity && !Produce(chem, quantity - available[chem]))
+            return false;
 
-            if (!available.ContainsKey(chem))
-                available[chem] = 0;
+        available[chem] -= quantity;
+        return true;
+    }
 
-            if (available[chem] < quantity && !Produce(chem, quantity - available[chem]))
-                return false;
+    private bool Produce(string chem, long quantity)
+    {
+        if (chem == "ORE")
+            return false;
 
-            available[chem] -= quantity;
-            return true;
-        }
+        var reaction = reactions[chem];
+        var reactionCount = (long)Math.Ceiling((double)quantity / reaction.product.Quantity);
 
-        private bool Produce(string chem, long quantity)
-        {
-            if (chem == "ORE")
+        foreach (var reactant in reaction.reactants)
+            if (!Consume(reactant.Name, reactionCount * reactant.Quantity))
                 return false;
 
-            var reaction = reactions[chem];
-            var reactionCount = (long) Math.Ceiling((double) quantity / reaction.product.Quantity);
+        available[chem] = available.GetValueOrDefault(chem) + reactionCount * reaction.product.Quantity;
+        return true;
+    }
 
-            foreach (var reactant in reaction.reactants)
-                if (!Consume(reactant.Name, reactionCount * reactant.Quantity))
-                    return false;
+    public override string Part1()
+    {
+        available = new Dictionary<string, long> { { "ORE", long.MaxValue } };
+        Consume("FUEL", 1);
+        return $"{long.MaxValue - available["ORE"]}";
+    }
 
-            available[chem] = available.GetValueOrDefault(chem) + reactionCount * reaction.product.Quantity;
-            return true;
-        }
+    public override string Part2()
+    {
+        const long capacity = 1_000_000_000_000;
+        available = new Dictionary<string, long> { { "ORE", capacity } };
+        Consume("FUEL", 1);
 
-        public override string Part1()
+        var oreConsumed = capacity - available["ORE"];
+        while (Produce("FUEL", Math.Max(1, available["ORE"] / oreConsumed)))
         {
-            available = new Dictionary<string, long> {{"ORE", long.MaxValue}};
-            Consume("FUEL", 1);
-            return $"{long.MaxValue - available["ORE"]}";
         }
 
-        public override string Part2()
-        {
-            const long capacity = 1_000_000_000_000;
-            available = new Dictionary<string, long> {{"ORE", capacity}};
-            Consume("FUEL", 1);
+        return $"{available["FUEL"] + 1}";
+    }
 
-            var oreConsumed = capacity - available["ORE"];
-            while (Produce("FUEL", Math.Max(1, available["ORE"] / oreConsumed)))
-            {
-            }
+    private struct Component
+    {
+        public string Name { get; set; }
+        public int Quantity { get; set; }
+    }
 
-            return $"{available["FUEL"] + 1}";
-        }
+    private class Reaction
+    {
+        public readonly Component product;
+        public readonly Component[] reactants;
 
-        private struct Component
+        private Reaction(Component[] reactants, Component product)
         {
-            public string Name { get; set; }
-            public int Quantity { get; set; }
+            this.reactants = reactants;
+            this.product = product;
         }
 
-        private class Reaction
+        public static Reaction Parse(string s)
         {
-            public readonly Component product;
-            public readonly Component[] reactants;
+            var ss = s.Split(new[] { ", ", " => " }, StringSplitOptions.None);
 
-            private Reaction(Component[] reactants, Component product)
-            {
-                this.reactants = reactants;
-                this.product = product;
-            }
+            return new Reaction(
+                ss.Take(ss.Length - 1).Select(ParseComponent).ToArray(),
+                ParseComponent(ss[^1])
+            );
 
-            public static Reaction Parse(string s)
+            static Component ParseComponent(string s)
             {
-                var ss = s.Split(new[] {", ", " => "}, StringSplitOptions.None);
-
-                return new Reaction(
-                    ss.Take(ss.Length - 1).Select(ParseComponent).ToArray(),
-                    ParseComponent(ss[^1])
-                );
-
-                static Component ParseComponent(string s)
+                var spl = s.Split(' ', 2);
+                return new Component
                 {
-                    var spl = s.Split(' ', 2);
-                    return new Component
-                    {
-                        Quantity = int.Parse(spl[0]),
-                        Name = spl[1]
-                    };
-                }
+                    Quantity = int.Parse(spl[0]),
+                    Name = spl[1]
+                };
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day15.cs b/aoc2019/Day15.cs
index 59d720c..046f52f 100644
--- a/aoc2019/Day15.cs
+++ b/aoc2019/Day15.cs
@@ -1,224 +1,206 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day15 : Day
 {
-    public sealed class Day15 : Day
-    {
-        private readonly bool verbose = false;
-        private readonly IntCodeVM vm;
+    private readonly bool verbose = false;
+    private readonly IntCodeVM vm;
 
-        public Day15() : base(15, "Oxygen System")
-        {
-            vm = new IntCodeVM(Input.First());
-        }
+    public Day15() : base(15, "Oxygen System")
+    {
+        vm = new IntCodeVM(Input.First());
+    }
 
-        public override string Part1()
+    public override string Part1()
+    {
+        vm.Reset();
+        var currentLocation = new Location(0, 0);
+        var halt = IntCodeVM.HaltType.Waiting;
+        while (halt == IntCodeVM.HaltType.Waiting)
         {
-            vm.Reset();
-            var currentLocation = new Location(0, 0);
-            var halt = IntCodeVM.HaltType.Waiting;
-            while (halt == IntCodeVM.HaltType.Waiting)
+            var direction = currentLocation!.NextDirection();
+            if (direction <= 4)
             {
-                var direction = currentLocation.NextDirection();
-                if (direction <= 4)
+                var (x, y) = currentLocation.Neighbor(direction);
+                if (Location.GetLocation(x, y) == null)
                 {
-                    var (x, y) = currentLocation.Neighbor(direction);
-                    if (Location.GetLocation(x, y) == null)
+                    halt = vm.Run(direction);
+                    currentLocation = vm.Result switch
                     {
-                        halt = vm.Run(direction);
-                        switch (vm.Result)
-                        {
-                            case Location.Wall:
-                                new Location(x, y, Location.Opposites[direction], Location.Wall);
-                                break;
-                            case Location.Empty:
-                                currentLocation = new Location(x, y, Location.Opposites[direction]);
-                                break;
-                            case Location.System:
-                                currentLocation = new Location(x, y, Location.Opposites[direction], Location.System);
-                                break;
-                            default:
-                                throw new Exception($"Unknown IntCodeVM response: {vm.Result}");
-                        }
-                    }
+                        Location.Wall   => new Location(x, y, Location.Opposites[direction], Location.Wall),
+                        Location.Empty  => new Location(x, y, Location.Opposites[direction]),
+                        Location.System => new Location(x, y, Location.Opposites[direction], Location.System),
+                        _ => throw new Exception($"Unknown IntCodeVM response: {vm.Result}"),
+                    };
                 }
-                else
+            }
+            else
+            {
+                direction = currentLocation.PreviousDirection;
+                if (direction > 0)
                 {
-                    direction = currentLocation.PreviousDirection;
-                    if (direction > 0)
+                    halt = vm.Run(direction);
+                    currentLocation = vm.Result switch
                     {
-                        halt = vm.Run(direction);
-                        switch (vm.Result)
-                        {
-                            case Location.Empty:
-                            case Location.System:
-                                currentLocation = Location.GetLocation(currentLocation.Neighbor(direction));
-                                break;
-                            default:
-                                throw new Exception($"Unknown or unexpected response for previous room: {vm.Result}");
-                        }
-                    }
-                    else
+                        Location.Empty or Location.System => Location.GetLocation(currentLocation.Neighbor(direction)),
+                        _ => throw new Exception($"Unknown or unexpected response for previous room: {vm.Result}"),
+                    };
+                }
+                else
+                {
+                    if (verbose)
                     {
-                        if (verbose)
+                        // find extents of canvas
+                        int xMin, xMax, yMin, yMax;
+                        xMin = yMin = int.MaxValue;
+                        xMax = yMax = int.MinValue;
+                        foreach (var (x, y) in Location.AllLocations.Keys)
                         {
-                            // find extents of canvas
-                            int xMin, xMax, yMin, yMax;
-                            xMin = yMin = int.MaxValue;
-                            xMax = yMax = int.MinValue;
-                            foreach (var (x, y) in Location.AllLocations.Keys)
-                            {
-                                if (x < xMin) xMin = x;
-                                if (x > xMax) xMax = x;
-                                if (y < yMin) yMin = y;
-                                if (y > yMax) yMax = y;
-                            }
-
-                            Console.WriteLine($"Canvas extends from ({xMin}, {yMin}) to ({xMax}, {yMax})");
-
-                            // print board
-                            for (var y = yMin; y <= yMax; y++)
-                            {
-                                var line = "";
-                                for (var x = xMin; x <= xMax; x++)
-                                    if (Location.AllLocations.ContainsKey((x, y)))
-                                        line += Location.AllLocations[(x, y)].Image();
-                                    else
-                                        line += "@";
-
-                                Console.WriteLine(line);
-                            }
+                            if (x < xMin) xMin = x;
+                            if (x > xMax) xMax = x;
+                            if (y < yMin) yMin = y;
+                            if (y > yMax) yMax = y;
                         }
 
-                        currentLocation = Location.OxygenLocation;
-                        var distance = 0;
-                        while (currentLocation.PreviousDirection != 0)
+                        Console.WriteLine($"Canvas extends from ({xMin}, {yMin}) to ({xMax}, {yMax})");
+
+                        // print board
+                        for (var y = yMin; y <= yMax; y++)
                         {
-                            distance++;
-                            currentLocation = Location.GetLocation(currentLocation.PreviousLocation());
+                            var line = "";
+                            for (var x = xMin; x <= xMax; x++)
+                                if (Location.AllLocations.ContainsKey((x, y)))
+                                    line += Location.AllLocations[(x, y)].Image();
+                                else
+                                    line += "@";
+
+                            Console.WriteLine(line);
                         }
+                    }
 
-                        return $"{distance}";
+                    currentLocation = Location.OxygenLocation;
+                    var distance = 0;
+                    while (currentLocation?.PreviousDirection != 0)
+                    {
+                        distance++;
+                        currentLocation = Location.GetLocation(currentLocation!.PreviousLocation());
                     }
+
+                    return $"{distance}";
                 }
             }
-
-            return "";
         }
 
-        public override string Part2()
-        {
-            var changed = true;
-            while (changed)
-            {
-                changed = false;
-                foreach (var location in Location.AllLocations.Values)
-                    changed = location.UpdateDistanceToOxygenSystem() || changed;
-            }
+        return "";
+    }
 
-            return Location.AllLocations.Values
-                .Where(l => !l.IsWall)
-                .Max(l => l.DistanceToOxygenSystem)
-                .ToString();
+    public override string Part2()
+    {
+        var changed = true;
+        while (changed)
+        {
+            changed = false;
+            foreach (var location in Location.AllLocations.Values)
+                changed = location.UpdateDistanceToOxygenSystem() || changed;
         }
 
-        private class Location
-        {
-            public const int Wall = 0;
-            public const int Empty = 1;
-            public const int System = 2;
+        return Location.AllLocations.Values
+            .Where(l => !l.IsWall)
+            .Max(l => l.DistanceToOxygenSystem)
+            .ToString();
+    }
 
-            private static readonly int[] Dx = {0, 0, 0, 1, -1};
-            private static readonly int[] Dy = {0, 1, -1, 0, 0};
-            public static readonly int[] Opposites = {0, 2, 1, 4, 3};
+    private class Location
+    {
+        public const int Wall = 0;
+        public const int Empty = 1;
+        public const int System = 2;
 
-            public static readonly Dictionary<(int x, int y), Location>
-                AllLocations = new Dictionary<(int x, int y), Location>();
+        private static readonly int[] Dx = { 0, 0, 0, 1, -1 };
+        private static readonly int[] Dy = { 0, 1, -1, 0, 0 };
+        public static readonly int[] Opposites = { 0, 2, 1, 4, 3 };
 
-            private readonly int currentType;
-            public int DistanceToOxygenSystem = int.MaxValue - 1;
+        public static readonly Dictionary<(int x, int y), Location> AllLocations = new();
 
-            private int searchDirection = 1;
+        private readonly int currentType;
+        public int DistanceToOxygenSystem = int.MaxValue - 1;
 
-            public Location(int x, int y, int prev = 0, int type = Empty)
-            {
-                PreviousDirection = prev;
-                currentType = type;
-                X = x;
-                Y = y;
+        private int searchDirection = 1;
 
-                if (type == System)
-                {
-                    OxygenLocation = this;
-                    DistanceToOxygenSystem = 0;
-                    // Console.WriteLine($"Found Oxygen System at ({x}, {y})");
-                }
+        public Location(int x, int y, int prev = 0, int type = Empty)
+        {
+            PreviousDirection = prev;
+            currentType = type;
+            X = x;
+            Y = y;
 
-                AllLocations.Add((x, y), this);
+            if (type == System)
+            {
+                OxygenLocation = this;
+                DistanceToOxygenSystem = 0;
+                // Console.WriteLine($"Found Oxygen System at ({x}, {y})");
             }
 
-            public static Location OxygenLocation { get; private set; }
-            public int PreviousDirection { get; }
-            private int X { get; }
-            private int Y { get; }
+            AllLocations.Add((x, y), this);
+        }
 
-            public bool IsWall => currentType == Wall;
+        public static Location? OxygenLocation { get; private set; }
+        public int PreviousDirection { get; }
+        private int X { get; }
+        private int Y { get; }
 
-            public string Image()
-            {
-                return currentType switch
-                {
-                    Wall => "\u2587",
-                    Empty => X == 0 && Y == 0 ? "S" : " ",
-                    System => "O",
-                    _ => "?"
-                };
-            }
+        public bool IsWall => currentType == Wall;
 
-            public bool UpdateDistanceToOxygenSystem()
+        public string Image()
+        {
+            return currentType switch
             {
-                if (currentType != Empty) return false;
+                Wall => "\u2587",
+                Empty => X == 0 && Y == 0 ? "S" : " ",
+                System => "O",
+                _ => "?"
+            };
+        }
+
+        public bool UpdateDistanceToOxygenSystem()
+        {
+            if (currentType != Empty) return false;
 
-                foreach (var direction in Enumerable.Range(1, 4))
+            foreach (var direction in Enumerable.Range(1, 4))
+            {
+                var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue;
+                if (distance + 1 < DistanceToOxygenSystem)
                 {
-                    var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue;
-                    if (distance + 1 < DistanceToOxygenSystem)
-                    {
-                        DistanceToOxygenSystem = distance + 1;
-                        return true;
-                    }
+                    DistanceToOxygenSystem = distance + 1;
+                    return true;
                 }
-
-                return false;
             }
 
-            public (int, int) Neighbor(int direction)
-            {
-                return (X + Dx[direction], Y + Dy[direction]);
-            }
+            return false;
+        }
 
-            public (int, int) PreviousLocation()
-            {
-                return Neighbor(PreviousDirection);
-            }
+        public (int, int) Neighbor(int direction)
+        {
+            return (X + Dx[direction], Y + Dy[direction]);
+        }
 
-            public int NextDirection()
-            {
-                return searchDirection++;
-            }
+        public (int, int) PreviousLocation()
+        {
+            return Neighbor(PreviousDirection);
+        }
 
-            public static Location GetLocation(int x, int y)
-            {
-                return AllLocations.ContainsKey((x, y)) ? AllLocations[(x, y)] : null;
-            }
+        public int NextDirection()
+        {
+            return searchDirection++;
+        }
 
-            public static Location GetLocation((int x, int y) coords)
-            {
-                return GetLocation(coords.x, coords.y);
-            }
+        public static Location? GetLocation(int x, int y)
+        {
+            return AllLocations.ContainsKey((x, y)) ? AllLocations[(x, y)] : null;
+        }
+
+        public static Location? GetLocation((int x, int y) coords)
+        {
+            return GetLocation(coords.x, coords.y);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day16.cs b/aoc2019/Day16.cs
index 310363a..1c5481e 100644
--- a/aoc2019/Day16.cs
+++ b/aoc2019/Day16.cs
@@ -1,64 +1,58 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day16 : Day
 {
-    public sealed class Day16 : Day
+    private static readonly int[] BasePattern = { 0, 1, 0, -1 };
+    private readonly int[] initialList;
+
+    public Day16() : base(16, "Flawed Frequency Transmission")
     {
-        private static readonly int[] BasePattern = {0, 1, 0, -1};
-        private readonly int[] initialList;
+        initialList = Input.First().Select(c => int.Parse($"{c}")).ToArray();
+    }
 
-        public Day16() : base(16, "Flawed Frequency Transmission")
-        {
-            initialList = Input.First().Select(c => int.Parse($"{c}")).ToArray();
-        }
+    public override string Part1()
+    {
+        const int phaseCount = 100;
+        var signal0 = initialList.ToArray();
+        var signal1 = new int[signal0.Length];
 
-        public override string Part1()
-        {
-            const int phaseCount = 100;
-            var signal0 = initialList.ToArray();
-            var signal1 = new int[signal0.Length];
+        for (var i = 0; i < phaseCount; i++)
+            CalculateSignal(i % 2 == 0 ? signal0 : signal1, i % 2 == 0 ? signal1 : signal0);
 
-            for (var i = 0; i < phaseCount; i++)
-                CalculateSignal(i % 2 == 0 ? signal0 : signal1, i % 2 == 0 ? signal1 : signal0);
+        return new string(
+            signal0.Take(8).Select(c => (char)(c + '0'))
+                .ToArray());
+    }
 
-            return new string(
-                signal0.Take(8).Select(c => (char) (c + '0'))
-                    .ToArray());
-        }
+    public override string Part2()
+    {
+        const int phaseCount = 100;
+        var messageOffset = initialList.Take(7).Aggregate((n, i) => n * 10 + i);
+        var signal = initialList.Repeat(10_000).Skip(messageOffset).ToArray();
 
-        public override string Part2()
+        for (var p = 0; p < phaseCount; p++)
         {
-            const int phaseCount = 100;
-            var messageOffset = initialList.Take(7).Aggregate((n, i) => n * 10 + i);
-            var signal = initialList.Repeat(10_000).Skip(messageOffset).ToArray();
-
-            for (var p = 0; p < phaseCount; p++)
-            {
-                signal[^1] %= 10;
-                for (var i = signal.Length - 2; i >= 0; i--)
-                    signal[i] = (signal[i + 1] + signal[i]) % 10;
-            }
-
-            return new string(signal.Take(8).Select(c => (char) (c + '0')).ToArray());
+            signal[^1] %= 10;
+            for (var i = signal.Length - 2; i >= 0; i--)
+                signal[i] = (signal[i + 1] + signal[i]) % 10;
         }
 
-        private static void CalculateSignal(IReadOnlyList<int> input, IList<int> output)
-        {
-            for (var outputIndex = 0; outputIndex < output.Count; outputIndex++)
-                output[outputIndex] =
-                    Math.Abs(PatternValues(outputIndex, input.Count).Select((pv, i) => pv * input[i] % 10).Sum()) % 10;
-        }
+        return new string(signal.Take(8).Select(c => (char)(c + '0')).ToArray());
+    }
 
-        private static IEnumerable<int> PatternValues(int index, int count)
-        {
-            return BasePattern
-                .SelectMany(v => Enumerable.Repeat(v, index + 1))
-                .Repeat(int.MaxValue)
-                .Skip(1)
-                .Take(count);
-        }
+    private static void CalculateSignal(IReadOnlyList<int> input, IList<int> output)
+    {
+        for (var outputIndex = 0; outputIndex < output.Count; outputIndex++)
+            output[outputIndex] =
+                Math.Abs(PatternValues(outputIndex, input.Count).Select((pv, i) => pv * input[i] % 10).Sum()) % 10;
+    }
+
+    private static IEnumerable<int> PatternValues(int index, int count)
+    {
+        return BasePattern
+            .SelectMany(v => Enumerable.Repeat(v, index + 1))
+            .Repeat(int.MaxValue)
+            .Skip(1)
+            .Take(count);
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day17.cs b/aoc2019/Day17.cs
index 0a3b550..376a80f 100644
--- a/aoc2019/Day17.cs
+++ b/aoc2019/Day17.cs
@@ -1,32 +1,27 @@
-using System;
-using System.Linq;
-using System.Text;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day17 : Day
 {
-    public sealed class Day17 : Day
-    {
-        private readonly bool Verbose = false;
-        private readonly IntCodeVM vm;
+    private readonly bool Verbose = false;
+    private readonly IntCodeVM vm;
 
-        public Day17() : base(17, "Set and Forget")
-        {
-            vm = new IntCodeVM(Input.First());
-        }
+    public Day17() : base(17, "Set and Forget")
+    {
+        vm = new IntCodeVM(Input.First());
+    }
 
-        public override string Part1()
-        {
-            vm.Reset();
-            vm.Run();
-            var sb = new StringBuilder();
-            while (vm.output.Any())
-                sb.Append((char) vm.Result);
-            if (Verbose) Console.Write(sb);
-            var grid = sb.ToString().Trim().Split().Select(s => s.ToCharArray()).ToArray();
+    public override string Part1()
+    {
+        vm.Reset();
+        vm.Run();
+        var sb = new StringBuilder();
+        while (vm.output.Any())
+            sb.Append((char)vm.Result);
+        if (Verbose) Console.Write(sb);
+        var grid = sb.ToString().Trim().Split().Select(s => s.ToCharArray()).ToArray();
 
-            var sum = 0;
-            for (var y = 1; y < grid.Length - 1; y++)
+        var sum = 0;
+        for (var y = 1; y < grid.Length - 1; y++)
             for (var x = 1; x < grid[y].Length - 1; x++)
                 if (grid[y][x] == '#' &&
                     grid[y - 1][x] == '#' &&
@@ -35,19 +30,18 @@ namespace aoc2019
                     grid[y][x + 1] == '#')
                     sum += x * y;
 
-            return $"{sum}";
-        }
+        return $"{sum}";
+    }
 
-        public override string Part2()
-        {
-            //vm.Reset();
-            //vm.memory[0] = 2;
-            //var halt = IntCodeVM.HaltType.Waiting;
-            //while (halt == IntCodeVM.HaltType.Waiting)
-            //{
-            //    halt = vm.Run();
-            //}
-            return "";
-        }
+    public override string Part2()
+    {
+        //vm.Reset();
+        //vm.memory[0] = 2;
+        //var halt = IntCodeVM.HaltType.Waiting;
+        //while (halt == IntCodeVM.HaltType.Waiting)
+        //{
+        //    halt = vm.Run();
+        //}
+        return "";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day18.cs b/aoc2019/Day18.cs
new file mode 100644
index 0000000..0760cd7
--- /dev/null
+++ b/aoc2019/Day18.cs
@@ -0,0 +1,18 @@
+namespace aoc2019;
+
+public sealed class Day18 : Day
+{
+    public Day18() : base(18, "Many-Worlds Interpretation")
+    {
+    }
+
+    public override string Part1()
+    {
+        return "";
+    }
+
+    public override string Part2()
+    {
+        return "";
+    }
+}
diff --git a/aoc2019/Day19.cs b/aoc2019/Day19.cs
index fe6b435..2136bcb 100644
--- a/aoc2019/Day19.cs
+++ b/aoc2019/Day19.cs
@@ -1,22 +1,19 @@
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day19 : Day
 {
-    public sealed class Day19 : Day
-    {
-        private readonly long[,] grid;
-        private readonly IntCodeVM vm;
+    private readonly long[,] grid;
+    private readonly IntCodeVM vm;
 
-        public Day19() : base(19, "Tractor Beam")
-        {
-            vm = new IntCodeVM(Input.First());
-            grid = new long[50, 50];
-        }
+    public Day19() : base(19, "Tractor Beam")
+    {
+        vm = new IntCodeVM(Input.First());
+        grid = new long[50, 50];
+    }
 
-        public override string Part1()
-        {
-            for (var x = 0; x < 50; x++)
+    public override string Part1()
+    {
+        for (var x = 0; x < 50; x++)
             for (var y = 0; y < 50; y++)
             {
                 vm.Reset();
@@ -24,26 +21,25 @@ namespace aoc2019
                 grid[x, y] = vm.Result;
             }
 
-            return $"{grid.Cast<long>().Sum()}";
-        }
+        return $"{grid.Cast<long>().Sum()}";
+    }
 
-        public override string Part2()
+    public override string Part2()
+    {
+        for (int x = 101, y = 0; ; x++)
         {
-            for (int x = 101, y = 0;; x++)
+            while (true)
             {
-                while (true)
-                {
-                    vm.Reset();
-                    vm.Run(x, y);
-                    if (vm.Result == 1) break;
-                    y++;
-                }
-
                 vm.Reset();
-                vm.Run(x - 99, y + 99);
-                if (vm.Result == 1)
-                    return $"{(x - 99) * 1e4 + y}";
+                vm.Run(x, y);
+                if (vm.Result == 1) break;
+                y++;
             }
+
+            vm.Reset();
+            vm.Run(x - 99, y + 99);
+            if (vm.Result == 1)
+                return $"{(x - 99) * 1e4 + y}";
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day20.cs b/aoc2019/Day20.cs
new file mode 100644
index 0000000..a8a521a
--- /dev/null
+++ b/aoc2019/Day20.cs
@@ -0,0 +1,18 @@
+namespace aoc2019;
+
+public sealed class Day20 : Day
+{
+    public Day20() : base(20, "Donut Maze")
+    {
+    }
+
+    public override string Part1()
+    {
+        return "";
+    }
+
+    public override string Part2()
+    {
+        return "";
+    }
+}
diff --git a/aoc2019/Day21.cs b/aoc2019/Day21.cs
index e2bc3fb..d81c114 100644
--- a/aoc2019/Day21.cs
+++ b/aoc2019/Day21.cs
@@ -1,27 +1,23 @@
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day21 : Day
 {
-    public sealed class Day21 : Day
-    {
-        private readonly IntCodeVM vm;
+    private readonly IntCodeVM vm;
 
-        public Day21() : base(21, "Springdroid Adventure")
-        {
-            vm = new IntCodeVM(Input.First());
-        }
+    public Day21() : base(21, "Springdroid Adventure")
+    {
+        vm = new IntCodeVM(Input.First());
+    }
 
-        public override string Part1()
-        {
-            vm.Reset();
-            var halt = vm.Run();
-            return "";
-        }
+    public override string Part1()
+    {
+        vm.Reset();
+        var halt = vm.Run();
+        return "";
+    }
 
-        public override string Part2()
-        {
-            return "";
-        }
+    public override string Part2()
+    {
+        return "";
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day22.cs b/aoc2019/Day22.cs
new file mode 100644
index 0000000..eaa3488
--- /dev/null
+++ b/aoc2019/Day22.cs
@@ -0,0 +1,18 @@
+namespace aoc2019;
+
+public sealed class Day22 : Day
+{
+    public Day22() : base(22, "Slam Shuffle")
+    {
+    }
+
+    public override string Part1()
+    {
+        return "";
+    }
+
+    public override string Part2()
+    {
+        return "";
+    }
+}
diff --git a/aoc2019/Day23.cs b/aoc2019/Day23.cs
index 53c840c..29da6a7 100644
--- a/aoc2019/Day23.cs
+++ b/aoc2019/Day23.cs
@@ -1,90 +1,86 @@
-using System.Linq;
-using aoc2019.lib;
+namespace aoc2019;
 
-namespace aoc2019
+public sealed class Day23 : Day
 {
-    public sealed class Day23 : Day
+    public Day23() : base(23, "Category Six")
     {
-        public Day23() : base(23, "Category Six")
-        {
-        }
+    }
 
-        public override string Part1()
-        {
-            var vms = Enumerable.Range(0, 50)
-                .Select((s, i) =>
-                {
-                    var vm = new IntCodeVM(Input.First());
-                    vm.Run(i);
-                    return vm;
-                }).ToList();
+    public override string Part1()
+    {
+        var vms = Enumerable.Range(0, 50)
+            .Select((s, i) =>
+            {
+                var vm = new IntCodeVM(Input.First());
+                vm.Run(i);
+                return vm;
+            }).ToList();
 
-            while (true)
-                foreach (var vm in vms)
+        while (true)
+            foreach (var vm in vms)
+            {
+                while (vm.output.Count > 0)
                 {
-                    while (vm.output.Count > 0)
-                    {
-                        var destination = (int) vm.Result;
-                        var x = vm.Result;
-                        var y = vm.Result;
-
-                        if (destination == 255) return $"{y}";
+                    var destination = (int)vm.Result;
+                    var x = vm.Result;
+                    var y = vm.Result;
 
-                        vms[destination].Run(x, y);
-                    }
+                    if (destination == 255) return $"{y}";
 
-                    vm.Run(-1);
+                    vms[destination].Run(x, y);
                 }
-        }
 
-        public override string Part2()
-        {
-            var vms = Enumerable.Range(0, 50)
-                .Select((s, i) =>
-                {
-                    var vm = new IntCodeVM(Input.First());
-                    vm.Run(i);
-                    return vm;
-                }).ToList();
+                vm.Run(-1);
+            }
+    }
+
+    public override string Part2()
+    {
+        var vms = Enumerable.Range(0, 50)
+            .Select((s, i) =>
+            {
+                var vm = new IntCodeVM(Input.First());
+                vm.Run(i);
+                return vm;
+            }).ToList();
 
-            long natX = 0, natY = 0, lastYSent = -1;
+        long natX = 0, natY = 0, lastYSent = -1;
 
-            while (true)
+        while (true)
+        {
+            var numIdle = 0;
+            foreach (var vm in vms)
             {
-                var numIdle = 0;
-                foreach (var vm in vms)
+                var isIdle = true;
+                while (vm.output.Count > 0)
                 {
-                    var isIdle = true;
-                    while (vm.output.Count > 0)
-                    {
-                        var destination = (int) vm.Result;
-                        var x = vm.Result;
-                        var y = vm.Result;
+                    var destination = (int)vm.Result;
+                    var x = vm.Result;
+                    var y = vm.Result;
 
-                        if (destination == 255)
-                        {
-                            natX = x;
-                            natY = y;
-                        }
-                        else
-                        {
-                            vms[destination].Run(x, y);
-                        }
-
-                        isIdle = false;
+                    if (destination == 255)
+                    {
+                        natX = x;
+                        natY = y;
+                    }
+                    else
+                    {
+                        vms[destination].Run(x, y);
                     }
 
-                    vm.Run(-1);
-                    if (isIdle) numIdle++;
+                    isIdle = false;
                 }
 
-                if (numIdle == 50)
-                {
-                    if (natY == lastYSent) return $"{natY}";
-                    vms[0].Run(natX, natY);
-                    lastYSent = natY;
-                }
+                vm.Run(-1);
+                if (isIdle) numIdle++;
+            }
+
+            if (numIdle == 50)
+            {
+                if (natY == lastYSent) return $"{natY}";
+                vms[0].Run(natX, natY);
+                lastYSent = natY;
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/Day24.cs b/aoc2019/Day24.cs
new file mode 100644
index 0000000..fee2339
--- /dev/null
+++ b/aoc2019/Day24.cs
@@ -0,0 +1,18 @@
+namespace aoc2019;
+
+public sealed class Day24 : Day
+{
+    public Day24() : base(24, "Planet of Discord")
+    {
+    }
+
+    public override string Part1()
+    {
+        return "";
+    }
+
+    public override string Part2()
+    {
+        return "";
+    }
+}
diff --git a/aoc2019/Day25.cs b/aoc2019/Day25.cs
new file mode 100644
index 0000000..5d45cdc
--- /dev/null
+++ b/aoc2019/Day25.cs
@@ -0,0 +1,18 @@
+namespace aoc2019;
+
+public sealed class Day25 : Day
+{
+    public Day25() : base(25, "Cryostasis")
+    {
+    }
+
+    public override string Part1()
+    {
+        return "";
+    }
+
+    public override string Part2()
+    {
+        return "";
+    }
+}
diff --git a/aoc2019/Extensions.cs b/aoc2019/Extensions.cs
new file mode 100644
index 0000000..76588c2
--- /dev/null
+++ b/aoc2019/Extensions.cs
@@ -0,0 +1,45 @@
+using System.Diagnostics;
+
+namespace aoc2019;
+
+public static class Extensions
+{
+    public static IEnumerable<IEnumerable<T>> Permute<T>(this IEnumerable<T> list)
+    {
+        if (list.Count() == 1) return new[] { list };
+        return list.SelectMany(t => Permute(list.Where(x => !x!.Equals(t))), (v, p) => p.Prepend(v));
+    }
+
+    public static IEnumerable<string> Chunk(this string str, int chunkSize)
+    {
+        for (var i = 0; i < str.Length; i += chunkSize)
+            yield return str.Substring(i, chunkSize);
+    }
+
+    public static string ToDelimitedString<T>(this IEnumerable<T> enumerable, string delimiter = "")
+    {
+        return string.Join(delimiter, enumerable);
+    }
+
+    public static IEnumerable<T> Repeat<T>(this IEnumerable<T> sequence, int? count = null)
+    {
+        while (count == null || count-- > 0)
+            foreach (var item in sequence)
+                yield return item;
+    }
+
+    /// <summary>
+    ///     increased accuracy for stopwatch based on frequency.
+    ///     <see
+    ///         href="http://geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx">
+    ///         blog
+    ///         details here
+    ///     </see>
+    /// </summary>
+    /// <param name="stopwatch"></param>
+    /// <returns></returns>
+    public static double ScaleMilliseconds(this Stopwatch stopwatch)
+    {
+        return 1_000 * stopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
+    }
+}
diff --git a/aoc2019/IntCodeVM.cs b/aoc2019/IntCodeVM.cs
new file mode 100644
index 0000000..d6f1214
--- /dev/null
+++ b/aoc2019/IntCodeVM.cs
@@ -0,0 +1,155 @@
+namespace aoc2019;
+
+public class IntCodeVM
+{
+    public enum HaltType
+    {
+        Terminate,
+        Waiting
+    }
+
+    private readonly long[] program;
+    private long i;
+    public Queue<long> input, output;
+    public long[] memory;
+    private long relativeBase;
+
+    public IntCodeVM(string tape)
+    {
+        i = 0;
+        relativeBase = 0;
+        program = tape.Split(',').Select(long.Parse).ToArray();
+        memory = program;
+        input = new Queue<long>();
+        output = new Queue<long>();
+    }
+
+    public long Result => output.Dequeue();
+
+    public void Reset()
+    {
+        i = 0;
+        relativeBase = 0;
+        memory = program;
+        input.Clear();
+        output.Clear();
+    }
+
+    public void AddInput(params long[] values)
+    {
+        foreach (var v in values) AddInput(v);
+    }
+
+    public void AddInput(long value)
+    {
+        input.Enqueue(value);
+    }
+
+    private long MemGet(long addr)
+    {
+        return addr < memory.Length ? memory[addr] : 0;
+    }
+
+    private void MemSet(long addr, long value)
+    {
+        if (addr < 0) addr = 0;
+        if (addr >= memory.Length)
+            Array.Resize(ref memory, (int)addr + 1);
+        memory[addr] = value;
+    }
+
+    private long Mode(long idx)
+    {
+        var mode = MemGet(i) / 100;
+        for (var s = 1; s < idx; s++)
+            mode /= 10;
+        return mode % 10;
+    }
+
+    private long Get(long idx)
+    {
+        var param = MemGet(i + idx);
+        return Mode(idx) switch
+        {
+            0 => MemGet(param),
+            1 => param,
+            2 => MemGet(relativeBase + param),
+            _ => throw new Exception("invalid parameter mode"),
+        };
+    }
+
+    private void Set(long idx, long val)
+    {
+        var param = MemGet(i + idx);
+        switch (Mode(idx))
+        {
+            case 0:
+                MemSet(param, val);
+                break;
+            case 1: throw new Exception("cannot set in immediate mode");
+            case 2:
+                MemSet(relativeBase + param, val);
+                break;
+            default: throw new Exception("invalid parameter mode");
+        }
+    }
+
+    public HaltType Run(params long[] additionalInput)
+    {
+        foreach (var s in additionalInput) AddInput(s);
+        return Run();
+    }
+
+    public HaltType Run()
+    {
+        while (i < memory.Length)
+        {
+            var op = MemGet(i) % 100;
+            switch (op)
+            {
+                case 1:
+                    Set(3, Get(1) + Get(2));
+                    i += 4;
+                    break;
+                case 2:
+                    Set(3, Get(1) * Get(2));
+                    i += 4;
+                    break;
+                case 3:
+                    if (!input.Any())
+                        return HaltType.Waiting;
+                    Set(1, input.Dequeue());
+                    i += 2;
+                    break;
+                case 4:
+                    output.Enqueue(Get(1));
+                    i += 2;
+                    break;
+                case 5:
+                    i = Get(1) == 0 ? i + 3 : Get(2);
+                    break;
+                case 6:
+                    i = Get(1) != 0 ? i + 3 : Get(2);
+                    break;
+                case 7:
+                    Set(3, Get(1) < Get(2) ? 1 : 0);
+                    i += 4;
+                    break;
+                case 8:
+                    Set(3, Get(1) == Get(2) ? 1 : 0);
+                    i += 4;
+                    break;
+                case 9:
+                    relativeBase += Get(1);
+                    i += 2;
+                    break;
+                case 99:
+                    return HaltType.Terminate;
+                default:
+                    throw new Exception($"unknown op {op} at {i}");
+            }
+        }
+
+        return HaltType.Terminate;
+    }
+}
diff --git a/aoc2019/Program.cs b/aoc2019/Program.cs
index c523439..ca7eec7 100644
--- a/aoc2019/Program.cs
+++ b/aoc2019/Program.cs
@@ -1,32 +1,29 @@
-using System;
-using System.Linq;
-using System.Reflection;
+using System.Reflection;
 
-namespace aoc2019
+namespace aoc2019;
+
+internal static class Program
 {
-    internal static class Program
+    private static void Main(string[] args)
     {
-        private static void Main(string[] args)
-        {
-            var days =
-                Assembly.GetExecutingAssembly().GetTypes()
-                    .Where(t => t.BaseType == typeof(Day))
-                    .Select(t => (Day) Activator.CreateInstance(t))
-                    .OrderBy(d => d.DayNumber);
+        var days =
+            Assembly.GetExecutingAssembly().GetTypes()
+                .Where(t => t.BaseType == typeof(Day))
+                .Select(t => Activator.CreateInstance(t) as Day)
+                .OrderBy(d => d?.DayNumber);
 
-            if (args.Length == 1 && int.TryParse(args[0], out var dayNum))
-            {
-                var day = days.FirstOrDefault(d => d.DayNumber == dayNum);
+        if (args.Length == 1 && int.TryParse(args[0], out var dayNum))
+        {
+            var day = days.FirstOrDefault(d => d?.DayNumber == dayNum);
 
-                if (day != null)
-                    day.AllParts();
-                else
-                    Console.WriteLine($"{dayNum} invalid or not yet implemented");
-            }
+            if (day != null)
+                day.AllParts();
             else
-            {
-                foreach (var d in days) d.AllParts();
-            }
+                Console.WriteLine($"{dayNum} invalid or not yet implemented");
+        }
+        else
+        {
+            foreach (var d in days) d?.AllParts();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/aoc2019/aoc2019.csproj b/aoc2019/aoc2019.csproj
index 494194f..fe5d9a6 100644
--- a/aoc2019/aoc2019.csproj
+++ b/aoc2019/aoc2019.csproj
@@ -2,7 +2,9 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
 
   <ItemGroup>
@@ -11,4 +13,11 @@
     </None>
   </ItemGroup>
 
+  <ItemGroup>
+    <Using Include="System.Collections.Generic" />
+    <Using Include="System.Collections.Immutable" />
+    <Using Include="System.Text" />
+    <Using Include="System.Text.RegularExpressions" />
+  </ItemGroup>
+
 </Project>
diff --git a/aoc2019/lib/Extensions.cs b/aoc2019/lib/Extensions.cs
deleted file mode 100644
index eb8c3cb..0000000
--- a/aoc2019/lib/Extensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-
-namespace aoc2019.lib
-{
-    public static class Extensions
-    {
-        public static IEnumerable<IEnumerable<T>> Permute<T>(this IEnumerable<T> list)
-        {
-            if (list.Count() == 1) return new[] {list};
-            return list.SelectMany(t => Permute(list.Where(x => !x.Equals(t))), (v, p) => p.Prepend(v));
-        }
-
-        public static IEnumerable<string> Chunk(this string str, int chunkSize)
-        {
-            for (var i = 0; i < str.Length; i += chunkSize)
-                yield return str.Substring(i, chunkSize);
-        }
-
-        public static string ToDelimitedString<T>(this IEnumerable<T> enumerable, string delimiter = "")
-        {
-            return string.Join(delimiter, enumerable);
-        }
-
-        public static IEnumerable<T> Repeat<T>(this IEnumerable<T> sequence, int? count = null)
-        {
-            while (count == null || count-- > 0)
-                foreach (var item in sequence)
-                    yield return item;
-        }
-
-        /// <summary>
-        ///     increased accuracy for stopwatch based on frequency.
-        ///     <see
-        ///         href="http://geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx">
-        ///         blog
-        ///         details here
-        ///     </see>
-        /// </summary>
-        /// <param name="stopwatch"></param>
-        /// <returns></returns>
-        public static double ScaleMilliseconds(this Stopwatch stopwatch)
-        {
-            return 1_000 * stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
-        }
-    }
-}
\ No newline at end of file
diff --git a/aoc2019/lib/IntCodeVM.cs b/aoc2019/lib/IntCodeVM.cs
deleted file mode 100644
index 4fb196f..0000000
--- a/aoc2019/lib/IntCodeVM.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace aoc2019.lib
-{
-    public class IntCodeVM
-    {
-        public enum HaltType
-        {
-            Terminate,
-            Waiting
-        }
-
-        private readonly long[] program;
-        private long i;
-        public Queue<long> input, output;
-        public long[] memory;
-        private long relativeBase;
-
-        public IntCodeVM(string tape)
-        {
-            i = 0;
-            relativeBase = 0;
-            program = tape.Split(',').Select(long.Parse).ToArray();
-            memory = program;
-            input = new Queue<long>();
-            output = new Queue<long>();
-        }
-
-        public long Result => output.Dequeue();
-
-        public void Reset()
-        {
-            i = 0;
-            relativeBase = 0;
-            memory = program;
-            input.Clear();
-            output.Clear();
-        }
-
-        public void AddInput(params long[] values)
-        {
-            foreach (var v in values) AddInput(v);
-        }
-
-        public void AddInput(long value)
-        {
-            input.Enqueue(value);
-        }
-
-        private long MemGet(long addr)
-        {
-            return addr < memory.Length ? memory[addr] : 0;
-        }
-
-        private void MemSet(long addr, long value)
-        {
-            if (addr < 0) addr = 0;
-            if (addr >= memory.Length)
-                Array.Resize(ref memory, (int) addr + 1);
-            memory[addr] = value;
-        }
-
-        private long Mode(long idx)
-        {
-            var mode = MemGet(i) / 100;
-            for (var s = 1; s < idx; s++)
-                mode /= 10;
-            return mode % 10;
-        }
-
-        private long Get(long idx)
-        {
-            var param = MemGet(i + idx);
-            switch (Mode(idx))
-            {
-                case 0: return MemGet(param);
-                case 1: return param;
-                case 2: return MemGet(relativeBase + param);
-                default: throw new Exception("invalid parameter mode");
-            }
-        }
-
-        private void Set(long idx, long val)
-        {
-            var param = MemGet(i + idx);
-            switch (Mode(idx))
-            {
-                case 0:
-                    MemSet(param, val);
-                    break;
-                case 1: throw new Exception("cannot set in immediate mode");
-                case 2:
-                    MemSet(relativeBase + param, val);
-                    break;
-                default: throw new Exception("invalid parameter mode");
-            }
-        }
-
-        public HaltType Run(params long[] additionalInput)
-        {
-            foreach (var s in additionalInput) AddInput(s);
-            return Run();
-        }
-
-        public HaltType Run()
-        {
-            while (i < memory.Length)
-            {
-                var op = MemGet(i) % 100;
-                switch (op)
-                {
-                    case 1:
-                        Set(3, Get(1) + Get(2));
-                        i += 4;
-                        break;
-                    case 2:
-                        Set(3, Get(1) * Get(2));
-                        i += 4;
-                        break;
-                    case 3:
-                        if (!input.Any())
-                            return HaltType.Waiting;
-                        Set(1, input.Dequeue());
-                        i += 2;
-                        break;
-                    case 4:
-                        output.Enqueue(Get(1));
-                        i += 2;
-                        break;
-                    case 5:
-                        i = Get(1) == 0 ? i + 3 : Get(2);
-                        break;
-                    case 6:
-                        i = Get(1) != 0 ? i + 3 : Get(2);
-                        break;
-                    case 7:
-                        Set(3, Get(1) < Get(2) ? 1 : 0);
-                        i += 4;
-                        break;
-                    case 8:
-                        Set(3, Get(1) == Get(2) ? 1 : 0);
-                        i += 4;
-                        break;
-                    case 9:
-                        relativeBase += Get(1);
-                        i += 2;
-                        break;
-                    case 99:
-                        return HaltType.Terminate;
-                    default:
-                        throw new Exception($"unknown op {op} at {i}");
-                }
-            }
-
-            return HaltType.Terminate;
-        }
-    }
-}
\ No newline at end of file