Compare commits
4 Commits
0dfc6b59de
...
2k22
| Author | SHA1 | Date | |
|---|---|---|---|
| b7b3192510 | |||
| 63c866f5a0 | |||
| 147c348ee1 | |||
| aa833569da |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ riderModule.iml
|
|||||||
/_ReSharper.Caches/
|
/_ReSharper.Caches/
|
||||||
.idea/.idea.AdventOfCode/.idea
|
.idea/.idea.AdventOfCode/.idea
|
||||||
AdventOfCode.sln.DotSettings.user
|
AdventOfCode.sln.DotSettings.user
|
||||||
|
BenchmarkDotNet.Artifacts
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
|
||||||
<PackageReference Include="Spectre.Console" Version="0.45.0" />
|
<PackageReference Include="Spectre.Console" Version="0.45.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
23
DayBenchmarker.cs
Normal file
23
DayBenchmarker.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using AdventOfCode.Days;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
|
||||||
|
namespace AdventOfCode;
|
||||||
|
|
||||||
|
[ShortRunJob]
|
||||||
|
[MemoryDiagnoser(false)]
|
||||||
|
public class DayBenchmark
|
||||||
|
{
|
||||||
|
private Day Day => new Day15();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void Part1()
|
||||||
|
{
|
||||||
|
Day.RunPart1(display: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void Part2()
|
||||||
|
{
|
||||||
|
Day.RunPart2(display: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ public abstract class Day
|
|||||||
{
|
{
|
||||||
public abstract int Number { get; }
|
public abstract int Number { get; }
|
||||||
public abstract string Name { get; }
|
public abstract string Name { get; }
|
||||||
|
|
||||||
public abstract void RunPart1();
|
public abstract void RunPart1(bool display = true);
|
||||||
public abstract void RunPart2();
|
public abstract void RunPart2(bool display = true);
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
515
Days/Day1.cs
515
Days/Day1.cs
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ public class Day10 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 10;
|
public override int Number => 10;
|
||||||
public override string Name => "Cathode-Ray Tube";
|
public override string Name => "Cathode-Ray Tube";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
int cycle = 1;
|
int cycle = 1;
|
||||||
int x = 1;
|
int x = 1;
|
||||||
@@ -47,10 +47,13 @@ public class Day10 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Sum of signal strengths: [yellow]{sum}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Sum of signal strengths: [yellow]{sum}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
// Setup the CRT
|
// Setup the CRT
|
||||||
const char litPixel = '#';
|
const char litPixel = '#';
|
||||||
@@ -122,7 +125,10 @@ public class Day10 : Day
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print the CRT
|
// Print the CRT
|
||||||
AnsiConsole.Write(crtCanvas);
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.Write(crtCanvas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Input
|
#region Input
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ public class Monkey
|
|||||||
// Divide worry level by 3 before test
|
// Divide worry level by 3 before test
|
||||||
if (divideWorry)
|
if (divideWorry)
|
||||||
{
|
{
|
||||||
newValue = newValue / 3;
|
newValue = newValue / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even using this simplification, it's still needed to use longs because
|
// Even using this simplification, it's still needed to use longs because
|
||||||
// they sometime overflow before being simplified in part 2
|
// they sometime overflow before being simplified in part 2
|
||||||
newValue = newValue % (2*3*5*7*11*13*17*19);
|
newValue = newValue % (2*3*5*7*11*13*17*19);
|
||||||
@@ -77,7 +77,7 @@ public class Day11 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 11;
|
public override int Number => 11;
|
||||||
public override string Name => "Monkey in the Middle";
|
public override string Name => "Monkey in the Middle";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
const int roundsCount = 20;
|
const int roundsCount = 20;
|
||||||
|
|
||||||
@@ -95,10 +95,13 @@ public class Day11 : Day
|
|||||||
|
|
||||||
var topMonkeys = monkeys.OrderByDescending(m => m.InspectionCount).Take(2).ToList();
|
var topMonkeys = monkeys.OrderByDescending(m => m.InspectionCount).Take(2).ToList();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Monkey business: [yellow]{topMonkeys[0].InspectionCount * topMonkeys[1].InspectionCount}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Monkey business: [yellow]{topMonkeys[0].InspectionCount * topMonkeys[1].InspectionCount}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
const int roundsCount = 10_000;
|
const int roundsCount = 10_000;
|
||||||
|
|
||||||
@@ -116,7 +119,10 @@ public class Day11 : Day
|
|||||||
|
|
||||||
var topMonkeys = monkeys.OrderByDescending(m => m.InspectionCount).Take(2).ToList();
|
var topMonkeys = monkeys.OrderByDescending(m => m.InspectionCount).Take(2).ToList();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Monkey business: [yellow]{topMonkeys[0].InspectionCount * topMonkeys[1].InspectionCount}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Monkey business: [yellow]{topMonkeys[0].InspectionCount * topMonkeys[1].InspectionCount}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IImmutableList<Monkey> ParseMonkeys()
|
private static IImmutableList<Monkey> ParseMonkeys()
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class Day12 : Day
|
|||||||
private (int x, int y) _end;
|
private (int x, int y) _end;
|
||||||
private (int x, int y) _start;
|
private (int x, int y) _start;
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
var map = ParseMap();
|
var map = ParseMap();
|
||||||
var canvas = DrawMap(map);
|
var canvas = DrawMap(map);
|
||||||
@@ -57,13 +57,16 @@ public class Day12 : Day
|
|||||||
canvas.SetPixel(x, y, Color.White);
|
canvas.SetPixel(x, y, Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.Write(canvas);
|
if (display)
|
||||||
AnsiConsole.WriteLine();
|
{
|
||||||
|
AnsiConsole.Write(canvas);
|
||||||
|
AnsiConsole.WriteLine();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
var map = ParseMap();
|
var map = ParseMap();
|
||||||
var canvas = DrawMap(map);
|
var canvas = DrawMap(map);
|
||||||
@@ -77,10 +80,13 @@ public class Day12 : Day
|
|||||||
canvas.SetPixel(x, y, Color.White);
|
canvas.SetPixel(x, y, Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.Write(canvas);
|
if (display)
|
||||||
AnsiConsole.WriteLine();
|
{
|
||||||
|
AnsiConsole.Write(canvas);
|
||||||
|
AnsiConsole.WriteLine();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private (int length, List<(int x, int y)> path) ExplorePath(byte[,] map)
|
private (int length, List<(int x, int y)> path) ExplorePath(byte[,] map)
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public class Day13 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 13;
|
public override int Number => 13;
|
||||||
public override string Name => "Distress Signal";
|
public override string Name => "Distress Signal";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
var pairs = ParsePacketPairs();
|
var pairs = ParsePacketPairs();
|
||||||
|
|
||||||
@@ -169,10 +169,13 @@ public class Day13 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Right order pair indices sum: [yellow]{sum}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Right order pair indices sum: [yellow]{sum}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
var packets = ParsePackets();
|
var packets = ParsePackets();
|
||||||
|
|
||||||
@@ -186,7 +189,11 @@ public class Day13 : Day
|
|||||||
|
|
||||||
var firstDividerIndex = orderedPackets.IndexOf(firstDivider) + 1;
|
var firstDividerIndex = orderedPackets.IndexOf(firstDivider) + 1;
|
||||||
var lastDividerIndex = orderedPackets.IndexOf(lastDivider) + 1;
|
var lastDividerIndex = orderedPackets.IndexOf(lastDivider) + 1;
|
||||||
AnsiConsole.MarkupLine($"[green]Decoder key is: [yellow]{firstDividerIndex * lastDividerIndex}[/][/]");
|
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Decoder key is: [yellow]{firstDividerIndex * lastDividerIndex}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private static PacketElement ReadElement(ref ReadOnlySpan<char> packet)
|
private static PacketElement ReadElement(ref ReadOnlySpan<char> packet)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,10 +118,10 @@ public class Day14 : Day
|
|||||||
public override int Number => 14;
|
public override int Number => 14;
|
||||||
public override string Name => "Regolith Reservoir";
|
public override string Name => "Regolith Reservoir";
|
||||||
|
|
||||||
private Point _sandSource = new(500, 0);
|
private readonly Point _sandSource = new(500, 0);
|
||||||
private Point _offsetSandSource;
|
private Point _offsetSandSource;
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
var map = GenerateMap();
|
var map = GenerateMap();
|
||||||
|
|
||||||
@@ -136,12 +136,15 @@ public class Day14 : Day
|
|||||||
sandBlocksCount++;
|
sandBlocksCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.Write(canvas);
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.Write(canvas);
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total sand blocks: [yellow]{sandBlocksCount}[/][/]");
|
AnsiConsole.MarkupLine($"[green]Total sand blocks: [yellow]{sandBlocksCount}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
var map = GenerateDictionaryMap();
|
var map = GenerateDictionaryMap();
|
||||||
|
|
||||||
@@ -156,12 +159,16 @@ public class Day14 : Day
|
|||||||
sandBlocksCount++;
|
sandBlocksCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.Write(GenerateCanvas(map, _sandSource));
|
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total sand blocks: [yellow]{sandBlocksCount}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.Write(GenerateCanvas(map, _sandSource));
|
||||||
|
|
||||||
|
AnsiConsole.MarkupLine($"[green]Total sand blocks: [yellow]{sandBlocksCount}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GenerateSand(CellType[,] map, Canvas canvas, in Point sandSource)
|
private static bool GenerateSand(CellType[,] map, Canvas canvas, in Point sandSource)
|
||||||
{
|
{
|
||||||
// Stop if source is blocked
|
// Stop if source is blocked
|
||||||
if (map[sandSource.X, sandSource.Y] == CellType.Sand)
|
if (map[sandSource.X, sandSource.Y] == CellType.Sand)
|
||||||
@@ -230,7 +237,7 @@ public class Day14 : Day
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GenerateSand(IDictionary<Point, CellType> map, in Point sandSource, int groundY)
|
private static bool GenerateSand(IDictionary<Point, CellType> map, in Point sandSource, int groundY)
|
||||||
{
|
{
|
||||||
// Stop if source is blocked
|
// Stop if source is blocked
|
||||||
if (map.GetValueOrDefault(sandSource, CellType.Air) == CellType.Sand)
|
if (map.GetValueOrDefault(sandSource, CellType.Air) == CellType.Sand)
|
||||||
@@ -374,7 +381,7 @@ public class Day14 : Day
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDictionary<Point, CellType> GenerateDictionaryMap()
|
private static IDictionary<Point, CellType> GenerateDictionaryMap()
|
||||||
{
|
{
|
||||||
var paths = Input.ReadAllLines()
|
var paths = Input.ReadAllLines()
|
||||||
.Select(line => new MapPath(line.Split(" -> ")
|
.Select(line => new MapPath(line.Split(" -> ")
|
||||||
|
|||||||
292
Days/Day15.cs
Normal file
292
Days/Day15.cs
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Drawing;
|
||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Days;
|
||||||
|
|
||||||
|
public class SensorBeaconPair
|
||||||
|
{
|
||||||
|
public Point SensorPosition { get; }
|
||||||
|
public Point BeaconPosition { get; }
|
||||||
|
|
||||||
|
public int SensorRange =>
|
||||||
|
Math.Abs(SensorPosition.X - BeaconPosition.X) + Math.Abs(SensorPosition.Y - BeaconPosition.Y);
|
||||||
|
|
||||||
|
public SensorBeaconPair(in Point sensorPosition, in Point beaconPosition)
|
||||||
|
{
|
||||||
|
SensorPosition = sensorPosition;
|
||||||
|
BeaconPosition = beaconPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CoverRange
|
||||||
|
{
|
||||||
|
public int Start { get; }
|
||||||
|
public int End { get; }
|
||||||
|
public int Covered => End - Start + 1;
|
||||||
|
|
||||||
|
public CoverRange(int start, int end)
|
||||||
|
{
|
||||||
|
Start = start;
|
||||||
|
End = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverRange(CoverRange coverRange)
|
||||||
|
{
|
||||||
|
Start = coverRange.Start;
|
||||||
|
End = coverRange.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverRange Subtract(CoverRange other)
|
||||||
|
{
|
||||||
|
// Overlap on left
|
||||||
|
int newStart;
|
||||||
|
if (other.Start <= Start && other.End >= Start)
|
||||||
|
{
|
||||||
|
newStart = other.End + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newStart = Start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overlap on right
|
||||||
|
int newEnd;
|
||||||
|
if (other.Start <= End && other.End >= End)
|
||||||
|
{
|
||||||
|
newEnd = other.Start - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newEnd = End;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CoverRange(newStart, newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CoverRange operator -(CoverRange left, CoverRange right)
|
||||||
|
{
|
||||||
|
return left.Subtract(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Day15 : Day
|
||||||
|
{
|
||||||
|
public override int Number => 15;
|
||||||
|
public override string Name => "Beacon Exclusion Zone";
|
||||||
|
public override void RunPart1(bool display = true)
|
||||||
|
{
|
||||||
|
const int targetY = 2_000_000;
|
||||||
|
|
||||||
|
// Parse pairs
|
||||||
|
var pairs = ParsePairs();
|
||||||
|
|
||||||
|
var ranges = new List<CoverRange>(pairs.Count);
|
||||||
|
|
||||||
|
// Get which columns are included on line targetY, remove the ones which already contains a beacon
|
||||||
|
var beaconsOnTargetY = new HashSet<int>();
|
||||||
|
foreach (var sensorBeaconPair in pairs)
|
||||||
|
{
|
||||||
|
// Get covered columns on y line
|
||||||
|
var xCenter = sensorBeaconPair.SensorPosition.X;
|
||||||
|
var coveredColumns = sensorBeaconPair.SensorRange - Math.Abs(sensorBeaconPair.SensorPosition.Y - targetY);
|
||||||
|
|
||||||
|
if (coveredColumns > 0)
|
||||||
|
{
|
||||||
|
ranges.Add(new CoverRange(xCenter - coveredColumns, xCenter + coveredColumns));
|
||||||
|
|
||||||
|
// Check if the beacon is on targetY
|
||||||
|
if (sensorBeaconPair.BeaconPosition.Y == targetY)
|
||||||
|
{
|
||||||
|
beaconsOnTargetY.Add(sensorBeaconPair.BeaconPosition.X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove overlapped ranges => inner.Start >= outer.Start && inner.End <= outer.End));
|
||||||
|
ranges.RemoveAll(inner =>
|
||||||
|
ranges.Where(outer => outer != inner).Any(outer => inner.Start >= outer.Start && inner.End <= outer.End));
|
||||||
|
|
||||||
|
// Compute unique number of x columns
|
||||||
|
long totalCovered = 0;
|
||||||
|
for (int i = 0; i < ranges.Count; i++)
|
||||||
|
{
|
||||||
|
var range = ranges[i];
|
||||||
|
var coverRange = range;
|
||||||
|
|
||||||
|
// Add number of covered columns and then subtract common ones
|
||||||
|
for (int j = i + 1; j < ranges.Count; j++)
|
||||||
|
{
|
||||||
|
var exclude = ranges[j];
|
||||||
|
|
||||||
|
coverRange -= exclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCovered += coverRange.Covered;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove lines which contains a beacon
|
||||||
|
totalCovered -= beaconsOnTargetY.Count;
|
||||||
|
|
||||||
|
// Print total covered columns on line Y
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Number of positions that cannot contain a beacon: [yellow]{totalCovered}[/][/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RunPart2(bool display = true)
|
||||||
|
{
|
||||||
|
const int xMin = 0;
|
||||||
|
const int xMax = 4_000_000;
|
||||||
|
const int yMin = 0;
|
||||||
|
const int yMax = 4_000_000;
|
||||||
|
|
||||||
|
bool IsOutbound(Point point) => point.X is < xMin or > xMax || point.Y is < yMin or > yMax;
|
||||||
|
|
||||||
|
// Parse pairs
|
||||||
|
var pairs = ParsePairs();
|
||||||
|
|
||||||
|
// Find all points that are just outside a sensor range
|
||||||
|
var possiblePoints = new ConcurrentBag<Point>();
|
||||||
|
|
||||||
|
Parallel.For(0, pairs.Count, i =>
|
||||||
|
{
|
||||||
|
var pair = pairs[i];
|
||||||
|
|
||||||
|
var sensor = pair.SensorPosition;
|
||||||
|
var distance = pair.SensorRange + 1;
|
||||||
|
|
||||||
|
for (int x = -distance; x <= distance; x++)
|
||||||
|
{
|
||||||
|
var y = distance - Math.Abs(x);
|
||||||
|
var positivePoint = new Point(sensor.X + x, sensor.Y + y);
|
||||||
|
var negativePoint = new Point(sensor.X + x, sensor.Y - y);
|
||||||
|
|
||||||
|
// If both points are outbound, just skip
|
||||||
|
var positiveIsOutbound = IsOutbound(positivePoint);
|
||||||
|
var negativeIsOutbound = IsOutbound(negativePoint);
|
||||||
|
|
||||||
|
if (positiveIsOutbound && negativeIsOutbound)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this point is just outside at least one other sensor range
|
||||||
|
for (int otherIndex = 0; otherIndex < pairs.Count; otherIndex++)
|
||||||
|
{
|
||||||
|
if (otherIndex == i)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var otherPair = pairs[otherIndex];
|
||||||
|
|
||||||
|
var otherSensor = otherPair.SensorPosition;
|
||||||
|
var otherDistance = otherPair.SensorRange + 1;
|
||||||
|
|
||||||
|
if (!positiveIsOutbound)
|
||||||
|
{
|
||||||
|
var distancePositive = Math.Abs(positivePoint.X - otherSensor.X) +
|
||||||
|
Math.Abs(positivePoint.Y - otherSensor.Y);
|
||||||
|
|
||||||
|
if (distancePositive == otherDistance)
|
||||||
|
{
|
||||||
|
possiblePoints.Add(positivePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!negativeIsOutbound)
|
||||||
|
{
|
||||||
|
var distanceNegative = Math.Abs(negativePoint.X - negativePoint.X) +
|
||||||
|
Math.Abs(negativePoint.Y - negativePoint.Y);
|
||||||
|
|
||||||
|
if (distanceNegative == otherDistance)
|
||||||
|
{
|
||||||
|
possiblePoints.Add(negativePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep the only outside detection point
|
||||||
|
var finalPoint = possiblePoints.First(f =>
|
||||||
|
pairs.All(p => Math.Abs(f.X - p.SensorPosition.X) + Math.Abs(f.Y - p.SensorPosition.Y) > p.SensorRange));
|
||||||
|
|
||||||
|
var tuningFrequency = finalPoint.X * (long) 4_000_000 + finalPoint.Y;
|
||||||
|
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Tuning frequency: [yellow]{tuningFrequency}[/][/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IList<SensorBeaconPair> ParsePairs()
|
||||||
|
{
|
||||||
|
var pairs = new List<SensorBeaconPair>();
|
||||||
|
|
||||||
|
foreach (var line in Input.ReadAllLines())
|
||||||
|
{
|
||||||
|
var span = line.AsSpan();
|
||||||
|
|
||||||
|
// Parse sensor position
|
||||||
|
int sensorXStart = span.IndexOf('=') + 1;
|
||||||
|
int sensorXEnd = span.IndexOf(',');
|
||||||
|
|
||||||
|
var sensorX = int.Parse(span[sensorXStart..sensorXEnd]);
|
||||||
|
span = span[sensorXEnd..];
|
||||||
|
|
||||||
|
int sensorYStart = span.IndexOf('=') + 1;
|
||||||
|
int sensorYEnd = span.IndexOf(':');
|
||||||
|
|
||||||
|
var sensorY = int.Parse(span[sensorYStart..sensorYEnd]);
|
||||||
|
span = span[sensorYEnd..];
|
||||||
|
|
||||||
|
// Parse beacon
|
||||||
|
int beaconXStart = span.IndexOf('=') + 1;
|
||||||
|
int beaconXEnd = span.IndexOf(',');
|
||||||
|
|
||||||
|
var beaconX = int.Parse(span[beaconXStart..beaconXEnd]);
|
||||||
|
span = span[beaconXEnd..];
|
||||||
|
|
||||||
|
int beaconYStart = span.IndexOf('=') + 1;
|
||||||
|
|
||||||
|
var beaconY = int.Parse(span[beaconYStart..]);
|
||||||
|
|
||||||
|
pairs.Add(new SensorBeaconPair(new Point(sensorX, sensorY), new Point(beaconX, beaconY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Input
|
||||||
|
|
||||||
|
public const string Input =
|
||||||
|
"""
|
||||||
|
Sensor at x=1384790, y=3850432: closest beacon is at x=2674241, y=4192888
|
||||||
|
Sensor at x=2825953, y=288046: closest beacon is at x=2154954, y=-342775
|
||||||
|
Sensor at x=3553843, y=2822363: closest beacon is at x=3444765, y=2347460
|
||||||
|
Sensor at x=2495377, y=3130491: closest beacon is at x=2761496, y=2831113
|
||||||
|
Sensor at x=1329263, y=1778185: closest beacon is at x=2729595, y=2000000
|
||||||
|
Sensor at x=2882039, y=2206085: closest beacon is at x=2729595, y=2000000
|
||||||
|
Sensor at x=3903141, y=2510440: closest beacon is at x=4006219, y=3011198
|
||||||
|
Sensor at x=3403454, y=3996578: closest beacon is at x=3754119, y=4475047
|
||||||
|
Sensor at x=3630476, y=1048796: closest beacon is at x=3444765, y=2347460
|
||||||
|
Sensor at x=16252, y=2089672: closest beacon is at x=-276514, y=2995794
|
||||||
|
Sensor at x=428672, y=1150723: closest beacon is at x=-281319, y=668868
|
||||||
|
Sensor at x=2939101, y=3624676: closest beacon is at x=2674241, y=4192888
|
||||||
|
Sensor at x=3166958, y=2890076: closest beacon is at x=2761496, y=2831113
|
||||||
|
Sensor at x=3758241, y=3546895: closest beacon is at x=4006219, y=3011198
|
||||||
|
Sensor at x=218942, y=3011070: closest beacon is at x=-276514, y=2995794
|
||||||
|
Sensor at x=52656, y=3484635: closest beacon is at x=-276514, y=2995794
|
||||||
|
Sensor at x=2057106, y=405314: closest beacon is at x=2154954, y=-342775
|
||||||
|
Sensor at x=1966905, y=2495701: closest beacon is at x=2761496, y=2831113
|
||||||
|
Sensor at x=511976, y=2696731: closest beacon is at x=-276514, y=2995794
|
||||||
|
Sensor at x=3094465, y=2478570: closest beacon is at x=3444765, y=2347460
|
||||||
|
Sensor at x=806671, y=228252: closest beacon is at x=-281319, y=668868
|
||||||
|
Sensor at x=3011731, y=1976307: closest beacon is at x=2729595, y=2000000
|
||||||
|
""";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
219
Days/Day16.cs
Normal file
219
Days/Day16.cs
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace AdventOfCode.Days;
|
||||||
|
|
||||||
|
public class Valve
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public int Rate { get; }
|
||||||
|
public IList<Valve> AccessibleValves { get; }
|
||||||
|
|
||||||
|
public Valve(string name, int rate)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Rate = rate;
|
||||||
|
AccessibleValves = new List<Valve>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ValvePath(int CurrentMinute, int PressurePerMinute, int ReleasedPressure, Valve CurrentValve, HashSet<Valve> OpenedValves);
|
||||||
|
|
||||||
|
public class Day16 : Day
|
||||||
|
{
|
||||||
|
public override int Number => 16;
|
||||||
|
public override string Name => "Proboscidea Volcanium";
|
||||||
|
public override void RunPart1(bool display = true)
|
||||||
|
{
|
||||||
|
var startValve = ParseValves();
|
||||||
|
|
||||||
|
// Test all possibles paths
|
||||||
|
int maxPressure = 0;
|
||||||
|
var paths = new Queue<ValvePath>();
|
||||||
|
paths.Enqueue(new ValvePath(1, 0, 0, startValve, new HashSet<Valve>()));
|
||||||
|
|
||||||
|
// Remember best pressure at each valve
|
||||||
|
var valvePotential = new Dictionary<Valve, (int currentMinute, int potential)>();
|
||||||
|
|
||||||
|
while (paths.Count > 0)
|
||||||
|
{
|
||||||
|
var state = paths.Dequeue();
|
||||||
|
|
||||||
|
// Check if this state is worse than last one at this same valve
|
||||||
|
int potential = state.ReleasedPressure + (30 - state.CurrentMinute + 1) * state.PressurePerMinute;
|
||||||
|
if (valvePotential.TryGetValue(state.CurrentValve, out var lastState))
|
||||||
|
{
|
||||||
|
if (state.CurrentMinute >= lastState.currentMinute)
|
||||||
|
{
|
||||||
|
if (potential <= lastState.potential)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valvePotential[state.CurrentValve] = (state.CurrentMinute, potential);
|
||||||
|
|
||||||
|
// Release pressure at start of minute
|
||||||
|
var newPressure = state.ReleasedPressure + state.PressurePerMinute;
|
||||||
|
|
||||||
|
// Compute new max
|
||||||
|
if (newPressure > maxPressure)
|
||||||
|
{
|
||||||
|
maxPressure = newPressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop at minute 30
|
||||||
|
if (state.CurrentMinute == 30)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the valve can be opened
|
||||||
|
if (!state.OpenedValves.Contains(state.CurrentValve))
|
||||||
|
{
|
||||||
|
// New state with current valve opened
|
||||||
|
var openedValves = new HashSet<Valve>(state.OpenedValves);
|
||||||
|
openedValves.Add(state.CurrentValve);
|
||||||
|
|
||||||
|
paths.Enqueue(new ValvePath(state.CurrentMinute + 1, state.PressurePerMinute + state.CurrentValve.Rate, newPressure, state.CurrentValve, openedValves));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to all accessible valves
|
||||||
|
foreach (var accessibleValve in state.CurrentValve.AccessibleValves)
|
||||||
|
{
|
||||||
|
paths.Enqueue(new ValvePath(state.CurrentMinute + 1, state.PressurePerMinute, newPressure, accessibleValve, state.OpenedValves));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Max pressure released: [yellow]{maxPressure}[/][/]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RunPart2(bool display = true)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Valve ParseValves()
|
||||||
|
{
|
||||||
|
var valves = new Dictionary<string, Valve>();
|
||||||
|
|
||||||
|
// Create valves first
|
||||||
|
foreach (var line in Input.ReadAllLines())
|
||||||
|
{
|
||||||
|
var span = line.AsSpan();
|
||||||
|
|
||||||
|
var nameStart = span.IndexOf(' ') + 1;
|
||||||
|
var name = span[nameStart..(nameStart + 2)].ToString();
|
||||||
|
|
||||||
|
var rateStart = span.IndexOf('=') + 1;
|
||||||
|
var rateEnd = span.IndexOf(';');
|
||||||
|
|
||||||
|
var rate = int.Parse(span[rateStart..rateEnd]);
|
||||||
|
|
||||||
|
valves.Add(name, new Valve(name, rate));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add links
|
||||||
|
// Create valves first
|
||||||
|
foreach (var line in Input.ReadAllLines())
|
||||||
|
{
|
||||||
|
var span = line.AsSpan();
|
||||||
|
|
||||||
|
var nameStart = span.IndexOf(' ') + 1;
|
||||||
|
var name = span[nameStart..(nameStart + 2)].ToString();
|
||||||
|
|
||||||
|
var valve = valves[name];
|
||||||
|
|
||||||
|
var valvesStart = span.IndexOf(',') != -1 ? span.IndexOf(',') - 2 : span.Length - 2;
|
||||||
|
var valvesToAdd = span[valvesStart..].ToString().Split(", ").Select(v => valves[v]);
|
||||||
|
|
||||||
|
foreach (var valveToAdd in valvesToAdd)
|
||||||
|
{
|
||||||
|
valve.AccessibleValves.Add(valveToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valves["AA"];
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Input
|
||||||
|
|
||||||
|
public const string ExampleInput =
|
||||||
|
"""
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||||
|
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||||
|
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||||
|
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||||
|
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||||
|
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||||
|
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||||
|
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||||
|
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||||
|
Valve JJ has flow rate=21; tunnel leads to valve II
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string Input =
|
||||||
|
"""
|
||||||
|
Valve JI has flow rate=21; tunnels lead to valves WI, XG
|
||||||
|
Valve DM has flow rate=3; tunnels lead to valves JX, NG, AW, BY, PF
|
||||||
|
Valve AZ has flow rate=0; tunnels lead to valves FJ, VC
|
||||||
|
Valve YQ has flow rate=0; tunnels lead to valves TE, OP
|
||||||
|
Valve WI has flow rate=0; tunnels lead to valves JI, VC
|
||||||
|
Valve NE has flow rate=0; tunnels lead to valves ZK, AA
|
||||||
|
Valve FM has flow rate=0; tunnels lead to valves LC, DU
|
||||||
|
Valve QI has flow rate=0; tunnels lead to valves TE, JW
|
||||||
|
Valve OY has flow rate=0; tunnels lead to valves XS, VF
|
||||||
|
Valve XS has flow rate=18; tunnels lead to valves RR, OY, SV, NQ
|
||||||
|
Valve NU has flow rate=0; tunnels lead to valves IZ, BD
|
||||||
|
Valve JX has flow rate=0; tunnels lead to valves DM, ZK
|
||||||
|
Valve WT has flow rate=23; tunnels lead to valves OV, QJ
|
||||||
|
Valve KM has flow rate=0; tunnels lead to valves TE, OL
|
||||||
|
Valve NG has flow rate=0; tunnels lead to valves II, DM
|
||||||
|
Valve FJ has flow rate=0; tunnels lead to valves AZ, II
|
||||||
|
Valve QR has flow rate=0; tunnels lead to valves ZK, KI
|
||||||
|
Valve KI has flow rate=9; tunnels lead to valves ZZ, DI, TL, AJ, QR
|
||||||
|
Valve ON has flow rate=0; tunnels lead to valves LC, QT
|
||||||
|
Valve AW has flow rate=0; tunnels lead to valves DM, AA
|
||||||
|
Valve HI has flow rate=0; tunnels lead to valves TE, VC
|
||||||
|
Valve XG has flow rate=0; tunnels lead to valves II, JI
|
||||||
|
Valve II has flow rate=19; tunnels lead to valves LF, NG, OL, FJ, XG
|
||||||
|
Valve VC has flow rate=24; tunnels lead to valves WI, HI, AZ
|
||||||
|
Valve VJ has flow rate=0; tunnels lead to valves UG, AA
|
||||||
|
Valve IZ has flow rate=0; tunnels lead to valves VF, NU
|
||||||
|
Valve EJ has flow rate=0; tunnels lead to valves ZK, LC
|
||||||
|
Valve DU has flow rate=12; tunnels lead to valves TC, UG, FM
|
||||||
|
Valve ZK has flow rate=10; tunnels lead to valves JX, EJ, JW, QR, NE
|
||||||
|
Valve XF has flow rate=25; tunnels lead to valves OP, VT
|
||||||
|
Valve LC has flow rate=4; tunnels lead to valves FM, EJ, ON, AJ, PF
|
||||||
|
Valve SV has flow rate=0; tunnels lead to valves XS, IY
|
||||||
|
Valve LF has flow rate=0; tunnels lead to valves II, OV
|
||||||
|
Valve DI has flow rate=0; tunnels lead to valves KI, BY
|
||||||
|
Valve OP has flow rate=0; tunnels lead to valves YQ, XF
|
||||||
|
Valve NQ has flow rate=0; tunnels lead to valves TC, XS
|
||||||
|
Valve QJ has flow rate=0; tunnels lead to valves VT, WT
|
||||||
|
Valve IY has flow rate=22; tunnel leads to valve SV
|
||||||
|
Valve AJ has flow rate=0; tunnels lead to valves LC, KI
|
||||||
|
Valve TE has flow rate=11; tunnels lead to valves QI, HI, KM, YQ
|
||||||
|
Valve ZZ has flow rate=0; tunnels lead to valves KI, AA
|
||||||
|
Valve VT has flow rate=0; tunnels lead to valves XF, QJ
|
||||||
|
Valve OL has flow rate=0; tunnels lead to valves KM, II
|
||||||
|
Valve TC has flow rate=0; tunnels lead to valves NQ, DU
|
||||||
|
Valve TL has flow rate=0; tunnels lead to valves VF, KI
|
||||||
|
Valve QT has flow rate=0; tunnels lead to valves AA, ON
|
||||||
|
Valve BY has flow rate=0; tunnels lead to valves DM, DI
|
||||||
|
Valve OV has flow rate=0; tunnels lead to valves LF, WT
|
||||||
|
Valve VN has flow rate=0; tunnels lead to valves RR, BD
|
||||||
|
Valve VF has flow rate=13; tunnels lead to valves OY, IZ, TL
|
||||||
|
Valve BD has flow rate=17; tunnels lead to valves NU, VN
|
||||||
|
Valve UG has flow rate=0; tunnels lead to valves VJ, DU
|
||||||
|
Valve PF has flow rate=0; tunnels lead to valves LC, DM
|
||||||
|
Valve RR has flow rate=0; tunnels lead to valves XS, VN
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves QT, ZZ, AW, VJ, NE
|
||||||
|
Valve JW has flow rate=0; tunnels lead to valves ZK, QI
|
||||||
|
""";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
30
Days/Day2.cs
30
Days/Day2.cs
@@ -18,10 +18,10 @@ public enum Outcome : long
|
|||||||
|
|
||||||
public class Day2 : Day
|
public class Day2 : Day
|
||||||
{
|
{
|
||||||
public override int Number { get; } = 2;
|
public override int Number => 2;
|
||||||
public override string Name { get; } = "Rock Paper Scissors";
|
public override string Name => "Rock Paper Scissors";
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
long score = 0;
|
long score = 0;
|
||||||
|
|
||||||
@@ -33,14 +33,17 @@ public class Day2 : Day
|
|||||||
score += (long) selfChoice;
|
score += (long) selfChoice;
|
||||||
score += (long) ComputeOutcome(adversaryChoice, selfChoice);
|
score += (long) ComputeOutcome(adversaryChoice, selfChoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total score: [yellow]{score}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Total score: [yellow]{score}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
long score = 0;
|
long score = 0;
|
||||||
|
|
||||||
foreach (var line in Input.ReadAllLines())
|
foreach (var line in Input.ReadAllLines())
|
||||||
{
|
{
|
||||||
var adversaryChoice = AdversaryInputToChoice(line[0]);
|
var adversaryChoice = AdversaryInputToChoice(line[0]);
|
||||||
@@ -50,8 +53,11 @@ public class Day2 : Day
|
|||||||
score += (long) selfChoice;
|
score += (long) selfChoice;
|
||||||
score += (long) desiredOutcome;
|
score += (long) desiredOutcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total score: [yellow]{score}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Total score: [yellow]{score}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Outcome ComputeOutcome(Choice adversary, Choice self) => (adversary, self) switch
|
private Outcome ComputeOutcome(Choice adversary, Choice self) => (adversary, self) switch
|
||||||
@@ -83,7 +89,7 @@ public class Day2 : Day
|
|||||||
'C' => Choice.Scissors,
|
'C' => Choice.Scissors,
|
||||||
_ => throw new ArgumentException("Invalid input")
|
_ => throw new ArgumentException("Invalid input")
|
||||||
};
|
};
|
||||||
|
|
||||||
private Choice SelfInputToChoice(char input) => input switch
|
private Choice SelfInputToChoice(char input) => input switch
|
||||||
{
|
{
|
||||||
'X' => Choice.Rock,
|
'X' => Choice.Rock,
|
||||||
|
|||||||
16
Days/Day3.cs
16
Days/Day3.cs
@@ -7,7 +7,7 @@ public class Day3 : Day
|
|||||||
public override int Number => 3;
|
public override int Number => 3;
|
||||||
public override string Name => "Rucksack Reorganization";
|
public override string Name => "Rucksack Reorganization";
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
long sum = 0;
|
long sum = 0;
|
||||||
|
|
||||||
@@ -22,10 +22,13 @@ public class Day3 : Day
|
|||||||
sum += CharToPriority(common);
|
sum += CharToPriority(common);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Sum of priorities is: [yellow]{sum}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Sum of priorities is: [yellow]{sum}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
long sum = 0;
|
long sum = 0;
|
||||||
|
|
||||||
@@ -40,10 +43,13 @@ public class Day3 : Day
|
|||||||
sum += CharToPriority(common);
|
sum += CharToPriority(common);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Sum of priorities is: [yellow]{sum}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Sum of priorities is: [yellow]{sum}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CharToPriority(char c)
|
private static int CharToPriority(char c)
|
||||||
{
|
{
|
||||||
if (char.IsLower(c))
|
if (char.IsLower(c))
|
||||||
{
|
{
|
||||||
|
|||||||
22
Days/Day4.cs
22
Days/Day4.cs
@@ -6,7 +6,7 @@ public class Day4 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 4;
|
public override int Number => 4;
|
||||||
public override string Name => "Camp Cleanup";
|
public override string Name => "Camp Cleanup";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
int overlaps = 0;
|
int overlaps = 0;
|
||||||
foreach (var line in Input.ReadAllLines())
|
foreach (var line in Input.ReadAllLines())
|
||||||
@@ -18,7 +18,7 @@ public class Day4 : Day
|
|||||||
|
|
||||||
var firstSection = sections[0];
|
var firstSection = sections[0];
|
||||||
var secondSection = sections[1];
|
var secondSection = sections[1];
|
||||||
|
|
||||||
// Check if first section contains second section
|
// Check if first section contains second section
|
||||||
if (firstSection.Start <= secondSection.Start && firstSection.End >= secondSection.End)
|
if (firstSection.Start <= secondSection.Start && firstSection.End >= secondSection.End)
|
||||||
{
|
{
|
||||||
@@ -30,11 +30,14 @@ public class Day4 : Day
|
|||||||
overlaps++;
|
overlaps++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Overlapping sections: [yellow]{overlaps}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Overlapping sections: [yellow]{overlaps}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
int overlaps = 0;
|
int overlaps = 0;
|
||||||
foreach (var line in Input.ReadAllLines())
|
foreach (var line in Input.ReadAllLines())
|
||||||
@@ -46,15 +49,18 @@ public class Day4 : Day
|
|||||||
|
|
||||||
var firstSection = sections[0];
|
var firstSection = sections[0];
|
||||||
var secondSection = sections[1];
|
var secondSection = sections[1];
|
||||||
|
|
||||||
// Check if first section overlaps second
|
// Check if first section overlaps second
|
||||||
if (firstSection.Start <= secondSection.End && firstSection.End >= secondSection.Start)
|
if (firstSection.Start <= secondSection.End && firstSection.End >= secondSection.Start)
|
||||||
{
|
{
|
||||||
overlaps++;
|
overlaps++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Overlapping sections: [yellow]{overlaps}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Overlapping sections: [yellow]{overlaps}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Input
|
#region Input
|
||||||
|
|||||||
22
Days/Day5.cs
22
Days/Day5.cs
@@ -9,7 +9,7 @@ public class Day5 : Day
|
|||||||
|
|
||||||
private IDictionary<int, Stack<char>>? _stacks;
|
private IDictionary<int, Stack<char>>? _stacks;
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
_stacks = InitStacks();
|
_stacks = InitStacks();
|
||||||
|
|
||||||
@@ -26,14 +26,17 @@ public class Day5 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 9; i++)
|
if (display)
|
||||||
{
|
{
|
||||||
AnsiConsole.Markup($"[{(i % 2 == 0 ? "yellow" : "green")}]{_stacks[i].Pop()}[/]");
|
for (int i = 1; i <= 9; i++)
|
||||||
|
{
|
||||||
|
AnsiConsole.Markup($"[{(i % 2 == 0 ? "yellow" : "green")}]{_stacks[i].Pop()}[/]");
|
||||||
|
}
|
||||||
|
AnsiConsole.WriteLine();
|
||||||
}
|
}
|
||||||
AnsiConsole.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
_stacks = InitStacks();
|
_stacks = InitStacks();
|
||||||
|
|
||||||
@@ -53,11 +56,14 @@ public class Day5 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 9; i++)
|
if (display)
|
||||||
{
|
{
|
||||||
AnsiConsole.Markup($"[{(i % 2 == 0 ? "yellow" : "green")}]{_stacks[i].Pop()}[/]");
|
for (int i = 1; i <= 9; i++)
|
||||||
|
{
|
||||||
|
AnsiConsole.Markup($"[{(i % 2 == 0 ? "yellow" : "green")}]{_stacks[i].Pop()}[/]");
|
||||||
|
}
|
||||||
|
AnsiConsole.WriteLine();
|
||||||
}
|
}
|
||||||
AnsiConsole.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Input
|
#region Input
|
||||||
|
|||||||
16
Days/Day6.cs
16
Days/Day6.cs
@@ -6,7 +6,7 @@ public class Day6 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 6;
|
public override int Number => 6;
|
||||||
public override string Name => "Tuning Trouble";
|
public override string Name => "Tuning Trouble";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
int position = 0;
|
int position = 0;
|
||||||
|
|
||||||
@@ -30,10 +30,13 @@ public class Day6 : Day
|
|||||||
charStream.Dequeue();
|
charStream.Dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Position of start-of-packet marker is: [yellow]{position}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Position of start-of-packet marker is: [yellow]{position}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
const int length = 14;
|
const int length = 14;
|
||||||
int position = 0;
|
int position = 0;
|
||||||
@@ -48,7 +51,7 @@ public class Day6 : Day
|
|||||||
for (int i = length - 1; i < Input.Length; i++)
|
for (int i = length - 1; i < Input.Length; i++)
|
||||||
{
|
{
|
||||||
charStream.Enqueue(Input[i]);
|
charStream.Enqueue(Input[i]);
|
||||||
|
|
||||||
// Check if all 14 chars are different
|
// Check if all 14 chars are different
|
||||||
if (charStream.ToHashSet().Count == charStream.Count)
|
if (charStream.ToHashSet().Count == charStream.Count)
|
||||||
{
|
{
|
||||||
@@ -59,7 +62,10 @@ public class Day6 : Day
|
|||||||
charStream.Dequeue();
|
charStream.Dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Position of start-of-message marker is: [yellow]{position}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Position of start-of-message marker is: [yellow]{position}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Input
|
#region Input
|
||||||
|
|||||||
14
Days/Day7.cs
14
Days/Day7.cs
@@ -32,7 +32,7 @@ public class Day7 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 7;
|
public override int Number => 7;
|
||||||
public override string Name => "No Space Left On Device";
|
public override string Name => "No Space Left On Device";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
var fileSystem = ParseFileSystem();
|
var fileSystem = ParseFileSystem();
|
||||||
|
|
||||||
@@ -42,10 +42,13 @@ public class Day7 : Day
|
|||||||
.Where(d => d.Size < 100_000)
|
.Where(d => d.Size < 100_000)
|
||||||
.Sum(d => d.Size);
|
.Sum(d => d.Size);
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total size: [yellow]{totalSize}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Total size: [yellow]{totalSize}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
const long fileSystemSpace = 70_000_000;
|
const long fileSystemSpace = 70_000_000;
|
||||||
const long requiredSpace = 30_000_000;
|
const long requiredSpace = 30_000_000;
|
||||||
@@ -63,7 +66,10 @@ public class Day7 : Day
|
|||||||
.Where(d => d.Size > missingSpace)
|
.Where(d => d.Size > missingSpace)
|
||||||
.MinBy(d => d.Size);
|
.MinBy(d => d.Size);
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Directory to remove size: [yellow]{directoryToRemove!.Size}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Directory to remove size: [yellow]{directoryToRemove!.Size}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DirectoryEntry ParseFileSystem()
|
private static DirectoryEntry ParseFileSystem()
|
||||||
|
|||||||
15
Days/Day8.cs
15
Days/Day8.cs
@@ -6,7 +6,7 @@ public class Day8 : Day
|
|||||||
{
|
{
|
||||||
public override int Number => 8;
|
public override int Number => 8;
|
||||||
public override string Name => "Treetop Tree House";
|
public override string Name => "Treetop Tree House";
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
var grid = CreateGrid();
|
var grid = CreateGrid();
|
||||||
|
|
||||||
@@ -92,10 +92,14 @@ public class Day8 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Total viewable trees: [yellow]{valid.Count}[/][/]");
|
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Total viewable trees: [yellow]{valid.Count}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
var grid = CreateGrid();
|
var grid = CreateGrid();
|
||||||
|
|
||||||
@@ -116,7 +120,10 @@ public class Day8 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]Max scenic score: [yellow]{maxScenicScore}[/][/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]Max scenic score: [yellow]{maxScenicScore}[/][/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ComputeScenicScore(int[,] grid, int i, int j, int size)
|
private int ComputeScenicScore(int[,] grid, int i, int j, int size)
|
||||||
|
|||||||
14
Days/Day9.cs
14
Days/Day9.cs
@@ -7,7 +7,7 @@ public class Day9 : Day
|
|||||||
public override int Number => 9;
|
public override int Number => 9;
|
||||||
public override string Name => "Rope Bridge";
|
public override string Name => "Rope Bridge";
|
||||||
|
|
||||||
public override void RunPart1()
|
public override void RunPart1(bool display = true)
|
||||||
{
|
{
|
||||||
// Start
|
// Start
|
||||||
(int x, int y) start = (0, 0);
|
(int x, int y) start = (0, 0);
|
||||||
@@ -49,10 +49,13 @@ public class Day9 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]The tail visited [yellow]{tailVisitedPositions.Count}[/] unique positions[/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]The tail visited [yellow]{tailVisitedPositions.Count}[/] unique positions[/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RunPart2()
|
public override void RunPart2(bool display = true)
|
||||||
{
|
{
|
||||||
const int tailSegments = 9;
|
const int tailSegments = 9;
|
||||||
|
|
||||||
@@ -130,7 +133,10 @@ public class Day9 : Day
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[green]The tail visited [yellow]{tailVisitedPositions.Count}[/] unique positions[/]");
|
if (display)
|
||||||
|
{
|
||||||
|
AnsiConsole.MarkupLine($"[green]The tail visited [yellow]{tailVisitedPositions.Count}[/] unique positions[/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Input
|
#region Input
|
||||||
|
|||||||
24
Program.cs
24
Program.cs
@@ -1,8 +1,18 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using AdventOfCode;
|
||||||
using AdventOfCode.Days;
|
using AdventOfCode.Days;
|
||||||
|
using BenchmarkDotNet.Running;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
|
// Benchmark
|
||||||
|
if (args is ["--bench" or "-b"])
|
||||||
|
{
|
||||||
|
BenchmarkRunner.Run<DayBenchmark>();
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal run
|
||||||
var days = Assembly.GetAssembly(typeof(Day))!.GetTypes()
|
var days = Assembly.GetAssembly(typeof(Day))!.GetTypes()
|
||||||
.Where(t => t.IsAssignableTo(typeof(Day)) && t.GetConstructor(Type.EmptyTypes) != null && !t.IsAbstract)
|
.Where(t => t.IsAssignableTo(typeof(Day)) && t.GetConstructor(Type.EmptyTypes) != null && !t.IsAbstract)
|
||||||
.Select(t => (Day)Activator.CreateInstance(t)!);
|
.Select(t => (Day)Activator.CreateInstance(t)!);
|
||||||
@@ -13,23 +23,35 @@ var select = new SelectionPrompt<Day>()
|
|||||||
|
|
||||||
var selectedDay = AnsiConsole.Prompt(select);
|
var selectedDay = AnsiConsole.Prompt(select);
|
||||||
|
|
||||||
|
var stopWatch = new Stopwatch();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine($"[cyan]Running [yellow]{selectedDay}[/]...[/]\n");
|
AnsiConsole.MarkupLine($"[cyan]Running [yellow]{selectedDay}[/]...[/]\n");
|
||||||
|
|
||||||
AnsiConsole.MarkupLine("[cyan]Part [yellow]1[/] result:[/]");
|
AnsiConsole.MarkupLine("[cyan]Part [yellow]1[/] result:[/]");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
stopWatch.Start();
|
||||||
selectedDay.RunPart1();
|
selectedDay.RunPart1();
|
||||||
|
stopWatch.Stop();
|
||||||
|
|
||||||
|
AnsiConsole.MarkupLine($"[red]Approximate run time: [yellow]{stopWatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000:F3} ms[/][/]");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
AnsiConsole.WriteException(e);
|
AnsiConsole.WriteException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopWatch.Reset();
|
||||||
|
|
||||||
AnsiConsole.MarkupLine("\n[cyan]Part [yellow]2[/] result:[/]");
|
AnsiConsole.MarkupLine("\n[cyan]Part [yellow]2[/] result:[/]");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
stopWatch.Start();
|
||||||
selectedDay.RunPart2();
|
selectedDay.RunPart2();
|
||||||
|
stopWatch.Stop();
|
||||||
|
|
||||||
|
AnsiConsole.MarkupLine($"[red]Approximate run time: [yellow]{stopWatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000:F3} ms[/][/]");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user