Пример #1
0
    public static List <Island> DetectIslands(Map map)
    {
        int width      = map.Width;
        int height     = map.Height;
        int blockCount = width * height;

        Block *matrix = map.GetBlockMatrix();

        //
        List <Island> islands = new List <Island>();

        //allocate and initialize the search matrix
        //so we can check which blocks we have already
        //added/searched.
        searchBlock *searchMatrix = (searchBlock *)Marshal.AllocHGlobal(
            sizeof(searchBlock) * blockCount);
        Block *      matrixPtr = matrix;
        searchBlock *ptr       = searchMatrix;
        searchBlock *ptrEnd    = ptr + blockCount;
        Block *      mapPtr    = matrix;

        while (ptr != ptrEnd)
        {
            searchBlock *current = ptr++;
            (*current).searched = false;
            (*current).block    = matrixPtr++;
        }

        //iterate through every block until we find every island
        ptr = searchMatrix;

        matrixPtr = matrix;
        int currentIslandIndex = 0;

        while (ptr != ptrEnd)
        {
            Block block = *matrixPtr++;

            //searched before?
            searchBlock *current = ptr++;
            if ((*current).searched)
            {
                continue;
            }

            //land?
            if (block.TypeID != Globals.TERRAIN_WATER)
            {
                //we hit an island
                islandInfo info = floodSearch(
                    current,
                    currentIslandIndex++,
                    width,
                    searchMatrix,
                    ptrEnd);

                //
                Island i = new Island(
                    map,
                    info.blocks,
                    info.minX,
                    info.minY,
                    info.maxX - info.minX,
                    info.maxY - info.minY);
            }
        }

        return(islands);
    }
Пример #2
0
    private static islandInfo floodSearch(searchBlock *block, int islandIndex, int rowWidth, searchBlock *start, searchBlock *end)
    {
        //create a queue to store pending blocks to
        //be processed.
        PtrQueue queue = new PtrQueue(10000);

        queue.Push(block);
        int count = 1;

        //count how many blocks we found
        int found = 0;

        //used to detect the size and location
        //of the island.
        int minX = 0, minY = 0;
        int maxX = 0, maxY = 0;

        minX = minY = int.MaxValue;

        //process every block
        List <IntPtr> blocks = new List <IntPtr>();

        while (count != 0)
        {
            searchBlock *ptr = (searchBlock *)queue.Pop();
            count--;

            //verify not out of bounds
            if (ptr < start || ptr >= end)
            {
                continue;
            }
            searchBlock deref = *ptr;

            //searched already?
            if (deref.searched)
            {
                continue;
            }

            //mark as processed
            (*ptr).searched = true;

            //we hit the water?
            Block b = (*deref.block);
            if (b.TypeID == Globals.TERRAIN_WATER)
            {
                continue;
            }
            found++;

            //add the block to the island
            blocks.Add((IntPtr)deref.block);

            //calculate x/y and do min/max to
            //detect island size/location
            int x = (int)((long)(ptr - start) % rowWidth);
            int y = (int)((long)(ptr - start) / rowWidth);
            if (x < minX)
            {
                minX = x;
            }
            if (y < minY)
            {
                minY = y;
            }
            if (x > maxX)
            {
                maxX = x;
            }
            if (y > maxY)
            {
                maxY = y;
            }

            #region reiterate for all 8 neighbors
            /*top row*/
            queue.Push(ptr - rowWidth);
            queue.Push(ptr - rowWidth - 1);
            queue.Push(ptr - rowWidth + 1);

            /*bottom row*/
            queue.Push(ptr + rowWidth);
            queue.Push(ptr + rowWidth - 1);
            queue.Push(ptr + rowWidth + 1);

            /*left/right*/
            queue.Push(ptr - 1);
            queue.Push(ptr + 1);

            count += 8;
            #endregion
        }

        return(new islandInfo {
            count = found,
            minX = minX,
            minY = minY,
            maxX = maxX,
            maxY = maxY,
            blocks = blocks
        });
    }