using System; using System.Collections.Generic; using System.Data.Common; using System.IO; using System.Linq; using AdvenOfCode.Contracts; using Coordinate = (int x, int y, int z); namespace AoC_2025; public class Day08 { private Coordinate[] ParsePuzzleInput(string path) { var puzzleInput = File.ReadAllLines(path) .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => line.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(str => int.Parse(str)).ToArray()) .Select(numbers => (numbers[0], numbers[1], numbers[2])) .ToArray(); return puzzleInput; } public long SolvePart1(string pathToPuzzleInput, int amountToConnect) { var points = ParsePuzzleInput(pathToPuzzleInput); Dictionary> connected = points.ToDictionary(p => p, p => new HashSet()); var pointsWithClosest = points.Select(point => { var closest = GetClosestPoint(point, points, connected); return (point, closest: closest.point, closest.distance); }) .OrderBy(x => x.distance) .ToArray(); List> circuits = []; for (var i = 0; i < amountToConnect; i++) { var next = pointsWithClosest[0]; _ = AddToCircuits(next.point, next.closest, circuits); connected[next.point].Add(next.closest); connected[next.closest].Add(next.point); pointsWithClosest = points.Select(point => { var closest = GetClosestPoint(point, points, connected); return (point, closest: closest.point, closest.distance); }) .OrderBy(x => x.distance) .ToArray(); } return circuits .Select(circuit => circuit.Count) .OrderDescending() .Take(3) .Aggregate((acc, next) => acc * next); } public long SolvePart2(string pathToPuzzleInput) { var points = ParsePuzzleInput(pathToPuzzleInput); Dictionary> connected = points.ToDictionary(p => p, p => new HashSet()); var pointsWithClosest = points.Select(point => { var closest = GetClosestPoint(point, points, connected); return (point, closest: closest.point, closest.distance); }) .OrderBy(x => x.distance) .ToArray(); List> circuits = points.Select(p => new List() { p }).ToList(); (Coordinate a, Coordinate b) lastConnected = ((0, 0, 0), (0, 0, 0)); while(circuits.Count > 1) { var next = pointsWithClosest[0]; _ = AddToCircuits(next.point, next.closest, circuits); connected[next.point].Add(next.closest); connected[next.closest].Add(next.point); lastConnected = (next.point, next.closest); pointsWithClosest = points.Select(point => { var closest = GetClosestPoint(point, points, connected); return (point, closest: closest.point, closest.distance); }) .OrderBy(x => x.distance) .ToArray(); } return lastConnected.a.x * lastConnected.b.x; } private (Coordinate point, double distance) GetClosestPoint(Coordinate a, Coordinate[] points, Dictionary> connections) { var minDistance = double.MaxValue; var minIndex = -1; for (var i = 0; i < points.Length; i++) { if(a == points[i]) continue; if(connections[a].Contains(points[i])) continue; var distance = GetDistance(a, points[i]); if (minDistance > distance) { minIndex = i; minDistance = GetDistance(a, points[i]); } } return (points[minIndex], minDistance); } private double GetDistance(Coordinate a, Coordinate b) { return Math.Sqrt(Math.Pow(a.x - b.x, 2) + Math.Pow(a.y - b.y, 2) + Math.Pow(a.z - b.z, 2)); } private int AddToCircuits(Coordinate a, Coordinate b, List> circuits) { var circuitToAddBTo = circuits.FirstOrDefault(circuit => circuit.Contains(a)); var circuitToAddATo = circuits.FirstOrDefault(circuit => circuit.Contains(b)); if (circuitToAddATo == null && circuitToAddBTo == null) { circuits.Add([a, b]); return 2; } if (circuitToAddATo == circuitToAddBTo) { return 0; } if (circuitToAddATo != null && circuitToAddBTo != null) { circuits.Remove(circuitToAddATo); circuits.Remove(circuitToAddBTo); circuits.Add([..circuitToAddATo, ..circuitToAddBTo]); return 0; } if (circuitToAddATo != null) { circuitToAddATo.Add(a); } else { circuitToAddBTo.Add(b); } return 1; } private IEnumerable<(Coordinate pointA, Coordinate pointB, double distance)> GetAllDistances(Coordinate[] coordinates) { var combinations = coordinates .SelectMany((coord, ix) => coordinates.Skip(ix + 1).Select(coordB => (coord, coordB, distance: GetDistance(coord, coordB)))) .OrderBy(x => x.distance) .ToArray(); return combinations; } }