From 4062039bad15fb471bde8eb92c006ed63bfb8e9c Mon Sep 17 00:00:00 2001 From: Parnic Date: Fri, 17 Dec 2021 10:20:18 -0600 Subject: [PATCH] Day 17 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've done better. I've done worse. ¯\_(ツ)_/¯ --- advent-of-code-2021.csproj | 3 + inputs/17.txt | 1 + src/17.cs | 183 +++++++++++++++++++++++++++++++++++++ src/main.cs | 3 +- 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 inputs/17.txt create mode 100644 src/17.cs diff --git a/advent-of-code-2021.csproj b/advent-of-code-2021.csproj index efdfd38..8cf4a20 100644 --- a/advent-of-code-2021.csproj +++ b/advent-of-code-2021.csproj @@ -66,6 +66,9 @@ PreserveNewest + + PreserveNewest + diff --git a/inputs/17.txt b/inputs/17.txt new file mode 100644 index 0000000..65e5855 --- /dev/null +++ b/inputs/17.txt @@ -0,0 +1 @@ +target area: x=32..65, y=-225..-177 \ No newline at end of file diff --git a/src/17.cs b/src/17.cs new file mode 100644 index 0000000..1cae221 --- /dev/null +++ b/src/17.cs @@ -0,0 +1,183 @@ +using System.Diagnostics; + +namespace aoc2021; + +internal class Day17 : Day +{ + [DebuggerDisplay("{minX},{minY} -> {maxX},{maxY}")] + private struct Rectangle + { + public int minX = 0; + public int minY = 0; + public int maxX = 0; + public int maxY = 0; + + public bool Contains((int x, int y) pt) => pt.x >= minX && pt.x <= maxX && pt.y >= minY && pt.y <= maxY; + public bool Beyond((int x, int y) pt) => IsFar(pt) || IsLow(pt); + public bool IsShort((int x, int y) pt) => pt.x < minX; + public bool IsFar((int x, int y) pt) => pt.x > maxX; + public bool IsHigh((int x, int y) pt) => pt.y > maxY; + public bool IsLow((int x, int y) pt) => pt.y < minY; + } + + internal override void Go() + { + var lines = Util.ReadAllLines("inputs/17.txt"); + var instructions = lines.ElementAt(0).Split(", "); + + Rectangle bounds = new(); + + var xs = instructions[0].Split(".."); + bounds.minX = Convert.ToInt32(xs[0][(xs[0].IndexOf('=') + 1)..]); + bounds.maxX = Convert.ToInt32(xs[1]); + + var ys = instructions[1].Split(".."); + bounds.minY = Convert.ToInt32(ys[0][(ys[0].IndexOf('=') + 1)..]); + bounds.maxY = Convert.ToInt32(ys[1]); + + Part1(bounds); + Part2(bounds); + } + + private static (int x, int y) Step((int x, int y) pt, ref (int x, int y) velocity) + { + pt.x += velocity.x; + pt.y += velocity.y; + if (velocity.x > 0) + { + velocity.x--; + } + else if (velocity.x < 0) + { + velocity.x++; + } + velocity.y--; + + return (pt.x, pt.y); + } + + private static void Part1(Rectangle bounds) + { + using var t = new Timer(); + + var successes = GetSuccessfulVelocities(bounds); + var max = successes.MaxBy(vel => vel.Value); + var numOthers = successes.Count(vel => vel.Value == max.Value); + + Logger.Log($"<+black>> part1: highest Y was at velocity {max.Key} (and {numOthers} other{(numOthers == 1 ? "" : "s")}): <+white>{max.Value}"); + } + + private static void Part2(Rectangle bounds) + { + using var t = new Timer(); + + var successes = GetSuccessfulVelocities(bounds); + + Logger.Log($"<+black>> part2: #successful velocities: <+white>{successes.Count}"); + } + + private static Dictionary<(int x, int y), int> GetSuccessfulVelocities(Rectangle bounds) + { + var (minX, maxX) = GetXVelocityRange(bounds); + var (minY, maxY) = GetYVelocityRange(bounds); + + (int x, int y) pt; + Dictionary<(int x, int y), int> successes = new(); + for (int x = minX; x <= maxX; x++) + { + for (int y = minY; y <= maxY; y++) + { + pt = (0, 0); + var startingVelocity = (x, y); + var velocity = startingVelocity; + int currHighestY = int.MinValue; + while (!bounds.Beyond(pt) && !bounds.Contains(pt)) + { + pt = Step(pt, ref velocity); + if (pt.y > currHighestY) + { + currHighestY = pt.y; + } + } + + if (bounds.Contains(pt)) + { + successes.Add(startingVelocity, currHighestY); + } + } + } + + return successes; + } + + private static (int min, int max) GetXVelocityRange(Rectangle bounds) + { + var minSuccessXVel = int.MaxValue; + for (var guess = bounds.maxX; ; guess--) + { + var guesspt = (0, 0); + var testVel = (x: guess, 0); + while (testVel.x > 0) + { + guesspt = Step(guesspt, ref testVel); + } + + if (bounds.IsShort(guesspt)) + { + break; + } + else if (!bounds.IsFar(guesspt)) + { + if (guess < minSuccessXVel) + { + minSuccessXVel = guess; + } + } + } + + return (minSuccessXVel, bounds.maxX); + } + + private static (int min, int max) GetYVelocityRange(Rectangle bounds) + { + int maxSuccessYVel = int.MinValue; + int guess = bounds.minY; + bool foundYVals = false; + while (!foundYVals) + { + var guesspt = (0, 0); + var testVel = (0, guess); + bool lastWasAbove = false; + while (true) + { + guesspt = Step(guesspt, ref testVel); + if (bounds.IsHigh(guesspt)) + { + lastWasAbove = true; + } + else if (!bounds.IsLow(guesspt)) + { + if (guess > maxSuccessYVel) + { + maxSuccessYVel = guess; + } + break; + } + else + { + // need to find a better way to choose a reasonable guess max... + if (lastWasAbove && guess > bounds.minY * -4) + { + foundYVals = true; + } + + break; + } + } + + guess++; + } + + return (bounds.minY, maxSuccessYVel); + } +} diff --git a/src/main.cs b/src/main.cs index 592466d..666915a 100644 --- a/src/main.cs +++ b/src/main.cs @@ -34,7 +34,8 @@ else "13" => new Day13(), "14" => new Day14(), "15" => new Day15(), - _ => new Day16(), + "16" => new Day16(), + _ => new Day17(), }; day.Go(); }