Files
AdventOfCode/Days/Day6.cs
2025-12-07 15:32:02 +01:00

209 lines
6.1 KiB
C#

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<char> 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<List<long>>(4);
var symbolRow = new List<char>();
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<List<long>>(4);
var symbolRow = new List<char>();
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<long> 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<long> numbers)
{
Span<char> number0 = stackalloc char[4];
Span<char> number1 = stackalloc char[4];
Span<char> number2 = stackalloc char[4];
Span<char> 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;
}
}