-- | Rectangular areas of levels and their basic operations. module Game.LambdaHack.Area ( Area, vicinityXY, vicinityCardinalXY, insideXY , normalizeArea, grid, validArea, trivialArea, expand ) where import Game.LambdaHack.PointXY import Game.LambdaHack.VectorXY -- | The type of areas. The bottom left and the top right points. type Area = (X, Y, X, Y) -- | All (8 at most) closest neighbours of a point within an area. vicinityXY :: Area -- ^ limit the search to this area -> PointXY -- ^ location to find neighbours of -> [PointXY] vicinityXY area xy = [ res | dxy <- movesXY, let res = shiftXY xy dxy, insideXY res area ] -- | All (4 at most) cardinal direction neighbours of a point within an area. vicinityCardinalXY :: Area -- ^ limit the search to this area -> PointXY -- ^ location to find neighbours of -> [PointXY] vicinityCardinalXY area xy = [ res | dxy <- movesCardinalXY, let res = shiftXY xy dxy, insideXY res area ] -- | Checks that a point belongs to an area. insideXY :: PointXY -> Area -> Bool insideXY (PointXY (x, y)) (x0, y0, x1, y1) = x1 >= x && x >= x0 && y1 >= y && y >= y0 -- | Sort the corners of an area so that the bottom left is the first point. normalizeArea :: Area -> Area normalizeArea (x0, y0, x1, y1) = (min x0 x1, min y0 y1, max x0 x1, max y0 y1) -- | Divide uniformly a larger area into the given number of smaller areas. grid :: (X, Y) -> Area -> [(PointXY, Area)] grid (nx, ny) (x0, y0, x1, y1) = let xd = x1 - x0 yd = y1 - y0 -- Make sure that in caves not filled with rock, there is a passage -- across the cave, even if a single room blocks most of the cave. xborder = if nx == 1 then 3 else 2 yborder = if ny == 1 then 3 else 2 in [ (PointXY (x, y), (x0 + (xd * x `div` nx) + xborder, y0 + (yd * y `div` ny) + yborder, x0 + (xd * (x + 1) `div` nx) - xborder, y0 + (yd * (y + 1) `div` ny) - yborder)) | x <- [0..nx-1], y <- [0..ny-1] ] -- | Checks if it's an area with at least one field. validArea :: Area -> Bool validArea (x0, y0, x1, y1) = x0 <= x1 && y0 <= y1 -- | Checks if it's an area with exactly one field. trivialArea :: Area -> Bool trivialArea (x0, y0, x1, y1) = x0 == x1 && y0 == y1 -- | Enlarge (or shrink) the given area on all fours sides by the amount. expand :: Area -> Int -> Area expand (x0, y0, x1, y1) k = (x0 - k, y0 - k, x1 + k, y1 + k)