using System.Collections.Frozen; using System.Numerics; using System.Runtime.Intrinsics.X86; using System.Text; using Spectre.Console; namespace AdventOfCode.Days; public class Day21 : Day { public override int Number => 21; public override string Name => "Keypad Conundrum"; private const char Up = '^'; private const char Right = '>'; private const char Down = 'v'; private const char Left = '<'; private const char Enter = 'A'; private readonly Dictionary _numpadPositions = new() { { '7', (0, 0) }, { '8', (1, 0) }, { '9', (2, 0) }, { '4', (0, 1) }, { '5', (1, 1) }, { '6', (2, 1) }, { '1', (0, 2) }, { '2', (1, 2) }, { '3', (2, 2) }, { '0', (1, 3) }, { Enter, (2, 3) } }; private readonly Dictionary _keypadPositions = new() { { Up, (1, 0) }, { Enter, (2, 0) }, { Left, (0, 1) }, { Down, (1, 1) }, { Right, (2, 1) } }; public override void RunPart1(bool display = true) { var codes = ParseCodes(); var complexitiesSum = 0; foreach (var code in codes) { // Get first keypad sequence var firstKeypadSequence = new StringBuilder(); var currentInput = Enter; foreach (var digit in code) { firstKeypadSequence.Append(GetNumpadMoveSequence(currentInput, digit)); currentInput = digit; } // Get second keypad sequence var secondKeypadSequence = new StringBuilder(); currentInput = Enter; foreach (var input in firstKeypadSequence.ToString()) { secondKeypadSequence.Append(GetKeypadMoveSequence(currentInput, input)); currentInput = input; } // Get third and last keypad sequence var thirdKeypadSequence = new StringBuilder(); currentInput = Enter; foreach (var input in secondKeypadSequence.ToString()) { thirdKeypadSequence.Append(GetKeypadMoveSequence(currentInput, input)); currentInput = input; } complexitiesSum += thirdKeypadSequence.Length * int.Parse(code.AsSpan()[..^1]); } if (display) { AnsiConsole.MarkupLine($"[green]Sum of complexities: [yellow]{complexitiesSum}[/][/]"); } } public override void RunPart2(bool display = true) { } private string GetNumpadMoveSequence(char origin, char destination) { var originPosition = _numpadPositions[origin]; var destinationPosition = _numpadPositions[destination]; var move = destinationPosition - originPosition; var moveRight = move.X > 0; var moveDown = move.Y > 0; var sequence = string.Concat( new string(moveRight ? Right : Left, Math.Abs(move.X)), new string(moveDown ? Down : Up, Math.Abs(move.Y)), Enter.ToString() // Always end on Enter to press key ); return sequence; } private string GetKeypadMoveSequence(char origin, char destination) { var originPosition = _keypadPositions[origin]; var destinationPosition = _keypadPositions[destination]; var move = destinationPosition - originPosition; var moveRight = move.X > 0; var moveDown = move.Y > 0; var sequence = string.Concat( new string(moveDown ? Down : Up, Math.Abs(move.Y)), new string(moveRight ? Right : Left, Math.Abs(move.X)), Enter.ToString() // Always end on Enter to press key ); return sequence; } private List ParseCodes() { var codes = new List(); foreach (var line in Input.AsSpan().EnumerateLines()) { codes.Add(line.ToString()); } return codes; } 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); public int DistanceTo(Point other) { var distance = other - this; return Math.Abs(distance.X) + Math.Abs(distance.Y); } } }