using System.Buffers; using System.Numerics; using Spectre.Console; namespace AdventOfCode.Days; public class Day8 : Day { public override int Number => 8; public override string Name => "Playground"; public override void RunPart1(bool display = true) { var boxPositions = ParseBoxPositions(Input); var boxPairDistances = FetchOrderedDistances(boxPositions); var circuits = new List>(); var connectionsCount = 0; while (connectionsCount < 1000) { // Fetch next minimal distance pair. This is always the last pair in our ordered list var (pairLeftBox, pairRightBox, _) = boxPairDistances[^1]; boxPairDistances.RemoveAt(boxPairDistances.Count - 1); // Create a connection if those two boxes are not already connected if (!ConnectionExists(circuits, pairLeftBox, pairRightBox)) { // Connect the boxes, eventually merging circuits ConnectBoxes(circuits, pairLeftBox, pairRightBox); } connectionsCount++; } var result = circuits .OrderByDescending(circuit => circuit.Count) .Take(3) .Aggregate(1, (product, circuit) => product * circuit.Count); if (display) { AnsiConsole.MarkupLine($"[green]Result is: [yellow]{result}[/][/]"); } } public override void RunPart2(bool display = true) { var boxPositions = ParseBoxPositions(Input); var boxPairDistances = FetchOrderedDistances(boxPositions); var circuits = new List>(); long result; while (true) { // Fetch next minimal distance pair. This is always the last pair in our ordered list var (pairLeftBox, pairRightBox, _) = boxPairDistances[^1]; boxPairDistances.RemoveAt(boxPairDistances.Count - 1); // Create a connection if those two boxes are not already connected if (!ConnectionExists(circuits, pairLeftBox, pairRightBox)) { // Connect the boxes, eventually merging circuits ConnectBoxes(circuits, pairLeftBox, pairRightBox); } // Check if there is a circuit with all boxes connected if (circuits[0].Count >= 1000) { result = pairLeftBox.X * pairRightBox.X; break; } } if (display) { AnsiConsole.MarkupLine($"[green]Result is: [yellow]{result}[/][/]"); } } private static double BoxDistance(Box left, Box right) { return Math.Sqrt( (right.X - left.X) * (right.X - left.X) + (right.Y - left.Y) * (right.Y - left.Y) + (right.Z - left.Z) * (right.Z - left.Z) ); } static bool ConnectionExists(List> circuits, Box left, Box right) { foreach (var circuit in circuits) { if (circuit.Contains(left) && circuit.Contains(right)) { return true; } } return false; } static void ConnectBoxes(List> circuits, Box pairLeftBox, Box pairRightBox) { // Try to find circuit containing each box HashSet? leftCircuit = null; HashSet? rightCircuit = null; foreach (var circuit in circuits) { if (circuit.Contains(pairLeftBox)) { leftCircuit = circuit; } if (circuit.Contains(pairRightBox)) { rightCircuit = circuit; } } // None is in a circuit, create a new one if (leftCircuit is null && rightCircuit is null) { var circuit = new HashSet { pairLeftBox, pairRightBox }; circuits.Add(circuit); } // One of the two is null else if (leftCircuit is not null && rightCircuit is null) { leftCircuit.Add(pairRightBox); } else if (leftCircuit is null && rightCircuit is not null) { rightCircuit.Add(pairLeftBox); } // Both are already in a circuit, merge them else { foreach (var box in rightCircuit!) { leftCircuit!.Add(box); } circuits.Remove(rightCircuit); } } private static List ParseBoxPositions(string input) { var positions = new List(); foreach (var line in input.EnumerateLines()) { var split = line.Split(','); split.MoveNext(); var x = long.Parse(line[split.Current]); split.MoveNext(); var y = long.Parse(line[split.Current]); split.MoveNext(); var z = long.Parse(line[split.Current]); positions.Add(new Box(x, y, z)); } return positions; } private static List FetchOrderedDistances(List boxes) { var boxPairDistances = new List(); for (var i = 0; i < boxes.Count - 1; i++) { for (var j = i + 1; j < boxes.Count; j++) { var leftBox = boxes[i]; var rightBox = boxes[j]; var distance = BoxDistance(leftBox, rightBox); boxPairDistances.Add(new BoxPairDistance(leftBox, rightBox, distance)); } } // Sort in reverse order boxPairDistances.Sort((left, right) => right.CompareTo(left)); return boxPairDistances; } private record Box(long X, long Y, long Z); private record BoxPairDistance(Box Left, Box Right, double Distance) : IComparable { public int CompareTo(BoxPairDistance? other) { if (ReferenceEquals(this, other)) { return 0; } if (other is null) { return 1; } return Distance.CompareTo(other.Distance); } } }