Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Diagnostics;
- using System.Numerics;
- using System.Runtime.Serialization;
- using System.Security.Cryptography;
- using static System.Runtime.InteropServices.JavaScript.JSType;
- namespace Day8
- {
- internal class Program
- {
- private static List<List<Point>> circuitList = new();
- static void Main(string[] args)
- {
- const string input_filename = "day8_input.txt";
- Debug.Assert(File.Exists(input_filename));
- string[] input_lines = File.ReadAllLines(input_filename);
- Debug.Assert(input_lines.Length > 0);
- // convert the input lines into Points
- List<Point> points = new();
- bool part1 = false;
- foreach (string input in input_lines)
- {
- string[] coords = input.Split(',');
- Debug.Assert(coords.Length == 3);
- Debug.Assert(long.TryParse(coords[0], out long x));
- Debug.Assert(long.TryParse(coords[1], out long y));
- Debug.Assert(long.TryParse(coords[2], out long z));
- points.Add(new Point(x, y, z));
- }
- // Now that we have a list of the points, we need to find the shortest distance between them
- // To do this, we will need to loop through the list (not quite n^2) to do all of the comparisons
- // We will keep the comparisons in a sorted Dictionary with a reference to the points involved
- Dictionary<PointDistanceKey, long> distanceList = new();
- for (int i = 0; i < points.Count; i++)
- {
- for (int j = i + 1; j < points.Count; j++)
- {
- distanceList.Add(new PointDistanceKey(points[i], points[j]), points[i].DistanceSquared(points[j]));
- }
- }
- // Now sort the list
- var sortedDistanceList = distanceList.OrderBy(i => i.Key).ToDictionary();
- // Now that we have a sorted list of the distance between all of the points, we need to assemble
- // circuits of them.
- int count = 0;
- foreach (PointDistanceKey key in sortedDistanceList.Keys)
- {
- count++;
- List<Point>? p1_circuit = FindCircuitContainingPoint(key.P1);
- List<Point>? p2_circuit = FindCircuitContainingPoint(key.P2);
- // if neither point is in a circuit, then start a new one
- if (p1_circuit == null && p2_circuit == null)
- {
- circuitList.Add(new List<Point> { key.P1, key.P2 });
- }
- else if (p1_circuit == null && p2_circuit != null) // Add p1 to p2_circuit
- {
- p2_circuit.Add(key.P1);
- }
- else if (p1_circuit != null && p2_circuit == null) // Add p2 to p1_circuit
- {
- p1_circuit.Add(key.P2);
- }
- else if (p1_circuit != p2_circuit) // we know (p1_circuit != null && p2_circuit != null)
- {
- // we need to combine the circuits
- p1_circuit.AddRange(p2_circuit);
- circuitList.Remove(p2_circuit);
- }
- if (part1)
- {
- if (count == 1000)
- {
- long product = MultiplyLargestThreeCounts(circuitList);
- Console.WriteLine("Product of largest 3 circuits: " + product);
- break;
- }
- }
- else
- {
- if (circuitList.Count == 1 && circuitList[0].Count == input_lines.Length)
- {
- Console.WriteLine("Last Points X = " + key.P1.X + " and " + key.P2.X + " (multiplied = " +(key.P1.X * key.P2.X) + ")");
- break;
- }
- }
- }
- }
- public static long MultiplyLargestThreeCounts<T>(List<List<T>> collections)
- {
- // 1. Get the count of each collection.
- IEnumerable<int> counts = collections.Select(c => c.Count);
- // 2. Order the counts in descending order.
- var sortedCountsDesc = counts.OrderByDescending(count => count);
- // 3. Take the top 3 counts.
- var topThreeCounts = sortedCountsDesc.Take(3);
- // 4. Multiply the three counts together using the Aggregate function.
- // We use an initial seed of 1 for multiplication.
- // Using 'long' to prevent potential overflow with large counts.
- long product = topThreeCounts.Aggregate(1L, (currentProduct, count) => currentProduct * count);
- return product;
- }
- static List<Point>? FindCircuitContainingPoint(Point p)
- {
- foreach (List<Point> circuit in circuitList)
- {
- if (circuit.Contains(p)) return circuit;
- }
- return null;
- }
- }
- internal class PointDistanceKey : IComparable<PointDistanceKey>
- {
- public Point P1;
- public Point P2;
- public PointDistanceKey(Point p1, Point p2)
- {
- P1 = p1;
- P2 = p2;
- }
- public int CompareTo(PointDistanceKey? other)
- {
- if (other == null) return 1; // Current instance is greater than a null object
- // Default sort by the Distance between the Points
- // The int returned by CompareTo determines the relative order:
- // > 0 means current object comes after 'other'
- // < 0 means current object comes before 'other'
- // 0 means they are equal in sort order
- double local_d2 = P1.DistanceSquared(P2);
- double other_d2 = other.P1.DistanceSquared( other.P2);
- if (local_d2 == other_d2)
- return 0;
- if (local_d2 < other_d2)
- return -1;
- else
- return 1; // if (local_d2 > other_d2)
- }
- public override string ToString()
- {
- return P1.ToString()+":"+P2.ToString();
- }
- }
- internal class Point
- {
- public long X;
- public long Y;
- public long Z;
- public Point(long x, long y, long z)
- {
- X = x;
- Y = y;
- Z = z;
- }
- public long DistanceSquared(Point p2)
- {
- return (p2.X - X) * (p2.X - X) + (p2.Y - Y) * (p2.Y - Y) + (p2.Z - Z) * (p2.Z - Z);
- }
- public override string ToString()
- {
- return X+","+Y+","+Z;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment