using System.Buffers; using System.Numerics; using Spectre.Console; namespace AdventOfCode.Days; public class Day6 : Day { public override int Number => 6; public override string Name => "Trash Compactor"; private static SearchValues DigitsSearchValue = SearchValues.Create( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ); public override void RunPart1(bool display = true) { long grandTotal = 0; var numberRows = new List>(4); var symbolRow = new List(); var rowIndex = 0; foreach (var line in Input.EnumerateLines()) { if (rowIndex <= 3) { numberRows.Add([]); } foreach (var range in line.Split(' ')) { var span = line[range]; // Ignore split columns if (span.IsWhiteSpace()) { continue; } // Numbers if (rowIndex <= 3) { numberRows[rowIndex].Add(int.Parse(span)); } // Symbols else { symbolRow.Add(span.Trim()[0]); } } rowIndex++; } // Do the calculations var count = numberRows[0].Count; for (var i = 0; i < count; i++) { checked { grandTotal += symbolRow[i] switch { '+' => numberRows[0][i] + numberRows[1][i] + numberRows[2][i] + numberRows[3][i], '*' => numberRows[0][i] * numberRows[1][i] * numberRows[2][i] * numberRows[3][i], _ => throw new ArgumentOutOfRangeException() }; } } if (display) { AnsiConsole.MarkupLine($"[green]The grand total is: [yellow]{grandTotal}[/][/]"); } } public override void RunPart2(bool display = true) { long grandTotal = 0L; var numberRows = new List>(4); var symbolRow = new List(); var lines = Input.Split(Environment.NewLine); for (var i = 0; i < 4; i++) { numberRows.Add([]); } var offset = 0; while (offset < lines[0].Length) { // Find offset at which the next set of numbers stop var numbersEnd = offset + 1; var foundSpaceColumn = false; while (!foundSpaceColumn) { foreach (var line in lines) { // If any line does not contain a space, we can go next offset if (line[numbersEnd] is not ' ') { numbersEnd++; foundSpaceColumn = false; break; } foundSpaceColumn = true; } } for (var i = 0; i < numberRows.Count; i++) { var span = lines[i].AsSpan()[offset..numbersEnd]; // Parse number with correct offset var lastPaddingIndex = span.LastIndexOfAnyExcept(DigitsSearchValue); var lastDigitIndex = span.LastIndexOfAny(DigitsSearchValue); if (lastPaddingIndex > lastDigitIndex) { numberRows[i].Add(long.Parse(span) * (int)Math.Pow(10, lastPaddingIndex - lastDigitIndex)); } else { numberRows[i].Add(long.Parse(span)); } } // Also get the symbol symbolRow.Add(lines[4][offset]); // Next pack of numbers starts after the space column offset = numbersEnd + 1; } // Do the calculations Span numbersBuffer = stackalloc long[4]; var count = numberRows[0].Count; for (var i = 0; i < count; i++) { numbersBuffer[0] = numberRows[0][i]; numbersBuffer[1] = numberRows[1][i]; numbersBuffer[2] = numberRows[2][i]; numbersBuffer[3] = numberRows[3][i]; NumbersToRtl(numbersBuffer); grandTotal += symbolRow[i] switch { '+' => numbersBuffer[0] + numbersBuffer[1] + numbersBuffer[2] + numbersBuffer[3], '*' => ValueOrIdentity(numbersBuffer[0]) * ValueOrIdentity(numbersBuffer[1]) * ValueOrIdentity(numbersBuffer[2]) * ValueOrIdentity(numbersBuffer[3]), _ => throw new ArgumentOutOfRangeException() }; } if (display) { AnsiConsole.MarkupLine($"[green]The grand total is: [yellow]{grandTotal}[/][/]"); } return; void NumbersToRtl(Span numbers) { Span number0 = stackalloc char[4]; Span number1 = stackalloc char[4]; Span number2 = stackalloc char[4]; Span number3 = stackalloc char[4]; numbers[0].TryFormat(number0, out _, "D4"); numbers[1].TryFormat(number1, out _, "D4"); numbers[2].TryFormat(number2, out _, "D4"); numbers[3].TryFormat(number3, out _, "D4"); // Reconstruct numbers for (var i = 0; i < 4; i++) { var number = 0; if (number0[i] - '0' is not 0 and var digit0) { number = digit0; } if (number1[i] - '0' is not 0 and var digit1) { number = (number * 10) + digit1; } if (number2[i] - '0' is not 0 and var digit2) { number = (number * 10) + digit2; } if (number3[i] - '0' is not 0 and var digit3) { number = (number * 10) + digit3; } numbers[i] = number; } } long ValueOrIdentity(long value) => value is 0 ? 1 : value; } }