using System.Collections.Frozen; using System.Numerics; using Spectre.Console; namespace AdventOfCode.Days; public class Day8 : Day { public override int Number => 8; public override string Name => "Resonant Collinearity"; private const int GridSize = 50; public override void RunPart1(bool display = true) { HashSet antinodePositions = []; var frequencyAntennas = ParseAntennas(); // Find antinodes for each frequency foreach (var (_, antennas) in frequencyAntennas) { // Take antennas by pair to find antinodes foreach (var firstAntenna in antennas) { foreach (var secondAntenna in antennas.Where(a => a != firstAntenna)) { var firstAntinode = firstAntenna + (firstAntenna - secondAntenna); var secondAntinode = secondAntenna + (secondAntenna - firstAntenna); if (firstAntinode is { X: >= 0 and < GridSize, Y: >= 0 and < GridSize }) { antinodePositions.Add(firstAntinode); } if (secondAntinode is { X: >= 0 and < GridSize, Y: >= 0 and < GridSize }) { antinodePositions.Add(secondAntinode); } } } } if (display) { AnsiConsole.MarkupLine($"[green]Unique antinode positions count: [yellow]{antinodePositions.Count}[/][/]"); } } public override void RunPart2(bool display = true) { HashSet antinodePositions = []; var frequencyAntennas = ParseAntennas(); // Find antinodes for each frequency foreach (var (_, antennas) in frequencyAntennas) { // Take antennas by pair to find antinodes foreach (var firstAntenna in antennas) { foreach (var secondAntenna in antennas.Where(a => a != firstAntenna)) { // Always add antinodes on antennas if a pair is formed antinodePositions.Add(firstAntenna); antinodePositions.Add(secondAntenna); // Compute potential antinode positions var firstAntinodeOffset = firstAntenna - secondAntenna; var secondAntinodeOffset = secondAntenna - firstAntenna; for (var i = 1; ; i++) { var firstAntinode = firstAntenna + (i * firstAntinodeOffset); if (firstAntinode is { X: >= 0 and < GridSize, Y: >= 0 and < GridSize }) { antinodePositions.Add(firstAntinode); } else { break; } } for (var i = 1; ; i++) { var secondAntinode = secondAntenna + (i * secondAntinodeOffset); if (secondAntinode is { X: >= 0 and < GridSize, Y: >= 0 and < GridSize }) { antinodePositions.Add(secondAntinode); } else { break; } } } } } if (display) { AnsiConsole.MarkupLine($"[green]Unique antinode positions count: [yellow]{antinodePositions.Count}[/][/]"); } } private FrozenDictionary> ParseAntennas() { var antennas = new Dictionary>(); var y = 0; foreach (var line in Input.AsSpan().EnumerateLines()) { var x = 0; foreach (var frequency in line) { if (frequency is '.') { x++; continue; } if (!antennas.TryGetValue(frequency, out var list)) { list = []; antennas[frequency] = list; } list.Add(new Point(x, y)); x++; } y++; } return antennas.ToFrozenDictionary(); } private readonly record struct Point(int X, int Y) : IAdditionOperators, ISubtractionOperators, IMultiplyOperators { public static Point operator +(Point left, Point right) { return new Point(left.X + right.X, left.Y + right.Y); } public static Point operator -(Point left, Point right) { return new Point(left.X - right.X, left.Y - right.Y); } public static Point operator *(Point left, int right) { return new Point(left.X * right, left.Y * right); } public static Point operator *(int left, Point right) { return new Point(right.X * left, right.Y * left); } } }