/** * Function performing a search around a center tile and going outward, thus in circle. * Although it really is a square search... * Every tile will be tested by means of the callback function proc, * which will determine if yes or no the given tile meets criteria of search. * @param tile to start the search from. Upon completion, it will return the tile matching the search * @param size: number of tiles per side of the desired search area * @param proc: callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search * @pre proc != NULL * @pre size > 0 */ public static bool CircularTileSearch <T>(ref TileIndex tile, uint size, TestTileOnSearchProc <T> proc, T userData) { if (proc == null) { throw new ArgumentNullException(nameof(proc)); } if (size <= 0) { throw new ArgumentOutOfRangeException(nameof(size), "Must be greater than zero"); } if (size % 2 == 1) { /* If the length of the side is uneven, the center has to be checked * separately, as the pattern of uneven sides requires to go around the center */ if (proc(ref tile, userData)) { return(true); } /* If tile test is not successful, get one tile up, * ready for a test in first circle around center tile */ tile = TILE_ADD(tile, (uint)(int)TileOffsByDir(Direction.DIR_N)); return(CircularTileSearch(ref tile, size / 2, 1, 1, proc, userData)); } else { return(CircularTileSearch(ref tile, size / 2, 0, 0, proc, userData)); } }
/** * Generalized circular search allowing for rectangles and a hole. * Function performing a search around a center rectangle and going outward. * The center rectangle is left out from the search. To do a rectangular search * without a hole, set either h or w to zero. * Every tile will be tested by means of the callback function proc, * which will determine if yes or no the given tile meets criteria of search. * @param tile to start the search from. Upon completion, it will return the tile matching the search. * This tile should be directly north of the hole (if any). * @param radius How many tiles to search outwards. Note: This is a radius and thus different * from the size parameter of the other CircularTileSearch function, which is a diameter. * @param w the width of the inner rectangle * @param h the height of the inner rectangle * @param proc callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search * @pre proc != NULL * @pre radius > 0 */ public static bool CircularTileSearch <T>(ref TileIndex tile, uint radius, uint w, uint h, TestTileOnSearchProc <T> proc, T userData) { if (proc == null) { throw new ArgumentNullException(nameof(proc)); } if (radius <= 0) { throw new ArgumentOutOfRangeException(nameof(radius), "Must be greater than zero"); } uint x = TileX(tile) + w + 1; uint y = TileY(tile); uint[] extent = new uint[(int)DiagDirection.DIAGDIR_END] { w, h, w, h }; for (uint n = 0; n < radius; n++) { for (var dir = (int)DiagDirection.DIAGDIR_BEGIN; dir < (int)DiagDirection.DIAGDIR_END; dir++) { /* Is the tile within the map? */ for (uint j = extent[dir] + n * 2 + 1; j != 0; j--) { if (x < MapSizeX() && y < MapSizeY()) { TileIndex t = TileXY(x, y); /* Is the callback successful? */ if (proc(ref t, userData)) { /* Stop the search */ tile = t; return(true); } } /* Step to the next 'neighbour' in the circular line */ x += (uint)_tileoffs_by_diagdir[dir].x; y += (uint)_tileoffs_by_diagdir[dir].y; } } /* Jump to next circle to test */ x += (uint)_tileoffs_by_dir[(int)Direction.DIR_W].x; y += (uint)_tileoffs_by_dir[(int)Direction.DIR_W].y; } tile = TileConstants.INVALID_TILE; return(false); }