// Assumes the station starts rotating clockwise from vertical public SolarObject GetNthAsteroidVaporized( SolarGridPoint centerPoint, int n) { if (n < 1) { throw new ArgumentOutOfRangeException(nameof(n)); } // Initialize the set of objects remaining var pointsRemaining = _solarObjectDictionary .Select(kvp => kvp.Key) .ToHashSet(); if (pointsRemaining.Contains(centerPoint)) { pointsRemaining.Remove(centerPoint); } // Initialize the ordered list of objects vaporized var objectsVaporized = new List <SolarObject>(); // On each rotation, get the list of objects vaporized, ordered // clockwise from the starting angle int currentRotation = 1; var startingLaserVector = new Tuple <Radical, Radical>(0, -1); while (pointsRemaining.Count > 0) { // Get the list of objects seen (and therefore vaporized) // on this rotation var objectsVaporizedOnRotation = GetObjectsVisibleFromPoint(centerPoint, pointsRemaining); // Order by clockwise angle var objectsVaporizedOnRotationOrdered = objectsVaporizedOnRotation .Select(o => new Tuple <double, SolarObject>( VectorHelper.GetClockwiseAngleBetweenVectors( startingLaserVector, SolarGridPoint.GetDifferenceVector(centerPoint, o.GridPoint).ToRadicalVector()), o)) .OrderBy(o => o.Item1) .ToList(); // Remove the objects vaporized from the remaining list foreach (var vaporizedObject in objectsVaporizedOnRotation) { if (pointsRemaining.Contains(vaporizedObject.GridPoint)) { pointsRemaining.Remove(vaporizedObject.GridPoint); } } // Add ordered list of objects to objectsVaporized.AddRange(objectsVaporizedOnRotationOrdered.Select(o => o.Item2)); currentRotation++; } // Get the nth item if (n - 1 >= objectsVaporized.Count) { return(null); } return(objectsVaporized[n - 1]); }
public IList <SolarObject> GetObjectsVisibleFromPoint( SolarGridPoint point, HashSet <SolarGridPoint> pointsToCheck) { // Define a "jump vector" as a displacement from the given // central point to another point. // 1) For each integer n starting with 1, find all jump vectors where // |x| + |y| = n. // 2a) For each jump vector for a given n, move outwards from the // central point in multiples of the given jump vector. // 2b) If a point is encountered containing an object that hasn't // been seen before, then mark that object as seen. Afterwards, // mark any subsequent objects encountered as blocked. IList <SolarObject> objectsSeen = new List <SolarObject>(); var pointsChecked = new HashSet <SolarGridPoint>(); var displacementVectorsChecked = new HashSet <Tuple <int, int> >(); var numberToCheck = pointsToCheck.Count; int jumpNumber = 1; while (pointsChecked.Count < numberToCheck) { // Get all jump vectors for this n var jumpVectors = VectorHelper.GetJumpVectors(jumpNumber); foreach (var jumpVector in jumpVectors) { int jumpStep = 1; var displacementVector = VectorHelper.MultiplyVector(jumpVector, jumpStep); if (displacementVectorsChecked.Contains(displacementVector)) { continue; } displacementVectorsChecked.Add(displacementVector); var currentPoint = SolarGridPoint.GetPointAtRayVector(point, displacementVector); bool encounteredObjectAlongRay = false; while (GetIsCoordinateInGrid(currentPoint)) { if (pointsChecked.Contains(currentPoint)) { continue; } // Check if the point contains an object if (pointsToCheck.Contains(currentPoint)) { if (!encounteredObjectAlongRay) { objectsSeen.Add(_solarObjectDictionary[currentPoint]); encounteredObjectAlongRay = true; } pointsChecked.Add(currentPoint); } jumpStep++; displacementVector = VectorHelper.MultiplyVector(jumpVector, jumpStep); displacementVectorsChecked.Add(displacementVector); currentPoint = SolarGridPoint.GetPointAtRayVector(point, displacementVector); } } jumpNumber++; } return(objectsSeen); }