using System.Collections.Frozen; using System.Numerics; using System.Text; using Spectre.Console; namespace AdventOfCode.Days; public class Day14 : Day { public override int Number => 14; public override string Name => "Restroom Redoubt"; private const int Height = 103; private const int HeightCenter = Height / 2; private const int Width = 101; private const int WidthCenter = Width / 2; private const int Iterations = 100; public override void RunPart1(bool display = true) { var robots = ParseRobots(); for (var i = 0; i < Iterations; i++) { foreach (var robot in robots) { robot.Position = new Point( Math.Abs((Width + robot.Position.X + robot.Velocity.X) % Width), Math.Abs((Height + robot.Position.Y + robot.Velocity.Y) % Height) ); } } // Compute safety factor var safetyFactor = robots.Count(r => r.Position is { X: < WidthCenter, Y: < HeightCenter }) * robots.Count(r => r.Position is { X: > WidthCenter, Y: < HeightCenter }) * robots.Count(r => r.Position is { X: < WidthCenter, Y: > HeightCenter }) * robots.Count(r => r.Position is { X: > WidthCenter, Y: > HeightCenter }); if (display) { AnsiConsole.MarkupLine($"[green]Safety factor: [yellow]{safetyFactor}[/][/]"); } } public override void RunPart2(bool display = true) { var robots = ParseRobots(); var canvas = new Canvas(Width, Height); for (var i = 0; i < int.MaxValue; i++) { for (var x = 0; x < Width; x++) { for (var y = 0; y < Height; y++) { canvas.SetPixel(x, y, Color.Grey23); } } foreach (var robot in robots) { robot.Position = new Point( Math.Abs((Width + robot.Position.X + robot.Velocity.X) % Width), Math.Abs((Height + robot.Position.Y + robot.Velocity.Y) % Height) ); canvas.SetPixel(robot.Position.X, robot.Position.Y, Color.Green1); } // Display grid if ((i + 1 - 46) % 101 == 0) { AnsiConsole.Write(canvas); AnsiConsole.WriteLine(); AnsiConsole.Write($"Seconds elapsed: {i + 1}"); var key = Console.ReadKey(true).Key; if (key is ConsoleKey.Enter) { AnsiConsole.WriteLine(); AnsiConsole.WriteLine(); AnsiConsole.MarkupLine($"[green]Image at instant: [yellow]t={i + 1}s[/][/]"); break; } AnsiConsole.Clear(); } } } private List ParseRobots() { var robots = new List(); foreach (var line in Input.AsSpan().EnumerateLines()) { var positionX = int.Parse(line[(line.IndexOf('=') + 1)..line.IndexOf(',')]); var positionY = int.Parse(line[(line.IndexOf(',') + 1)..line.IndexOf(' ')]); var velocityX = int.Parse(line[(line.LastIndexOf('=') + 1)..line.LastIndexOf(',')]); var velocityY = int.Parse(line[(line.LastIndexOf(',') + 1)..]); robots.Add(new Robot(new Point(positionX, positionY), new Point(velocityX, velocityY))); } return robots; } private class Robot(Point position, Point velocity) { public Point Position { get; set; } = position; public Point Velocity { get; } = velocity; } private readonly record struct Point(int X, int Y) : IAdditionOperators, ISubtractionOperators, IMultiplyOperators { public static Point operator +(Point left, Point right) { return new Point(left.X + right.X, left.Y + right.Y); } public static Point operator -(Point left, Point right) { return new Point(left.X - right.X, left.Y - right.Y); } public static Point operator *(Point left, int right) { return new Point(left.X * right, left.Y * right); } public static Point operator *(int left, Point right) { return new Point(right.X * left, right.Y * left); } public static implicit operator Point((int X, int Y) point) => new(point.X, point.Y); } }