using Spectre.Console; namespace AdventOfCode.Days; public class Day2 : Day { public override int Number => 2; public override string Name => "Red-Nosed Reports"; public override void RunPart1(bool display = true) { var safeReports = 0; foreach (var line in Input.AsSpan().EnumerateLines()) { var isSafe = true; var levels = line.Split(' '); var previousDirection = 0; var previousLevel = int.MinValue; foreach (var levelRange in levels) { var level = int.Parse(line[levelRange]); // First level, skip to next if (previousLevel == int.MinValue) { previousLevel = level; continue; } // Check that direction is preserved var direction = level - previousLevel; if (previousDirection != 0 && Math.Sign(direction) != Math.Sign(previousDirection)) { isSafe = false; break; } // Check that distance >= 1 and <= 3 if (Math.Abs(direction) is < 1 or > 3) { isSafe = false; break; } previousLevel = level; previousDirection = direction; } if (isSafe) { safeReports++; } } if (display) { AnsiConsole.MarkupLine($"[green]Number of safe reports: [yellow]{safeReports}[/][/]"); } } public override void RunPart2(bool display = true) { var safeReports = 0; foreach (var line in Input.AsSpan().EnumerateLines()) { if (IsSafe(line)) { safeReports++; } } if (display) { AnsiConsole.MarkupLine($"[green]Number of safe reports: [yellow]{safeReports}[/][/]"); } return; bool IsSafe(ReadOnlySpan line, Range? toSkip = null) { var levels = line.Split(' '); var previousDirection = 0; var previousLevel = int.MinValue; Range previousLevelRange = default; Range firstLevelRange = default; foreach (var levelRange in levels) { if (levelRange.Equals(toSkip)) { // This level can be skipped using the problem dampener continue; } var level = int.Parse(line[levelRange]); // First level, skip to next if (previousLevel == int.MinValue) { previousLevel = level; previousLevelRange = levelRange; firstLevelRange = levelRange; continue; } // Check that direction is preserved var direction = level - previousLevel; if (previousDirection != 0 && Math.Sign(direction) != Math.Sign(previousDirection)) { // Also try by removing current or previous level if it's first try (problem dampener) return toSkip is null && (IsSafe(line, levelRange) || IsSafe(line, previousLevelRange) || IsSafe(line, firstLevelRange)); } // Check that distance >= 1 and <= 3 if (Math.Abs(direction) is < 1 or > 3) { // Also try by removing current or previous level if it's first try (problem dampener) return toSkip is null && (IsSafe(line, levelRange) || IsSafe(line, previousLevelRange) || IsSafe(line, firstLevelRange)); } previousLevel = level; previousDirection = direction; previousLevelRange = levelRange; } return true; } } }