139 lines
4.1 KiB
C#
139 lines
4.1 KiB
C#
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<char> 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;
|
|
}
|
|
}
|
|
} |