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 @@ - net5.0 + net6.0 false 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) { - protected Day(int dayNumber, string puzzleName) - { - DayNumber = dayNumber; - PuzzleName = puzzleName; - } - - public int DayNumber { get; } - public string PuzzleName { get; } - - protected virtual IEnumerable 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(); + DayNumber = dayNumber; + PuzzleName = puzzleName; } -} \ No newline at end of file + + public int DayNumber { get; } + public string PuzzleName { get; } + + protected virtual IEnumerable 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(); +} 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 masses; + + public Day01() : base(1, "The Tyranny of the Rocket Equation") { - private readonly IEnumerable masses; - - 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 FullCost(int cost) - { - int total = 0, newcost, tmp = cost; - - while ((newcost = FuelCost(tmp)) >= 0) - { - total += newcost; - tmp = newcost; - } - - return total; - } - - public override string Part1() - { - return $"{masses.Sum(FuelCost)}"; - } - - public override string Part2() - { - return $"{masses.Sum(FullCost)}"; - } + masses = Input.Select(int.Parse); } -} \ No newline at end of file + + private static int FuelCost(int weight) + { + return weight / 3 - 2; + } + + private static int FullCost(int cost) + { + int total = 0, newcost, tmp = cost; + + while ((newcost = FuelCost(tmp)) >= 0) + { + total += newcost; + tmp = newcost; + } + + return total; + } + + public override string Part1() + { + return $"{masses.Sum(FuelCost)}"; + } + + public override string Part2() + { + return $"{masses.Sum(FullCost)}"; + } +} 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 input; + + public Day02() : base(2, "1202 Program Alarm") { - private readonly IEnumerable input; + input = Input.First().Split(',').Select(int.Parse); + } - 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; - 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]] + }; - 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]; + } - return v[0]; - } + public override string Part1() + { + return $"{RunIntCode(12, 2)}"; + } - public override string Part1() - { - return $"{RunIntCode(12, 2)}"; - } - - public override string Part2() - { - for (var i = 0; i < 100; i++) + public override string Part2() + { + 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> wires; + + public Day03() : base(3, "Crossed Wires") { - private readonly IEnumerable<(int, int)> intersections; - private readonly List> wires; - - 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 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; - - foreach (var step in line.Split(',')) - { - 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; - } - } - - return r; - } + wires = Input.Select(ParseWire).ToList(); + intersections = wires[0].Keys.Intersect(wires[1].Keys); } -} \ No newline at end of file + + 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}"; + } + + private static Dictionary<(int, int), int> ParseWire(string line) + { + 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]) + { + 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; + } +} 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 start; + + public Day04() : base(4, "Secure Container") { - private readonly int end; - - 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]; - } - - private bool IsValid(int i) - { - 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; - } - - 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 Part1() - { - return $"{Enumerable.Range(start, end).Count(IsValid)}"; - } - - public override string Part2() - { - return $"{Enumerable.Range(start, end).Count(HasOnePair)}"; - } + var range = Input.First().Split('-').Select(int.Parse).ToList(); + start = range[0]; + end = range[1]; } -} \ No newline at end of file + + private bool IsValid(int i) + { + 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; + } + + 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 Part1() + { + return $"{Enumerable.Range(start, end).Count(IsValid)}"; + } + + public override string Part2() + { + return $"{Enumerable.Range(start, end).Count(HasOnePair)}"; + } +} 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 tape; + + private int output; + + public Day05() : base(5, "Sunny with a Chance of Asteroids") { - private readonly IEnumerable tape; + tape = Input.First().Split(',').Select(int.Parse); + } - private int output; - - public Day05() : base(5, "Sunny with a Chance of Asteroids") + public void RunIntCode(List v, int input) + { + var i = 0; + while (i < v.Count && v[i] != 99) { - tape = Input.First().Split(',').Select(int.Parse); - } - - public void RunIntCode(List v, int input) - { - 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 Part2() - { - RunIntCode(tape.ToList(), 5); - return $"{output}"; - } } -} \ No newline at end of file + + public override string Part1() + { + RunIntCode(tape.ToList(), 1); + return $"{output}"; + } + + public override string Part2() + { + RunIntCode(tape.ToList(), 5); + return $"{output}"; + } +} 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 input; + + public Day06() : base(6, "Universal Orbit Map") { - private readonly Dictionary input; - - public Day06() : base(6, "Universal Orbit Map") - { - input = Input.ToDictionary(i => i.Split(')')[1], i => i.Split(')')[0]); - } - - private List GetParents(string obj) - { - var res = new List(); - 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 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}"; - } + input = Input.ToDictionary(i => i.Split(')')[1], i => i.Split(')')[0]); } -} \ No newline at end of file + + private List GetParents(string obj) + { + var res = new List(); + 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 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}"; + } +} 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]; - - 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; - - foreach (var phaseSeq in Enumerable.Range(0, 5).Permute()) - { - i = 0; - foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq)) - { - vm.Reset(); - vm.Run(phase, i); - i = vm.Result; - } - - if (i > largest) - largest = i; - } - - return $"{largest}"; - } - - public override string Part2() - { - long i, largest = 0; - - foreach (var phaseSeq in Enumerable.Range(5, 5).Permute()) - { - i = 0; - foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq)) - { - vm.Reset(); - vm.AddInput(phase); - } - - var vms = new Queue(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; - } - - if (i > largest) - largest = i; - } - - return $"{largest}"; - } + for (var i = 0; i < 5; i++) Amplifiers[i] = new IntCodeVM(Input.First()); } -} \ No newline at end of file + + public override string Part1() + { + long i, largest = 0; + + foreach (var phaseSeq in Enumerable.Range(0, 5).Permute()) + { + i = 0; + foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq)) + { + vm.Reset(); + vm.Run(phase, i); + i = vm.Result; + } + + if (i > largest) + largest = i; + } + + return $"{largest}"; + } + + public override string Part2() + { + long i, largest = 0; + + foreach (var phaseSeq in Enumerable.Range(5, 5).Permute()) + { + i = 0; + foreach (var (vm, phase) in Amplifiers.Zip(phaseSeq)) + { + vm.Reset(); + vm.AddInput(phase); + } + + var vms = new Queue(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; + } + + if (i > largest) + largest = i; + } + + return $"{largest}"; + } +} 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> photo; + + public Day08() : base(8, "Space Image Format") { - private readonly List> photo; - - 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 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'); - } + photo = Input.First().Chunk(25 * 6).Select(s => s.ToList()).ToList(); } -} \ No newline at end of file + + 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 + ) + ) + .ToDelimitedString() + .Chunk(25) + .ToDelimitedString("\n") + .Replace('1', 'x'); + } +} 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; + + public Day09() : base(9, "Sensor Boost") { - private readonly IntCodeVM vm; - - 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 Part2() - { - vm.Reset(); - vm.Run(2); - return $"{vm.output.ToDelimitedString(",")}"; - } + vm = new IntCodeVM(Input.First()); } -} \ No newline at end of file + + 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(",")}"; + } +} 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; - - public Day10() : base(10, "Monitoring Station") - { - 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 override string Part1() - { - foreach (var asteroid in asteroids) - { - 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; - } - } - - 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 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(); - } + 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(); } -} \ No newline at end of file + + public override string Part1() + { + foreach (var asteroid in asteroids) + { + 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; + } + } + + 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 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(); + } +} 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; - - public Day11() : base(11, "Space Police") - { - vm = new IntCodeVM(Input.First()); - } - - 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) - { - 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(); - } - - 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); - } - - return map; - } - - public override string Part1() - { - return $"{PaintShip(0).Count}"; - } - - 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 - } + vm = new IntCodeVM(Input.First()); } -} \ No newline at end of file + + 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) + { + 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(); + } + + 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); + } + + return map; + } + + public override string Part1() + { + return $"{PaintShip(0).Count}"; + } + + 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 + } +} 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 moons; + private int step; + + public Day12() : base(12, "The N-Body Problem") { - private readonly List 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(); - public Day12() : base(12, "The N-Body Problem") + 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 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(); + + foreach (var moon in moons) + moon.Move(); + + step++; + } + + public override string Part1() + { + while (step < 1000) + Step(); + + return $"{moons.Sum(p => p.TotalEnergy)}"; + } + + public override string Part2() + { + int cycleX = 0, cycleY = 0, cycleZ = 0; + + while (cycleX == 0 || cycleY == 0 || cycleZ == 0) { - 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); + 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; } - public static long LCM(long a, long b) + return $"{LCM(cycleX, LCM(cycleY, cycleZ))}"; + } + + public class Position + { + public int dx, dy, dz; + private List siblings; + public int x, y, z; + + public Position(IList moon) { - return a * b / GCD(a, b); + x = moon[0]; + y = moon[1]; + z = moon[2]; + dx = 0; + dy = 0; + dz = 0; + siblings = new(); } - public static long GCD(long a, long b) + 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 TotalEnergy => + KineticEnergy * PotentialEnergy; + + public void SetSiblings(List positions) { - if (b == 0) return a; - return GCD(b, a % b); + siblings = positions.Where(p => p != this).ToList(); } - private void Step() + public override string ToString() { - foreach (var moon in moons) - moon.Gravitate(); - - foreach (var moon in moons) - moon.Move(); - - step++; + return $"pos= vel="; } - public override string Part1() + internal void Gravitate() { - while (step < 1000) - Step(); - - return $"{moons.Sum(p => p.TotalEnergy)}"; + 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; + } } - public override string Part2() + internal void Move() { - int cycleX = 0, cycleY = 0, cycleZ = 0; - - 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))}"; - } - - public class Position - { - public int dx, dy, dz; - private List siblings; - public int x, y, z; - - public Position(IList moon) - { - x = moon[0]; - y = moon[1]; - z = moon[2]; - dx = 0; - dy = 0; - dz = 0; - } - - 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 TotalEnergy => - KineticEnergy * PotentialEnergy; - - public void SetSiblings(List positions) - { - siblings = positions.Where(p => p != this).ToList(); - } - - public override string ToString() - { - return $"pos= vel="; - } - - internal void Gravitate() - { - 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; - } - } - - internal void Move() - { - x += dx; - y += dy; - z += dz; - } + 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 IntCodeVM vm; + + public Day13() : base(13, "Care Package") { - private readonly Dictionary<(int x, int y), int> board; + vm = new IntCodeVM(Input.First()); + board = new Dictionary<(int, int), int>(); + } - private readonly IntCodeVM vm; + private void UpdateTiles(IEnumerable queue) + { + var input = queue.Select(i => (int)i).ToList(); - public Day13() : base(13, "Care Package") + for (var i = 0; i < input.Count - 2; i += 3) { - vm = new IntCodeVM(Input.First()); - board = new Dictionary<(int, int), int>(); - } + var x = input[i]; + var y = input[i + 1]; + var val = input[i + 2]; - private void UpdateTiles(IEnumerable 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]; - - if (board.ContainsKey((x, y))) - board[(x, y)] = val; - else - board.Add((x, y), val); - } - } - - private void PrintBoard() - { - foreach (var ((x, y), value) in board) - { - 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()}"; - } - - public override string Part2() - { - vm.Reset(); - vm.memory[0] = 2; - var printBoard = false; - var gameTicks = 0; - if (printBoard) Console.Clear(); - - var haltType = IntCodeVM.HaltType.Waiting; - while (haltType == IntCodeVM.HaltType.Waiting) - { - haltType = vm.Run(); - UpdateTiles(vm.output); - - 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); - - gameTicks++; - if (printBoard) PrintBoard(); - } - - return $"after {gameTicks} moves, the score is: {board[(-1, 0)]}"; + if (board.ContainsKey((x, y))) + board[(x, y)] = val; + else + board.Add((x, y), val); } } -} \ No newline at end of file + + private void PrintBoard() + { + foreach (var ((x, y), value) in board) + { + 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()}"; + } + + public override string Part2() + { + vm.Reset(); + vm.memory[0] = 2; + var printBoard = false; + var gameTicks = 0; + if (printBoard) Console.Clear(); + + var haltType = IntCodeVM.HaltType.Waiting; + while (haltType == IntCodeVM.HaltType.Waiting) + { + haltType = vm.Run(); + UpdateTiles(vm.output); + + 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); + + gameTicks++; + if (printBoard) PrintBoard(); + } + + return $"after {gameTicks} moves, the score is: {board[(-1, 0)]}"; + } +} 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 reactions; + + private Dictionary available; + + public Day14() : base(14, "Space Stoichiometry") { - private readonly Dictionary reactions; + reactions = Input + .Select(Reaction.Parse) + .ToDictionary(r => r.product.Name); + + available = new(); + } - private Dictionary 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])) + private bool Produce(string chem, long quantity) + { + if (chem == "ORE") + return false; + + var reaction = reactions[chem]; + var reactionCount = (long)Math.Ceiling((double)quantity / reaction.product.Quantity); + + foreach (var reactant in reaction.reactants) + if (!Consume(reactant.Name, reactionCount * reactant.Quantity)) return false; - available[chem] -= quantity; - return true; + available[chem] = available.GetValueOrDefault(chem) + reactionCount * reaction.product.Quantity; + return true; + } + + public override string Part1() + { + available = new Dictionary { { "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 { { "ORE", capacity } }; + Consume("FUEL", 1); + + var oreConsumed = capacity - available["ORE"]; + while (Produce("FUEL", Math.Max(1, available["ORE"] / oreConsumed))) + { } - private bool Produce(string chem, long quantity) + return $"{available["FUEL"] + 1}"; + } + + private struct Component + { + public string Name { get; set; } + public int Quantity { get; set; } + } + + private class Reaction + { + public readonly Component product; + public readonly Component[] reactants; + + private Reaction(Component[] reactants, Component product) { - if (chem == "ORE") - return false; - - var reaction = reactions[chem]; - var reactionCount = (long) Math.Ceiling((double) quantity / reaction.product.Quantity); - - foreach (var reactant in reaction.reactants) - if (!Consume(reactant.Name, reactionCount * reactant.Quantity)) - return false; - - available[chem] = available.GetValueOrDefault(chem) + reactionCount * reaction.product.Quantity; - return true; + this.reactants = reactants; + this.product = product; } - public override string Part1() + public static Reaction Parse(string s) { - available = new Dictionary {{"ORE", long.MaxValue}}; - Consume("FUEL", 1); - return $"{long.MaxValue - available["ORE"]}"; - } + var ss = s.Split(new[] { ", ", " => " }, StringSplitOptions.None); - public override string Part2() - { - const long capacity = 1_000_000_000_000; - available = new Dictionary {{"ORE", capacity}}; - Consume("FUEL", 1); + return new Reaction( + ss.Take(ss.Length - 1).Select(ParseComponent).ToArray(), + ParseComponent(ss[^1]) + ); - var oreConsumed = capacity - available["ORE"]; - while (Produce("FUEL", Math.Max(1, available["ORE"] / oreConsumed))) + static Component ParseComponent(string s) { - } - - return $"{available["FUEL"] + 1}"; - } - - private struct Component - { - public string Name { get; set; } - public int Quantity { get; set; } - } - - private class Reaction - { - public readonly Component product; - public readonly Component[] reactants; - - private Reaction(Component[] reactants, Component product) - { - this.reactants = reactants; - this.product = product; - } - - public static Reaction Parse(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; + + public Day15() : base(15, "Oxygen System") { - private readonly bool verbose = false; - private readonly IntCodeVM vm; + vm = new IntCodeVM(Input.First()); + } - public Day15() : base(15, "Oxygen System") + public override string Part1() + { + vm.Reset(); + var currentLocation = new Location(0, 0); + var halt = IntCodeVM.HaltType.Waiting; + while (halt == IntCodeVM.HaltType.Waiting) { - vm = new IntCodeVM(Input.First()); - } - - public override string Part1() - { - 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 + { + direction = currentLocation.PreviousDirection; + if (direction > 0) + { + halt = vm.Run(direction); + currentLocation = vm.Result switch + { + Location.Empty or Location.System => Location.GetLocation(currentLocation.Neighbor(direction)), + _ => throw new Exception($"Unknown or unexpected response for previous room: {vm.Result}"), + }; } else { - direction = currentLocation.PreviousDirection; - if (direction > 0) + if (verbose) { - halt = vm.Run(direction); - switch (vm.Result) + // 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) { - 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}"); + 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); } } - else + + currentLocation = Location.OxygenLocation; + var distance = 0; + while (currentLocation?.PreviousDirection != 0) { - 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) - { - 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); - } - } - - currentLocation = Location.OxygenLocation; - var distance = 0; - while (currentLocation.PreviousDirection != 0) - { - distance++; - currentLocation = Location.GetLocation(currentLocation.PreviousLocation()); - } - - return $"{distance}"; + 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 + return Location.AllLocations.Values + .Where(l => !l.IsWall) + .Max(l => l.DistanceToOxygenSystem) + .ToString(); + } + + private class Location + { + public const int Wall = 0; + public const int Empty = 1; + public const int System = 2; + + 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 }; + + public static readonly Dictionary<(int x, int y), Location> AllLocations = new(); + + private readonly int currentType; + public int DistanceToOxygenSystem = int.MaxValue - 1; + + private int searchDirection = 1; + + public Location(int x, int y, int prev = 0, int type = Empty) { - public const int Wall = 0; - public const int Empty = 1; - public const int System = 2; + PreviousDirection = prev; + currentType = type; + X = x; + Y = y; - 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}; - - public static readonly Dictionary<(int x, int y), Location> - AllLocations = new Dictionary<(int x, int y), Location>(); - - private readonly int currentType; - public int DistanceToOxygenSystem = int.MaxValue - 1; - - private int searchDirection = 1; - - public Location(int x, int y, int prev = 0, int type = Empty) + if (type == System) { - PreviousDirection = prev; - currentType = type; - X = x; - Y = y; + OxygenLocation = this; + DistanceToOxygenSystem = 0; + // Console.WriteLine($"Found Oxygen System at ({x}, {y})"); + } - if (type == System) + AllLocations.Add((x, y), this); + } + + public static Location? OxygenLocation { get; private set; } + public int PreviousDirection { get; } + private int X { get; } + private int Y { get; } + + public bool IsWall => currentType == Wall; + + public string Image() + { + return currentType switch + { + 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)) + { + var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue; + if (distance + 1 < DistanceToOxygenSystem) { - OxygenLocation = this; - DistanceToOxygenSystem = 0; - // Console.WriteLine($"Found Oxygen System at ({x}, {y})"); + DistanceToOxygenSystem = distance + 1; + return true; } - - AllLocations.Add((x, y), this); } - public static Location OxygenLocation { get; private set; } - public int PreviousDirection { get; } - private int X { get; } - private int Y { get; } + return false; + } - public bool IsWall => currentType == Wall; + public (int, int) Neighbor(int direction) + { + return (X + Dx[direction], Y + Dy[direction]); + } - public string Image() - { - return currentType switch - { - Wall => "\u2587", - Empty => X == 0 && Y == 0 ? "S" : " ", - System => "O", - _ => "?" - }; - } + public (int, int) PreviousLocation() + { + return Neighbor(PreviousDirection); + } - public bool UpdateDistanceToOxygenSystem() - { - if (currentType != Empty) return false; + public int NextDirection() + { + return searchDirection++; + } - foreach (var direction in Enumerable.Range(1, 4)) - { - var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue; - if (distance + 1 < DistanceToOxygenSystem) - { - DistanceToOxygenSystem = distance + 1; - return true; - } - } + public static Location? GetLocation(int x, int y) + { + return AllLocations.ContainsKey((x, y)) ? AllLocations[(x, y)] : null; + } - return false; - } - - public (int, int) Neighbor(int direction) - { - return (X + Dx[direction], Y + Dy[direction]); - } - - public (int, int) PreviousLocation() - { - return Neighbor(PreviousDirection); - } - - public int NextDirection() - { - return searchDirection++; - } - - 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); - } + 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; - - 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]; - - 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()); - } - - 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(); - - 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()); - } - - private static void CalculateSignal(IReadOnlyList input, IList 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 PatternValues(int index, int count) - { - return BasePattern - .SelectMany(v => Enumerable.Repeat(v, index + 1)) - .Repeat(int.MaxValue) - .Skip(1) - .Take(count); - } + initialList = Input.First().Select(c => int.Parse($"{c}")).ToArray(); } -} \ No newline at end of file + + 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); + + 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(); + + 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()); + } + + private static void CalculateSignal(IReadOnlyList input, IList 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 PatternValues(int index, int count) + { + return BasePattern + .SelectMany(v => Enumerable.Repeat(v, index + 1)) + .Repeat(int.MaxValue) + .Skip(1) + .Take(count); + } +} 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; + + public Day17() : base(17, "Set and Forget") { - private readonly bool Verbose = false; - private readonly IntCodeVM vm; + 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}"; - } - - public override string Part2() - { - //vm.Reset(); - //vm.memory[0] = 2; - //var halt = IntCodeVM.HaltType.Waiting; - //while (halt == IntCodeVM.HaltType.Waiting) - //{ - // halt = vm.Run(); - //} - return ""; - } + return $"{sum}"; } -} \ No newline at end of file + + public override string Part2() + { + //vm.Reset(); + //vm.memory[0] = 2; + //var halt = IntCodeVM.HaltType.Waiting; + //while (halt == IntCodeVM.HaltType.Waiting) + //{ + // halt = vm.Run(); + //} + return ""; + } +} 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; + + public Day19() : base(19, "Tractor Beam") { - private readonly long[,] grid; - private readonly IntCodeVM vm; + 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().Sum()}"; - } + return $"{grid.Cast().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; + + public Day21() : base(21, "Springdroid Adventure") { - private readonly IntCodeVM vm; - - 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 Part2() - { - return ""; - } + vm = new IntCodeVM(Input.First()); } -} \ No newline at end of file + + public override string Part1() + { + vm.Reset(); + var halt = vm.Run(); + return ""; + } + + public override string Part2() + { + return ""; + } +} 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}"; + + vms[destination].Run(x, y); + } + + 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; + + while (true) + { + var numIdle = 0; + foreach (var vm in vms) + { + var isIdle = true; + while (vm.output.Count > 0) + { + var destination = (int)vm.Result; + var x = vm.Result; + var y = vm.Result; + + if (destination == 255) + { + natX = x; + natY = y; + } + else { - var destination = (int) vm.Result; - var x = vm.Result; - var y = vm.Result; - - if (destination == 255) return $"{y}"; - vms[destination].Run(x, y); } - vm.Run(-1); + isIdle = false; } - } - 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); + if (isIdle) numIdle++; + } - long natX = 0, natY = 0, lastYSent = -1; - - while (true) + if (numIdle == 50) { - var numIdle = 0; - foreach (var vm in vms) - { - var isIdle = true; - while (vm.output.Count > 0) - { - 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; - } - - vm.Run(-1); - if (isIdle) numIdle++; - } - - if (numIdle == 50) - { - if (natY == lastYSent) return $"{natY}"; - vms[0].Run(natX, natY); - lastYSent = natY; - } + 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> Permute(this IEnumerable 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 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(this IEnumerable enumerable, string delimiter = "") + { + return string.Join(delimiter, enumerable); + } + + public static IEnumerable Repeat(this IEnumerable sequence, int? count = null) + { + while (count == null || count-- > 0) + foreach (var item in sequence) + yield return item; + } + + /// + /// increased accuracy for stopwatch based on frequency. + /// + /// blog + /// details here + /// + /// + /// + /// + 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 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(); + output = new Queue(); + } + + 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 => Activator.CreateInstance(t) as Day) + .OrderBy(d => d?.DayNumber); + + if (args.Length == 1 && int.TryParse(args[0], out var dayNum)) { - var days = - Assembly.GetExecutingAssembly().GetTypes() - .Where(t => t.BaseType == typeof(Day)) - .Select(t => (Day) Activator.CreateInstance(t)) - .OrderBy(d => d.DayNumber); + 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 @@ Exe - net5.0 + net6.0 + enable + enable @@ -11,4 +13,11 @@ + + + + + + + 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> Permute(this IEnumerable 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 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(this IEnumerable enumerable, string delimiter = "") - { - return string.Join(delimiter, enumerable); - } - - public static IEnumerable Repeat(this IEnumerable sequence, int? count = null) - { - while (count == null || count-- > 0) - foreach (var item in sequence) - yield return item; - } - - /// - /// increased accuracy for stopwatch based on frequency. - /// - /// blog - /// details here - /// - /// - /// - /// - 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 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(); - output = new Queue(); - } - - 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