/*********
        ** Private methods
        *********/
        /// <summary>Extend the given machine group to include all machines and containers connected to the given tile, if any.</summary>
        /// <param name="group">The machine group to extend.</param>
        /// <param name="location">The location to search.</param>
        /// <param name="origin">The first tile to check.</param>
        /// <param name="visited">A lookup of visited tiles.</param>
        /// <param name="reflection">Simplifies access to private game code.</param>
        private void FloodFillGroup(MachineGroupBuilder group, GameLocation location, Vector2 origin, ISet <Vector2> visited, IReflectionHelper reflection)
        {
            // skip if already visited
            if (visited.Contains(origin))
            {
                return;
            }

            // flood-fill connected machines & containers
            Queue <Vector2> queue = new Queue <Vector2>();

            queue.Enqueue(origin);
            while (queue.Any())
            {
                // get tile
                Vector2 tile = queue.Dequeue();
                if (!visited.Add(tile))
                {
                    continue;
                }

                // get machine or container on tile
                Vector2 foundSize;
                if (this.TryGetMachine(location, tile, reflection, out IMachine machine, out Vector2 size))
                {
                    group.Add(machine);
                    foundSize = size;
                }
        /*********
        ** Public methods
        *********/
        /// <summary>Get all machine groups in a location.</summary>
        /// <param name="location">The location to search.</param>
        /// <param name="reflection">Simplifies access to private game code.</param>
        public IEnumerable <MachineGroup> GetMachineGroups(GameLocation location, IReflectionHelper reflection)
        {
            MachineGroupBuilder builder = new MachineGroupBuilder(location);
            ISet <Vector2>      visited = new HashSet <Vector2>();

            foreach (Vector2 tile in location.GetTiles())
            {
                this.FloodFillGroup(builder, location, tile, visited, reflection);
                if (builder.HasTiles())
                {
                    yield return(builder.Build());

                    builder.Reset();
                }
            }
        }
        /// <summary>Get all machine groups in a location.</summary>
        /// <param name="location">The location to search.</param>
        public IEnumerable <MachineGroup> GetMachineGroups(GameLocation location)
        {
            MachineGroupBuilder    builder       = new MachineGroupBuilder(location, this.Config);
            LocationFloodFillIndex locationIndex = new LocationFloodFillIndex(location);
            ISet <Vector2>         visited       = new HashSet <Vector2>();

            foreach (Vector2 tile in location.GetTiles())
            {
                this.FloodFillGroup(builder, location, tile, locationIndex, visited);
                if (builder.HasTiles())
                {
                    yield return(builder.Build());

                    builder.Reset();
                }
            }
        }
 /*********
 ** Private methods
 *********/
 /// <summary>Extend the given machine group to include all machines and containers connected to the given tile, if any.</summary>
 /// <param name="machineGroup">The machine group to extend.</param>
 /// <param name="location">The location to search.</param>
 /// <param name="origin">The first tile to check.</param>
 /// <param name="locationIndex">An indexed view of the location.</param>
 /// <param name="visited">A lookup of visited tiles.</param>
 private void FloodFillGroup(MachineGroupBuilder machineGroup, GameLocation location, in Vector2 origin, LocationFloodFillIndex locationIndex, ISet <Vector2> visited)