public int DistToSqrd(Point3d other)
        {
            int dx = X - other.X;
            int dy = Y - other.Y;
            int dz = Z - other.Z;

            return dx*dx + dy*dy + dz*dz;
        }
        static List<Range> ProjectBombs(int x, int y, Point3d[] bombsByZ, int radSqr)
        {
            var result = new List<Range>();

            foreach (var b in bombsByZ)
            {
                int dx = b.X - x;
                int dy = b.Y - y;

                int xYDistSqr = dx*dx + dy*dy;

                if (radSqr >= xYDistSqr)
                {
                    int maxDz = (int)Math.Sqrt(radSqr - xYDistSqr);
                    var newRange = new Range(b.Z - maxDz, b.Z + maxDz + 1);

                    // The intersection of a bomb is symetric around its Z
                    // Also, each bomb has Z >= all previous ones
                    // Thus, if the Begin of the range is less than a previous Begin, the new range totally superceeds the previous range, 
                    //  and the previous range can be removed
                    for (int iExisting = result.Count - 1; iExisting >= 0; iExisting--)
                    {
                        if (newRange.Begin <= result[iExisting].Begin)
                        {
                            result.RemoveAt(iExisting);
                        }
                        else
                        {
                            // result is build up sorted by Begin
                            // Thus, if Begin at iExisting is too small, there is no point continuing back through the list
                            break;
                        }
                    }

                    result.Add(newRange);
                }
            }

            return result;
        }
 private static int FindMinRadius(Point3d p, List<Point3d> bombs)
 {
     var result = bombs.Select(b => b.DistToSqrd(p)).Min();
     return result;
 }
        static void Main()
        {
            var bombs = new List<Point3d>();
            var rand = new Random();

            while (bombs.Count < 200)
            {
                int x = rand.Next(CubeSize);
                int y = rand.Next(CubeSize);
                int z = rand.Next(CubeSize);

                var next = new Point3d(x, y, z);

                if (!bombs.Contains(next))
                {
                    bombs.Add(next);
                }
            }
            // Add in Corner bombs, as otherwise the corners tend to be the safest spots, which isn't very interesting
            bombs.Add(new Point3d(0, 0, 0));
            bombs.Add(new Point3d(0, 0, 1000));
            bombs.Add(new Point3d(0, 1000, 0));
            bombs.Add(new Point3d(0, 1000, 1000));
            bombs.Add(new Point3d(1000, 0, 0));
            bombs.Add(new Point3d(1000, 0, 1000));
            bombs.Add(new Point3d(1000, 1000, 0));
            bombs.Add(new Point3d(1000, 1000, 1000));

            // Add the center of each face
            bombs.Add(new Point3d(0, 500, 500));
            bombs.Add(new Point3d(1000, 500, 500));

            bombs.Add(new Point3d(500, 0, 500));
            bombs.Add(new Point3d(500, 1000, 500));

            bombs.Add(new Point3d(500, 500, 0));
            bombs.Add(new Point3d(500, 500, 1000));

            Console.WriteLine("{0} bombs - eg {1}", bombs.Count, bombs.First());
            Console.WriteLine();

            FindSafest(bombs);
        }
        static void FindSafest(List<Point3d> bombs)
        {
            var bombsByZ = bombs.OrderBy(b => b.Z).ToArray();

            int bestRad = 0;
            var bestPlace = new Point3d();

            // Basic algorithm - each x = x1, y = y1 defines a line of CubeSize points for each Z
            // Project each bomb with current best radius onto this line to find
            //  section where the sphere around each bomb intersects
            // Then, only need to check Z values not in these intersections
            for (int x = 0; x < CubeSize; x++)
            {
                for (int y = 0; y < CubeSize; y++)
                {
                    var exclusions = ProjectBombs(x, y, bombsByZ, bestRad);

                    int oldRad = bestRad;
                    foreach (int z in ValuesLeft(exclusions))
                    {
                        var p = new Point3d(x, y, z);

                        int candidate = FindMinRadius(p, bombs);
                        if (candidate > bestRad)
                        {
                            bestRad = candidate;
                            bestPlace = p;
                        }
                    }

                    if (bestRad > oldRad)
                    {
                        Console.WriteLine("{0,20} : Cursor : {1} : Found new radius of {2}", TimeStamp(), bestPlace, bestRad);
                    }
                }
            }

            Console.WriteLine("Total Time = {0}", s_timer.Elapsed);
            Console.WriteLine("Safest radius {0} @ {1}", bestRad, bestPlace);
        }