grid 5.0 → 5.1
raw patch · 14 files changed
+1422/−1723 lines, 14 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Math.Geometry.Grid: data HexHexGrid
- Math.Geometry.Grid: data ParaHexGrid
- Math.Geometry.Grid: data ParaTriGrid
- Math.Geometry.Grid: data RectOctGrid
- Math.Geometry.Grid: data RectSquareGrid
- Math.Geometry.Grid: data RectTriGrid
- Math.Geometry.Grid: data TorOctGrid
- Math.Geometry.Grid: data TorSquareGrid
- Math.Geometry.Grid: data TorTriGrid
- Math.Geometry.Grid: data TriTriGrid
- Math.Geometry.Grid: data UnboundedHexGrid
- Math.Geometry.Grid: data UnboundedOctGrid
- Math.Geometry.Grid: data UnboundedSquareGrid
- Math.Geometry.Grid: data UnboundedTriGrid
- Math.Geometry.Grid: hexHexGrid :: Int -> HexHexGrid
- Math.Geometry.Grid: numNeighbours :: Grid g => g -> Index g -> Int
- Math.Geometry.Grid: paraHexGrid :: Int -> Int -> ParaHexGrid
- Math.Geometry.Grid: paraTriGrid :: Int -> Int -> ParaTriGrid
- Math.Geometry.Grid: rectOctGrid :: Int -> Int -> RectOctGrid
- Math.Geometry.Grid: rectSquareGrid :: Int -> Int -> RectSquareGrid
- Math.Geometry.Grid: rectTriGrid :: Int -> Int -> RectTriGrid
- Math.Geometry.Grid: torOctGrid :: Int -> Int -> TorOctGrid
- Math.Geometry.Grid: torSquareGrid :: Int -> Int -> TorSquareGrid
- Math.Geometry.Grid: torTriGrid :: Int -> Int -> TorTriGrid
- Math.Geometry.Grid: triTriGrid :: Int -> TriTriGrid
- Math.Geometry.Grid: viewpoint :: Grid g => g -> Index g -> [(Index g, Int)]
- Math.Geometry.GridInternal: data HexHexGrid
- Math.Geometry.GridInternal: data ParaHexGrid
- Math.Geometry.GridInternal: data ParaTriGrid
- Math.Geometry.GridInternal: data RectOctGrid
- Math.Geometry.GridInternal: data RectSquareGrid
- Math.Geometry.GridInternal: data RectTriGrid
- Math.Geometry.GridInternal: data TorOctGrid
- Math.Geometry.GridInternal: data TorSquareGrid
- Math.Geometry.GridInternal: data TorTriGrid
- Math.Geometry.GridInternal: data TriTriGrid
- Math.Geometry.GridInternal: data UnboundedHexGrid
- Math.Geometry.GridInternal: data UnboundedOctGrid
- Math.Geometry.GridInternal: data UnboundedSquareGrid
- Math.Geometry.GridInternal: data UnboundedTriGrid
- Math.Geometry.GridInternal: hexHexGrid :: Int -> HexHexGrid
- Math.Geometry.GridInternal: instance BoundedGrid HexHexGrid
- Math.Geometry.GridInternal: instance BoundedGrid ParaHexGrid
- Math.Geometry.GridInternal: instance BoundedGrid ParaTriGrid
- Math.Geometry.GridInternal: instance BoundedGrid RectOctGrid
- Math.Geometry.GridInternal: instance BoundedGrid RectSquareGrid
- Math.Geometry.GridInternal: instance BoundedGrid RectTriGrid
- Math.Geometry.GridInternal: instance BoundedGrid TriTriGrid
- Math.Geometry.GridInternal: instance Eq HexHexGrid
- Math.Geometry.GridInternal: instance Eq ParaHexGrid
- Math.Geometry.GridInternal: instance Eq ParaTriGrid
- Math.Geometry.GridInternal: instance Eq RectOctGrid
- Math.Geometry.GridInternal: instance Eq RectSquareGrid
- Math.Geometry.GridInternal: instance Eq RectTriGrid
- Math.Geometry.GridInternal: instance Eq TorOctGrid
- Math.Geometry.GridInternal: instance Eq TorSquareGrid
- Math.Geometry.GridInternal: instance Eq TorTriGrid
- Math.Geometry.GridInternal: instance Eq TriTriGrid
- Math.Geometry.GridInternal: instance FiniteGrid HexHexGrid
- Math.Geometry.GridInternal: instance FiniteGrid ParaHexGrid
- Math.Geometry.GridInternal: instance FiniteGrid ParaTriGrid
- Math.Geometry.GridInternal: instance FiniteGrid RectOctGrid
- Math.Geometry.GridInternal: instance FiniteGrid RectSquareGrid
- Math.Geometry.GridInternal: instance FiniteGrid RectTriGrid
- Math.Geometry.GridInternal: instance FiniteGrid TorOctGrid
- Math.Geometry.GridInternal: instance FiniteGrid TorSquareGrid
- Math.Geometry.GridInternal: instance FiniteGrid TorTriGrid
- Math.Geometry.GridInternal: instance FiniteGrid TriTriGrid
- Math.Geometry.GridInternal: instance Grid HexHexGrid
- Math.Geometry.GridInternal: instance Grid ParaHexGrid
- Math.Geometry.GridInternal: instance Grid ParaTriGrid
- Math.Geometry.GridInternal: instance Grid RectOctGrid
- Math.Geometry.GridInternal: instance Grid RectSquareGrid
- Math.Geometry.GridInternal: instance Grid RectTriGrid
- Math.Geometry.GridInternal: instance Grid TorOctGrid
- Math.Geometry.GridInternal: instance Grid TorSquareGrid
- Math.Geometry.GridInternal: instance Grid TorTriGrid
- Math.Geometry.GridInternal: instance Grid TriTriGrid
- Math.Geometry.GridInternal: instance Grid UnboundedHexGrid
- Math.Geometry.GridInternal: instance Grid UnboundedOctGrid
- Math.Geometry.GridInternal: instance Grid UnboundedSquareGrid
- Math.Geometry.GridInternal: instance Grid UnboundedTriGrid
- Math.Geometry.GridInternal: instance Show HexHexGrid
- Math.Geometry.GridInternal: instance Show ParaHexGrid
- Math.Geometry.GridInternal: instance Show ParaTriGrid
- Math.Geometry.GridInternal: instance Show RectOctGrid
- Math.Geometry.GridInternal: instance Show RectSquareGrid
- Math.Geometry.GridInternal: instance Show RectTriGrid
- Math.Geometry.GridInternal: instance Show TorOctGrid
- Math.Geometry.GridInternal: instance Show TorSquareGrid
- Math.Geometry.GridInternal: instance Show TorTriGrid
- Math.Geometry.GridInternal: instance Show TriTriGrid
- Math.Geometry.GridInternal: instance Show UnboundedHexGrid
- Math.Geometry.GridInternal: instance Show UnboundedOctGrid
- Math.Geometry.GridInternal: instance Show UnboundedSquareGrid
- Math.Geometry.GridInternal: instance Show UnboundedTriGrid
- Math.Geometry.GridInternal: instance WrappedGrid TorOctGrid
- Math.Geometry.GridInternal: instance WrappedGrid TorSquareGrid
- Math.Geometry.GridInternal: instance WrappedGrid TorTriGrid
- Math.Geometry.GridInternal: paraHexGrid :: Int -> Int -> ParaHexGrid
- Math.Geometry.GridInternal: paraTriGrid :: Int -> Int -> ParaTriGrid
- Math.Geometry.GridInternal: rectOctGrid :: Int -> Int -> RectOctGrid
- Math.Geometry.GridInternal: rectSquareGrid :: Int -> Int -> RectSquareGrid
- Math.Geometry.GridInternal: rectTriGrid :: Int -> Int -> RectTriGrid
- Math.Geometry.GridInternal: torOctGrid :: Int -> Int -> TorOctGrid
- Math.Geometry.GridInternal: torSquareGrid :: Int -> Int -> TorSquareGrid
- Math.Geometry.GridInternal: torTriGrid :: Int -> Int -> TorTriGrid
- Math.Geometry.GridInternal: triTriGrid :: Int -> TriTriGrid
+ Math.Geometry.Grid: directionTo :: Grid g => g -> Index g -> Index g -> [Direction g]
+ Math.Geometry.Grid: neighbour :: (Grid g, Eq (Direction g)) => g -> Index g -> Direction g -> Index g
+ Math.Geometry.Grid.Hexagonal: data HexHexGrid
+ Math.Geometry.Grid.Hexagonal: data ParaHexGrid
+ Math.Geometry.Grid.Hexagonal: data UnboundedHexGrid
+ Math.Geometry.Grid.Hexagonal: hexHexGrid :: Int -> HexHexGrid
+ Math.Geometry.Grid.Hexagonal: paraHexGrid :: Int -> Int -> ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: East :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: HexHexGrid :: Int -> [(Int, Int)] -> HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: Northeast :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: Northwest :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: ParaHexGrid :: (Int, Int) -> [(Int, Int)] -> ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: Southeast :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: Southwest :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: UnboundedHexGrid :: UnboundedHexGrid
+ Math.Geometry.Grid.HexagonalInternal: West :: HexDirection
+ Math.Geometry.Grid.HexagonalInternal: data HexDirection
+ Math.Geometry.Grid.HexagonalInternal: data HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: data ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: data UnboundedHexGrid
+ Math.Geometry.Grid.HexagonalInternal: hexHexGrid :: Int -> HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance BoundedGrid HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance BoundedGrid ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Eq HexDirection
+ Math.Geometry.Grid.HexagonalInternal: instance Eq HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Eq ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance FiniteGrid HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance FiniteGrid ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Grid HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Grid ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Grid UnboundedHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Show HexDirection
+ Math.Geometry.Grid.HexagonalInternal: instance Show HexHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Show ParaHexGrid
+ Math.Geometry.Grid.HexagonalInternal: instance Show UnboundedHexGrid
+ Math.Geometry.Grid.HexagonalInternal: paraHexGrid :: Int -> Int -> ParaHexGrid
+ Math.Geometry.Grid.Octagonal: data RectOctGrid
+ Math.Geometry.Grid.Octagonal: data TorOctGrid
+ Math.Geometry.Grid.Octagonal: data UnboundedOctGrid
+ Math.Geometry.Grid.Octagonal: rectOctGrid :: Int -> Int -> RectOctGrid
+ Math.Geometry.Grid.Octagonal: torOctGrid :: Int -> Int -> TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: East :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: North :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: Northeast :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: Northwest :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: RectOctGrid :: (Int, Int) -> [(Int, Int)] -> RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: South :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: Southeast :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: Southwest :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: TorOctGrid :: (Int, Int) -> [(Int, Int)] -> TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: UnboundedOctGrid :: UnboundedOctGrid
+ Math.Geometry.Grid.OctagonalInternal: West :: OctDirection
+ Math.Geometry.Grid.OctagonalInternal: data OctDirection
+ Math.Geometry.Grid.OctagonalInternal: data RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: data TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: data UnboundedOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance BoundedGrid RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Eq OctDirection
+ Math.Geometry.Grid.OctagonalInternal: instance Eq RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Eq TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance FiniteGrid RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance FiniteGrid TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Grid RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Grid TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Grid UnboundedOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Show OctDirection
+ Math.Geometry.Grid.OctagonalInternal: instance Show RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Show TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance Show UnboundedOctGrid
+ Math.Geometry.Grid.OctagonalInternal: instance WrappedGrid TorOctGrid
+ Math.Geometry.Grid.OctagonalInternal: rectOctGrid :: Int -> Int -> RectOctGrid
+ Math.Geometry.Grid.OctagonalInternal: torOctGrid :: Int -> Int -> TorOctGrid
+ Math.Geometry.Grid.Square: data RectSquareGrid
+ Math.Geometry.Grid.Square: data TorSquareGrid
+ Math.Geometry.Grid.Square: data UnboundedSquareGrid
+ Math.Geometry.Grid.Square: rectSquareGrid :: Int -> Int -> RectSquareGrid
+ Math.Geometry.Grid.Square: torSquareGrid :: Int -> Int -> TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: East :: SquareDirection
+ Math.Geometry.Grid.SquareInternal: North :: SquareDirection
+ Math.Geometry.Grid.SquareInternal: RectSquareGrid :: (Int, Int) -> [(Int, Int)] -> RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: South :: SquareDirection
+ Math.Geometry.Grid.SquareInternal: TorSquareGrid :: (Int, Int) -> [(Int, Int)] -> TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: UnboundedSquareGrid :: UnboundedSquareGrid
+ Math.Geometry.Grid.SquareInternal: West :: SquareDirection
+ Math.Geometry.Grid.SquareInternal: data RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: data SquareDirection
+ Math.Geometry.Grid.SquareInternal: data TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: data UnboundedSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance BoundedGrid RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Eq RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Eq SquareDirection
+ Math.Geometry.Grid.SquareInternal: instance Eq TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance FiniteGrid RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance FiniteGrid TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Grid RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Grid TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Grid UnboundedSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Show RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Show SquareDirection
+ Math.Geometry.Grid.SquareInternal: instance Show TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance Show UnboundedSquareGrid
+ Math.Geometry.Grid.SquareInternal: instance WrappedGrid TorSquareGrid
+ Math.Geometry.Grid.SquareInternal: rectSquareGrid :: Int -> Int -> RectSquareGrid
+ Math.Geometry.Grid.SquareInternal: torSquareGrid :: Int -> Int -> TorSquareGrid
+ Math.Geometry.Grid.Triangular: data ParaTriGrid
+ Math.Geometry.Grid.Triangular: data RectTriGrid
+ Math.Geometry.Grid.Triangular: data TorTriGrid
+ Math.Geometry.Grid.Triangular: data TriTriGrid
+ Math.Geometry.Grid.Triangular: data UnboundedTriGrid
+ Math.Geometry.Grid.Triangular: paraTriGrid :: Int -> Int -> ParaTriGrid
+ Math.Geometry.Grid.Triangular: rectTriGrid :: Int -> Int -> RectTriGrid
+ Math.Geometry.Grid.Triangular: torTriGrid :: Int -> Int -> TorTriGrid
+ Math.Geometry.Grid.Triangular: triTriGrid :: Int -> TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: North :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: Northeast :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: Northwest :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: ParaTriGrid :: (Int, Int) -> [(Int, Int)] -> ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: RectTriGrid :: (Int, Int) -> [(Int, Int)] -> RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: South :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: Southeast :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: Southwest :: TriDirection
+ Math.Geometry.Grid.TriangularInternal: TorTriGrid :: (Int, Int) -> [(Int, Int)] -> TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: TriTriGrid :: Int -> [(Int, Int)] -> TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: UnboundedTriGrid :: UnboundedTriGrid
+ Math.Geometry.Grid.TriangularInternal: YCylTriGrid :: (Int, Int) -> [(Int, Int)] -> YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: data ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: data RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: data TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: data TriDirection
+ Math.Geometry.Grid.TriangularInternal: data TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: data UnboundedTriGrid
+ Math.Geometry.Grid.TriangularInternal: data YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: inTriTriGrid :: (Int, Int) -> Int -> Bool
+ Math.Geometry.Grid.TriangularInternal: instance BoundedGrid ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance BoundedGrid RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance BoundedGrid TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Eq ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Eq RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Eq TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Eq TriDirection
+ Math.Geometry.Grid.TriangularInternal: instance Eq TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Eq YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance FiniteGrid ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance FiniteGrid RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance FiniteGrid TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance FiniteGrid TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance FiniteGrid YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid UnboundedTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Grid YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show TriDirection
+ Math.Geometry.Grid.TriangularInternal: instance Show TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show UnboundedTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance Show YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance WrappedGrid TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: instance WrappedGrid YCylTriGrid
+ Math.Geometry.Grid.TriangularInternal: paraTriGrid :: Int -> Int -> ParaTriGrid
+ Math.Geometry.Grid.TriangularInternal: rectTriGrid :: Int -> Int -> RectTriGrid
+ Math.Geometry.Grid.TriangularInternal: torTriGrid :: Int -> Int -> TorTriGrid
+ Math.Geometry.Grid.TriangularInternal: triTriGrid :: Int -> TriTriGrid
+ Math.Geometry.Grid.TriangularInternal: triZ :: Int -> Int -> Int
+ Math.Geometry.Grid.TriangularInternal: yCylTriGrid :: Int -> Int -> YCylTriGrid
+ Math.Geometry.GridInternal: adjacentEdges :: Grid g => Index g -> g -> [(Index g, Index g)]
+ Math.Geometry.GridInternal: cartesianCentre :: (Int, Int) -> [(Int, Int)]
+ Math.Geometry.GridInternal: cartesianIndices :: (Enum r, Enum c, Num r, Num c, Ord r, Ord c) => (r, c) -> [(c, r)]
+ Math.Geometry.GridInternal: cartesianMidpoints :: Int -> [Int]
+ Math.Geometry.GridInternal: defaultAdjacentTilesToward :: Grid g => g -> Index g -> Index g -> [Index g]
+ Math.Geometry.GridInternal: defaultEdges :: (Grid g, Eq (Index g)) => g -> [(Index g, Index g)]
+ Math.Geometry.GridInternal: defaultIsAdjacent :: Grid g => g -> Index g -> Index g -> Bool
+ Math.Geometry.GridInternal: defaultMinDistance :: Grid g => g -> [Index g] -> Index g -> Int
+ Math.Geometry.GridInternal: defaultMinimalPaths :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> [[Index g]]
+ Math.Geometry.GridInternal: defaultNeighbour :: (Grid g, Eq (Direction g)) => g -> Index g -> Direction g -> Index g
+ Math.Geometry.GridInternal: defaultNeighbours :: Grid g => g -> Index g -> [Index g]
+ Math.Geometry.GridInternal: defaultTileCount :: Grid g => g -> Int
+ Math.Geometry.GridInternal: denormalise :: WrappedGrid g => g -> Index g -> [Index g]
+ Math.Geometry.GridInternal: directionTo :: Grid g => g -> Index g -> Index g -> [Direction g]
+ Math.Geometry.GridInternal: directionToBasedOn :: (Eq (Index g), Eq (Direction g), Grid g, Grid u, Index g ~ Index u, Direction g ~ Direction u) => u -> g -> Index g -> Index g -> [Direction g]
+ Math.Geometry.GridInternal: directionToWrappedBasedOn :: (Eq (Index g), Eq (Direction g), WrappedGrid g, Grid u, Index g ~ Index u, Direction g ~ Direction u) => u -> g -> Index g -> Index g -> [Direction g]
+ Math.Geometry.GridInternal: distanceBasedOn :: (Eq (Index g), Grid g, Grid u, Index g ~ Index u) => u -> g -> Index g -> Index g -> Int
+ Math.Geometry.GridInternal: distanceWrappedBasedOn :: (Eq (Index g), WrappedGrid g, Grid u, Index g ~ Index u) => u -> g -> Index g -> Index g -> Int
+ Math.Geometry.GridInternal: neighbour :: (Grid g, Eq (Direction g)) => g -> Index g -> Direction g -> Index g
+ Math.Geometry.GridInternal: neighbourWrappedBasedOn :: (Eq (Index g), Eq (Direction g), WrappedGrid g, Grid u, Index g ~ Index u, Direction g ~ Direction u) => u -> g -> Index g -> Direction g -> Index g
+ Math.Geometry.GridInternal: neighboursBasedOn :: (Eq (Index u), Grid g, Grid u, Index g ~ Index u) => u -> g -> Index g -> [Index g]
+ Math.Geometry.GridInternal: neighboursWrappedBasedOn :: (Eq (Index g), WrappedGrid g, Grid u, Index g ~ Index u) => u -> g -> Index g -> [Index g]
+ Math.Geometry.GridInternal: sameEdge :: Eq t => (t, t) -> (t, t) -> Bool
- Math.Geometry.Grid: class Grid g => BoundedGrid g where boundary g = map fst . filter f $ xds where xds = map (\ y -> (y, numNeighbours g y)) $ indices g f (_, n) = n < tileSideCount g isBoundary g x = x `elem` boundary g centre g = map fst . head . reverse . groupBy ((≡) `on` snd) . sortBy (comparing snd) $ xds where xds = map (\ y -> (y, minDistance g bs y)) $ indices g bs = boundary g isCentre g x = x `elem` centre g
+ Math.Geometry.Grid: class Grid g => BoundedGrid g where boundary g = map fst . filter f $ xds where xds = map (\ b -> (b, numNeighbours g b)) $ indices g f (_, n) = n < tileSideCount g isBoundary g a = a `elem` boundary g centre g = map fst . last . groupBy ((≡) `on` snd) . sortBy (comparing snd) $ xds where xds = map (\ b -> (b, minDistance g bs b)) $ indices g bs = boundary g isCentre g a = a `elem` centre g
- Math.Geometry.Grid: class Grid g where type family Index g minDistance g xs x = minimum . map (distance g x) $ xs neighbours g x = filter (\ a -> distance g x a ≡ 1) $ indices g numNeighbours g = length . neighbours g contains g x = x `elem` indices g viewpoint g p = map f (indices g) where f x = (x, distance g p x) tileCount = length . indices null g = tileCount g ≡ 0 nonNull = not . null edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g isAdjacent g a b = a `elem` (neighbours g b) adjacentTilesToward g a b = filter f $ neighbours g a where f x = distance g x b ≡ distance g a b - 1 minimalPaths g a b | a ≡ b = [[a]] | distance g a b ≡ 1 = [[a, b]] | otherwise = map (a :) xs where xs = concatMap (\ x -> minimalPaths g x b) ys ys = adjacentTilesToward g a b
+ Math.Geometry.Grid: class Grid g where type family Index g type family Direction g minDistance = defaultMinDistance neighbours = defaultNeighbours neighbour = defaultNeighbour numNeighbours g = length . neighbours g contains g a = a `elem` indices g tileCount = length . indices null g = tileCount g ≡ 0 nonNull = not . null edges = defaultEdges viewpoint g p = map f (indices g) where f a = (a, distance g p a) isAdjacent = defaultIsAdjacent adjacentTilesToward = defaultAdjacentTilesToward minimalPaths = defaultMinimalPaths defaultMinDistance g xs a = minimum . map (distance g a) $ xs defaultNeighbours g a = filter (\ b -> distance g a b ≡ 1) $ indices g defaultNeighbour g a d = head . filter (\ b -> [d] ≡ directionTo g a b) . neighbours g $ a defaultTileCount = length . indices defaultEdges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g defaultIsAdjacent g a b = distance g a b ≡ 1 defaultAdjacentTilesToward g a b = filter f $ neighbours g a where f c = distance g c b ≡ distance g a b - 1 defaultMinimalPaths g a b | a ≡ b = [[a]] | distance g a b ≡ 1 = [[a, b]] | otherwise = map (a :) xs where xs = concatMap (\ c -> minimalPaths g c b) ys ys = adjacentTilesToward g a b
- Math.Geometry.Grid: isAdjacent :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> Bool
+ Math.Geometry.Grid: isAdjacent :: Grid g => g -> Index g -> Index g -> Bool
- Math.Geometry.GridInternal: class Grid g => BoundedGrid g where boundary g = map fst . filter f $ xds where xds = map (\ y -> (y, numNeighbours g y)) $ indices g f (_, n) = n < tileSideCount g isBoundary g x = x `elem` boundary g centre g = map fst . head . reverse . groupBy ((≡) `on` snd) . sortBy (comparing snd) $ xds where xds = map (\ y -> (y, minDistance g bs y)) $ indices g bs = boundary g isCentre g x = x `elem` centre g
+ Math.Geometry.GridInternal: class Grid g => BoundedGrid g where boundary g = map fst . filter f $ xds where xds = map (\ b -> (b, numNeighbours g b)) $ indices g f (_, n) = n < tileSideCount g isBoundary g a = a `elem` boundary g centre g = map fst . last . groupBy ((≡) `on` snd) . sortBy (comparing snd) $ xds where xds = map (\ b -> (b, minDistance g bs b)) $ indices g bs = boundary g isCentre g a = a `elem` centre g
- Math.Geometry.GridInternal: class Grid g where type family Index g minDistance g xs x = minimum . map (distance g x) $ xs neighbours g x = filter (\ a -> distance g x a ≡ 1) $ indices g numNeighbours g = length . neighbours g contains g x = x `elem` indices g viewpoint g p = map f (indices g) where f x = (x, distance g p x) tileCount = length . indices null g = tileCount g ≡ 0 nonNull = not . null edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g isAdjacent g a b = a `elem` (neighbours g b) adjacentTilesToward g a b = filter f $ neighbours g a where f x = distance g x b ≡ distance g a b - 1 minimalPaths g a b | a ≡ b = [[a]] | distance g a b ≡ 1 = [[a, b]] | otherwise = map (a :) xs where xs = concatMap (\ x -> minimalPaths g x b) ys ys = adjacentTilesToward g a b
+ Math.Geometry.GridInternal: class Grid g where type family Index g type family Direction g minDistance = defaultMinDistance neighbours = defaultNeighbours neighbour = defaultNeighbour numNeighbours g = length . neighbours g contains g a = a `elem` indices g tileCount = length . indices null g = tileCount g ≡ 0 nonNull = not . null edges = defaultEdges viewpoint g p = map f (indices g) where f a = (a, distance g p a) isAdjacent = defaultIsAdjacent adjacentTilesToward = defaultAdjacentTilesToward minimalPaths = defaultMinimalPaths defaultMinDistance g xs a = minimum . map (distance g a) $ xs defaultNeighbours g a = filter (\ b -> distance g a b ≡ 1) $ indices g defaultNeighbour g a d = head . filter (\ b -> [d] ≡ directionTo g a b) . neighbours g $ a defaultTileCount = length . indices defaultEdges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g defaultIsAdjacent g a b = distance g a b ≡ 1 defaultAdjacentTilesToward g a b = filter f $ neighbours g a where f c = distance g c b ≡ distance g a b - 1 defaultMinimalPaths g a b | a ≡ b = [[a]] | distance g a b ≡ 1 = [[a, b]] | otherwise = map (a :) xs where xs = concatMap (\ c -> minimalPaths g c b) ys ys = adjacentTilesToward g a b
- Math.Geometry.GridInternal: isAdjacent :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> Bool
+ Math.Geometry.GridInternal: isAdjacent :: Grid g => g -> Index g -> Index g -> Bool
Files
- grid.cabal +9/−1
- src/Math/Geometry/Grid.hs +15/−51
- src/Math/Geometry/Grid/Hexagonal.hs +33/−0
- src/Math/Geometry/Grid/HexagonalInternal.hs +145/−0
- src/Math/Geometry/Grid/Octagonal.hs +37/−0
- src/Math/Geometry/Grid/OctagonalInternal.hs +139/−0
- src/Math/Geometry/Grid/Square.hs +33/−0
- src/Math/Geometry/Grid/SquareInternal.hs +137/−0
- src/Math/Geometry/Grid/Triangular.hs +39/−0
- src/Math/Geometry/Grid/TriangularInternal.hs +317/−0
- src/Math/Geometry/GridInternal.hs +156/−611
- src/Math/Geometry/GridMap/Lazy.hs +3/−1
- test/Main.hs +8/−2
- test/Math/Geometry/GridQC.hs +351/−1057
grid.cabal view
@@ -1,5 +1,5 @@ name: grid-version: 5.0+version: 5.1 synopsis: Tools for working with regular grids (graphs, lattices). description: Provides tools for working with regular arrangements of tiles, such as might be used in a board game or some@@ -33,7 +33,15 @@ containers ==0.4.2.* || ==0.5.* ghc-options: -Wall exposed-modules: Math.Geometry.Grid,+ Math.Geometry.Grid.Triangular,+ Math.Geometry.Grid.Square,+ Math.Geometry.Grid.Hexagonal,+ Math.Geometry.Grid.Octagonal, Math.Geometry.GridInternal,+ Math.Geometry.Grid.TriangularInternal,+ Math.Geometry.Grid.SquareInternal,+ Math.Geometry.Grid.HexagonalInternal,+ Math.Geometry.Grid.OctagonalInternal, Math.Geometry.GridMap, Math.Geometry.GridMap.Lazy
src/Math/Geometry/Grid.hs view
@@ -37,6 +37,8 @@ -- You can still /display/ the tiles as squares, but for internal -- calculations they are octagons. --+-- NOTE: Version 6.0 moved the various grid flavours to sub-modules.+-- -- NOTE: Version 4.0 uses associated (type) synonyms instead of -- multi-parameter type classes. --@@ -52,61 +54,23 @@ ( -- * Example -- $Example- -- * The Grid class- Grid(..),++ -- * Grids+ Grid(indices, distance, minDistance, neighbours, neighbour, + contains, tileCount, null, nonNull, edges, isAdjacent,+ adjacentTilesToward, minimalPaths, directionTo),+ Index,+ Direction,++ -- * Finite grids FiniteGrid(..),- BoundedGrid(..),- -- * Grids with triangular tiles- -- ** Unbounded grid with triangular tiles- UnboundedTriGrid,- -- ** Triangular grid with triangular tiles- TriTriGrid,- triTriGrid,- -- ** Parallelogram-shaped grid with triangular tiles- ParaTriGrid,- paraTriGrid,- -- ** Rectangular grid with triangular tiles- RectTriGrid,- rectTriGrid,- -- ** Toroidal grid with triangular tiles- TorTriGrid,- torTriGrid,- -- * Grids with square tiles- -- ** Unbounded grid with square tiles- UnboundedSquareGrid,- -- ** Rectangular grid with square tiles- RectSquareGrid,- rectSquareGrid,- -- ** Toroidal grid with square tiles- TorSquareGrid,- torSquareGrid,- -- * Grids with hexagonal tiles- -- ** Unbounded grid with hexagonal tiles- UnboundedHexGrid,- -- ** Hexagonal grid with hexagonal tiles- HexHexGrid,- hexHexGrid,- -- ** Parallelogram-shaped grid with hexagonal tiles- ParaHexGrid,- paraHexGrid,- -- * Grids with octagonal tiles- -- ** Unbounded grid with octagonal tiles- UnboundedOctGrid,- -- ** Rectangular grid with octagonal tiles- RectOctGrid,- rectOctGrid,- -- ** Toroidal grid with octagonal tiles- TorOctGrid,- torOctGrid++ -- * Bounded grids+ BoundedGrid(..) ) where import Math.Geometry.GridInternal (Grid(..), FiniteGrid(..), - BoundedGrid(..), UnboundedTriGrid, TriTriGrid, triTriGrid, - ParaTriGrid, paraTriGrid, RectTriGrid, rectTriGrid, - TorTriGrid, torTriGrid, UnboundedSquareGrid, - RectSquareGrid, rectSquareGrid, TorSquareGrid, torSquareGrid, - UnboundedHexGrid, HexHexGrid, hexHexGrid, ParaHexGrid, paraHexGrid, - UnboundedOctGrid, RectOctGrid, rectOctGrid, TorOctGrid, torOctGrid)+ BoundedGrid(..)) {- $Example
+ src/Math/Geometry/Grid/Hexagonal.hs view
@@ -0,0 +1,33 @@+-----------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.HexGrid+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A regular arrangement of hexagonal tiles.+-- The userguide, with illustrations, is available at +-- <https://github.com/mhwombat/grid/wiki>.+-- Also see @Math.Geometry.Grid@ for examples of how to use this class.+--+-----------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, TypeSynonymInstances, + FlexibleInstances #-}++module Math.Geometry.Grid.Hexagonal+ (+ -- * Unbounded grid with hexagonal tiles+ UnboundedHexGrid,+ -- * Hexagonal grid with hexagonal tiles+ HexHexGrid,+ hexHexGrid,+ -- * Parallelogram-shaped grid with hexagonal tiles+ ParaHexGrid,+ paraHexGrid+ ) where++import Math.Geometry.Grid.HexagonalInternal (UnboundedHexGrid, HexHexGrid, + hexHexGrid, ParaHexGrid, paraHexGrid)+
+ src/Math/Geometry/Grid/HexagonalInternal.hs view
@@ -0,0 +1,145 @@+------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.HexGridInternal+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A module containing private @HexGrid@ internals. Most developers +-- should use @HexGrid@ instead. This module is subject to change +-- without notice.+--+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-}++module Math.Geometry.Grid.HexagonalInternal where++import Prelude hiding (null)+import Data.Ord.Unicode ((≤))+import Math.Geometry.GridInternal++data HexDirection = West | Northwest | Northeast | East | Southeast | + Southwest deriving (Show, Eq)++-- | An unbounded grid with hexagonal tiles+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data UnboundedHexGrid = UnboundedHexGrid deriving Show++instance Grid UnboundedHexGrid where+ type Index UnboundedHexGrid = (Int, Int)+ type Direction UnboundedHexGrid = HexDirection+ indices _ = undefined+ neighbours _ (x,y) = + [(x-1,y), (x-1,y+1), (x,y+1), (x+1,y), (x+1,y-1), (x,y-1)]+ distance _ (x1, y1) (x2, y2) = + maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]+ where z1 = -x1 - y1+ z2 = -x2 - y2+ directionTo _ (x1, y1) (x2, y2) = f1 . f2 . f3 . f4 . f5 . f6 $ []+ where f1 ds = if dx < 0 && dz > 0 then West:ds else ds+ f2 ds = if dx < 0 && dy > 0 then Northwest:ds else ds+ f3 ds = if dy > 0 && dz < 0 then Northeast:ds else ds+ f4 ds = if dx > 0 && dz < 0 then East:ds else ds+ f5 ds = if dx > 0 && dy < 0 then Southeast:ds else ds+ f6 ds = if dy < 0 && dz > 0 then Southwest:ds else ds+ dx = x2 - x1+ dy = y2 - y1+ z1 = -x1 - y1+ z2 = -x2 - y2+ dz = z2 - z1+ contains _ _ = True+ null _ = False+ nonNull _ = True++--+-- Hexagonal grids with hexagonal tiles+--++-- | A hexagonal grid with hexagonal tiles+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data HexHexGrid = HexHexGrid Int [(Int, Int)] deriving Eq++instance Show HexHexGrid where show (HexHexGrid s _) = "hexHexGrid " ++ show s++instance Grid HexHexGrid where+ type Index HexHexGrid = (Int, Int)+ type Direction HexHexGrid = HexDirection+ indices (HexHexGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedHexGrid+ distance = distanceBasedOn UnboundedHexGrid+ directionTo = directionToBasedOn UnboundedHexGrid+ contains g (x,y) = -s < x && x < s && check+ where s = size g+ check = if x < 0+ then -s-x < y && y < s+ else -s < y && y < s-x++instance FiniteGrid HexHexGrid where+ type Size HexHexGrid = Int+ size (HexHexGrid s _) = s++instance BoundedGrid HexHexGrid where+ tileSideCount _ = 6+ boundary g = + north ++ northeast ++ southeast ++ south ++ southwest ++ northwest+ where s = size g+ north = [(k,s-1) | k ← [-s+1,-s+2..0]]+ northeast = [(k,s-1-k) | k ← [1,2..s-1]]+ southeast = [(s-1,k) | k ← [-1,-2..(-s)+1]]+ south = [(k,(-s)+1) | k ← [s-2,s-3..0]]+ southwest = [(k,(-s)+1-k) | k ← [-1,-2..(-s)+1]]+ northwest = [(-s+1,k) | k ← [1,2..s-2]]+ centre _ = [(0,0)]++-- | @'hexHexGrid' s@ returns a grid of hexagonal shape, with+-- sides of length @s@, using hexagonal tiles. If @s@ is nonnegative, the +-- resulting grid will have @3*s*(s-1) + 1@ tiles. Otherwise, the resulting +-- grid will be null and the list of indices will be null.+hexHexGrid ∷ Int → HexHexGrid+hexHexGrid r = HexHexGrid r [(x, y) | x ← [-r+1..r-1], y ← f x]+ where f x = if x < 0 then [1-r-x .. r-1] else [1-r .. r-1-x]++--+-- Parallelogrammatical grids with hexagonal tiles+--++-- | A parallelogramatical grid with hexagonal tiles+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data ParaHexGrid = ParaHexGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show ParaHexGrid where + show (ParaHexGrid (r,c) _) = "paraHexGrid " ++ show r ++ " " ++ show c++instance Grid ParaHexGrid where+ type Index ParaHexGrid = (Int, Int)+ type Direction ParaHexGrid = HexDirection+ indices (ParaHexGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedHexGrid+ distance = distanceBasedOn UnboundedHexGrid+ directionTo = directionToBasedOn UnboundedHexGrid+ contains g (x,y) = 0 ≤ x && x < c && 0 ≤ y && y < r+ where (r,c) = size g++instance FiniteGrid ParaHexGrid where+ type Size ParaHexGrid = (Int, Int)+ size (ParaHexGrid s _) = s++instance BoundedGrid ParaHexGrid where+ tileSideCount _ = 6+ boundary g = cartesianIndices . size $ g+ centre g = cartesianCentre . size $ g++-- | @'paraHexGrid' r c@ returns a grid in the shape of a +-- parallelogram with @r@ rows and @c@ columns, using hexagonal tiles. If +-- @r@ and @c@ are both nonnegative, the resulting grid will have @r*c@ tiles.+-- Otherwise, the resulting grid will be null and the list of indices will +-- be null.+paraHexGrid ∷ Int → Int → ParaHexGrid+paraHexGrid r c = + ParaHexGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]+
+ src/Math/Geometry/Grid/Octagonal.hs view
@@ -0,0 +1,37 @@+-----------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.OctGrid+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A regular arrangement of octagonal tiles.+-- Octagons won't tile a regular plane (there will be diamond-shaped+-- gaps between the tiles), but they will tile a /hyperbolic/ plane.+-- (Alternatively, you can think of these as squares on a board game+-- where diagonal moves are allowed.)+-- The userguide, with illustrations, is available at +-- <https://github.com/mhwombat/grid/wiki>.+-- Also see @Math.Geometry.Grid@ for examples of how to use this class.+--+-----------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, TypeSynonymInstances, + FlexibleInstances #-}++module Math.Geometry.Grid.Octagonal+ (+ -- * Unbounded grid with octagonal tiles+ UnboundedOctGrid,+ -- * Rectangular grid with octagonal tiles+ RectOctGrid,+ rectOctGrid,+ -- * Toroidal grid with octagonal tiles+ TorOctGrid,+ torOctGrid+ ) where++import Math.Geometry.Grid.OctagonalInternal (UnboundedOctGrid, RectOctGrid, + rectOctGrid, TorOctGrid, torOctGrid)+
+ src/Math/Geometry/Grid/OctagonalInternal.hs view
@@ -0,0 +1,139 @@+------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.OctGridInternal+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A module containing private @OctGrid@ internals. Most developers +-- should use @OctGrid@ instead. This module is subject to change +-- without notice.+--+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-}++module Math.Geometry.Grid.OctagonalInternal where++import Prelude hiding (null)++import Data.List (nub)+import Data.Ord.Unicode ((≤))+import Math.Geometry.GridInternal++data OctDirection = West | Northwest | North | Northeast | East | + Southeast | South | Southwest deriving (Show, Eq)++-- | An unbounded grid with octagonal tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data UnboundedOctGrid = UnboundedOctGrid deriving Show++instance Grid UnboundedOctGrid where+ type Index UnboundedOctGrid = (Int, Int)+ type Direction UnboundedOctGrid = OctDirection+ indices _ = undefined+ neighbours _ (x,y) = [(x-1,y+1), (x,y+1), (x+1,y+1), (x+1,y), + (x+1,y-1), (x,y-1), (x-1,y-1), (x-1,y)]+ distance _ (x1, y1) (x2, y2) = max (abs (x2-x1)) (abs (y2-y1))+ contains _ _ = True+ directionTo _ (x1, y1) (x2, y2) = + f1 . f2 . f3 . f4 . f5 . f6 . f7 . f8 $ []+ where f1 ds = if dy > abs dx then North:ds else ds+ f2 ds = if -dy > abs dx then South:ds else ds+ f3 ds = if dx > abs dy then East:ds else ds+ f4 ds = if -dx > abs dy then West:ds else ds+ f5 ds = if dx > 0 && dy > 0 then Northeast:ds else ds+ f6 ds = if dx > 0 && dy < 0 then Southeast:ds else ds+ f7 ds = if dx < 0 && dy < 0 then Southwest:ds else ds+ f8 ds = if dx < 0 && dy > 0 then Northwest:ds else ds+ dx = x2 - x1+ dy = y2 - y1+ null _ = False+ nonNull _ = True++--+-- Rectangular grids with octagonal tiles+--++-- | A rectangular grid with octagonal tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data RectOctGrid = RectOctGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show RectOctGrid where + show (RectOctGrid (r,c) _) = + "rectOctGrid " ++ show r ++ " " ++ show c++instance Grid RectOctGrid where+ type Index RectOctGrid = (Int, Int)+ type Direction RectOctGrid = OctDirection+ indices (RectOctGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedOctGrid+ distance = distanceBasedOn UnboundedOctGrid+ directionTo = directionToBasedOn UnboundedOctGrid+ contains g (x,y) = 0 ≤ x && x < c && 0 ≤ y && y < r+ where (r,c) = size g++instance FiniteGrid RectOctGrid where+ type Size RectOctGrid = (Int, Int)+ size (RectOctGrid s _) = s++instance BoundedGrid RectOctGrid where+ tileSideCount _ = 4+ boundary g = cartesianIndices . size $ g+ centre g = cartesianCentre . size $ g++-- | @'rectOctGrid' r c@ produces a rectangular grid with @r@ rows+-- and @c@ columns, using octagonal tiles. If @r@ and @c@ are both +-- nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, +-- the resulting grid will be null and the list of indices will be +-- null.+rectOctGrid ∷ Int → Int → RectOctGrid+rectOctGrid r c = + RectOctGrid (r,c) [(x,y) | x ← [0..c-1], y ← [0..r-1]]++--+-- Toroidal grids with octagonal tiles.+--++-- | A toroidal grid with octagonal tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data TorOctGrid = TorOctGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show TorOctGrid where + show (TorOctGrid (r,c) _) = "torOctGrid " ++ show r ++ " " ++ show c++instance Grid TorOctGrid where+ type Index TorOctGrid = (Int, Int)+ type Direction TorOctGrid = OctDirection+ indices (TorOctGrid _ xs) = xs+ neighbours = neighboursWrappedBasedOn UnboundedOctGrid+ neighbour = neighbourWrappedBasedOn UnboundedOctGrid+ distance = distanceWrappedBasedOn UnboundedOctGrid+ directionTo = directionToWrappedBasedOn UnboundedOctGrid+ isAdjacent g a b = distance g a b ≤ 1+ contains _ _ = True++instance FiniteGrid TorOctGrid where+ type Size TorOctGrid = (Int, Int)+ size (TorOctGrid s _) = s++instance WrappedGrid TorOctGrid where+ normalise g (x,y) = (x `mod` c, y `mod` r)+ where (r, c) = size g+ denormalise g a = nub [ (x-c,y+r), (x,y+r), (x+c,y+r), + (x-c,y), (x,y), (x+c,y),+ (x-c,y-r), (x,y-r), (x+c,y-r) ]+ where (r, c) = size g+ (x, y) = normalise g a++-- | @'torOctGrid' r c@ returns a toroidal grid with @r@ +-- rows and @c@ columns, using octagonal tiles. If @r@ and @c@ are +-- both nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, +-- the resulting grid will be null and the list of indices will be null.+torOctGrid ∷ Int → Int → TorOctGrid+torOctGrid r c = TorOctGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]+
+ src/Math/Geometry/Grid/Square.hs view
@@ -0,0 +1,33 @@+-----------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.SquareGrid+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A regular arrangement of square tiles.+-- The userguide, with illustrations, is available at +-- <https://github.com/mhwombat/grid/wiki>.+-- Also see @Math.Geometry.Grid@ for examples of how to use this class.+--+-----------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, TypeSynonymInstances, + FlexibleInstances #-}++module Math.Geometry.Grid.Square+ (+ -- * Unbounded grid with square tiles+ UnboundedSquareGrid,+ -- * Rectangular grid with square tiles+ RectSquareGrid,+ rectSquareGrid,+ -- * Toroidal grid with square tiles+ TorSquareGrid,+ torSquareGrid+ ) where++import Math.Geometry.Grid.SquareInternal (UnboundedSquareGrid, + RectSquareGrid, rectSquareGrid, TorSquareGrid, torSquareGrid)+
+ src/Math/Geometry/Grid/SquareInternal.hs view
@@ -0,0 +1,137 @@+------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.SquareGridInternal+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A module containing private @SquareGrid@ internals. Most developers +-- should use @SquareGrid@ instead. This module is subject to change +-- without notice.+--+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-}++module Math.Geometry.Grid.SquareInternal where++import Prelude hiding (null)++import Data.Eq.Unicode ((≠))+import Data.List (nub)+import Data.Ord.Unicode ((≤))+import Math.Geometry.GridInternal++data SquareDirection = North | East | South | West deriving (Show, Eq)++-- | An unbounded grid with square tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data UnboundedSquareGrid = UnboundedSquareGrid deriving Show++instance Grid UnboundedSquareGrid where+ type Index UnboundedSquareGrid = (Int, Int)+ type Direction UnboundedSquareGrid = SquareDirection+ indices _ = undefined+ neighbours _ (x,y) = [(x,y+1), (x,y-1), (x+1,y), (x-1,y)]+ distance _ (x1, y1) (x2, y2) = abs (x2-x1) + abs (y2-y1)+ contains _ _ = True+ directionTo _ (x1, y1) (x2, y2) = f1 . f2 . f3 . f4 $ []+ where f1 ds = if y2 > y1 then North:ds else ds+ f2 ds = if y2 < y1 then South:ds else ds+ f3 ds = if x2 > x1 then East:ds else ds+ f4 ds = if x2 < x1 then West:ds else ds+ null _ = False+ nonNull _ = True++--+-- Rectangular grids with square tiles+--++-- | A rectangular grid with square tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data RectSquareGrid = RectSquareGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show RectSquareGrid where + show (RectSquareGrid (r,c) _) = + "rectSquareGrid " ++ show r ++ " " ++ show c++instance Grid RectSquareGrid where+ type Index RectSquareGrid = (Int, Int)+ type Direction RectSquareGrid = SquareDirection+ indices (RectSquareGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedSquareGrid+ distance = distanceBasedOn UnboundedSquareGrid+ adjacentTilesToward g a@(x1, y1) (x2, y2) = + filter (\i → g `contains` i && i ≠ a) $ nub [(x1,y1+dy),(x1+dx,y1)]+ where dx = signum (x2-x1)+ dy = signum (y2-y1)+ directionTo g x y = if g `contains` x && g `contains` y+ then directionTo UnboundedSquareGrid x y+ else []+ contains g (x,y) = 0 ≤ x && x < c && 0 ≤ y && y < r+ where (r, c) = size g++instance FiniteGrid RectSquareGrid where+ type Size RectSquareGrid = (Int, Int)+ size (RectSquareGrid s _) = s++instance BoundedGrid RectSquareGrid where+ tileSideCount _ = 4+ boundary g = cartesianIndices . size $ g+ centre g = cartesianCentre . size $ g++-- | @'rectSquareGrid' r c@ produces a rectangular grid with @r@ rows+-- and @c@ columns, using square tiles. If @r@ and @c@ are both +-- nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, +-- the resulting grid will be null and the list of indices will be +-- null.+rectSquareGrid ∷ Int → Int → RectSquareGrid+rectSquareGrid r c = + RectSquareGrid (r,c) [(x,y) | x ← [0..c-1], y ← [0..r-1]]++--+-- Toroidal grids with square tiles.+--++-- | A toroidal grid with square tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data TorSquareGrid = TorSquareGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show TorSquareGrid where + show (TorSquareGrid (r,c) _) = "torSquareGrid " ++ show r ++ " " ++ show c++instance Grid TorSquareGrid where+ type Index TorSquareGrid = (Int, Int)+ type Direction TorSquareGrid = SquareDirection+ indices (TorSquareGrid _ xs) = xs+ neighbours = neighboursWrappedBasedOn UnboundedSquareGrid+ neighbour = neighbourWrappedBasedOn UnboundedSquareGrid+ distance = distanceWrappedBasedOn UnboundedSquareGrid+ directionTo = directionToWrappedBasedOn UnboundedSquareGrid+ isAdjacent g a b = distance g a b ≤ 1+ contains _ _ = True++instance FiniteGrid TorSquareGrid where+ type Size TorSquareGrid = (Int, Int)+ size (TorSquareGrid s _) = s++instance WrappedGrid TorSquareGrid where+ normalise g (x,y) = (x `mod` c, y `mod` r)+ where (r, c) = size g+ denormalise g b = nub [ (x-c,y+r), (x,y+r), (x+c,y+r),+ (x-c,y), (x,y), (x+c,y),+ (x-c,y-r), (x,y-r), (x+c,y-r) ]+ where (r, c) = size g+ (x, y) = normalise g b++-- | @'torSquareGrid' r c@ returns a toroidal grid with @r@ +-- rows and @c@ columns, using square tiles. If @r@ and @c@ are +-- both nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, +-- the resulting grid will be null and the list of indices will be null.+torSquareGrid ∷ Int → Int → TorSquareGrid+torSquareGrid r c = TorSquareGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]+
+ src/Math/Geometry/Grid/Triangular.hs view
@@ -0,0 +1,39 @@+-----------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.TriGrid+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A regular arrangement of triangular tiles.+-- The userguide, with illustrations, is available at +-- <https://github.com/mhwombat/grid/wiki>.+-- Also see @Math.Geometry.Grid@ for examples of how to use this class.+--+-----------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, TypeSynonymInstances, + FlexibleInstances #-}++module Math.Geometry.Grid.Triangular+ (+ -- * Unbounded grid with triangular tiles+ UnboundedTriGrid,+ -- * Triangular grid with triangular tiles+ TriTriGrid,+ triTriGrid,+ -- * Parallelogram-shaped grid with triangular tiles+ ParaTriGrid,+ paraTriGrid,+ -- * Rectangular grid with triangular tiles+ RectTriGrid,+ rectTriGrid,+ -- * Toroidal grid with triangular tiles+ TorTriGrid,+ torTriGrid+ ) where++import Math.Geometry.Grid.TriangularInternal (UnboundedTriGrid, TriTriGrid, + triTriGrid, ParaTriGrid, paraTriGrid, RectTriGrid, rectTriGrid, + TorTriGrid, torTriGrid)
+ src/Math/Geometry/Grid/TriangularInternal.hs view
@@ -0,0 +1,317 @@+------------------------------------------------------------------------+-- |+-- Module : Math.Geometry.TriGridInternal+-- Copyright : (c) Amy de Buitléir 2012+-- License : BSD-style+-- Maintainer : amy@nualeargais.ie+-- Stability : experimental+-- Portability : portable+--+-- A module containing private @TriGrid@ internals. Most developers +-- should use @TriGrid@ instead. This module is subject to change +-- without notice.+--+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-}++module Math.Geometry.Grid.TriangularInternal where++import Prelude hiding (null)++import Data.Eq.Unicode ((≡))+import Data.List (nub)+import Data.Ord.Unicode ((≤), (≥))+import Math.Geometry.GridInternal++data TriDirection = South | Northwest | Northeast | + North | Southeast | Southwest deriving (Show, Eq)++-- | An unbounded grid with triangular tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data UnboundedTriGrid = UnboundedTriGrid deriving Show++instance Grid UnboundedTriGrid where+ type Index UnboundedTriGrid = (Int, Int)+ type Direction UnboundedTriGrid = TriDirection+ indices _ = undefined+ neighbours _ (x,y) = if even y+ then [(x-1,y+1), (x+1,y+1), (x+1,y-1)]+ else [(x-1,y-1), (x-1,y+1), (x+1,y-1)]+ distance _ (x1, y1) (x2, y2) = + maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]+ where z1 = triZ x1 y1+ z2 = triZ x2 y2+ contains _ _ = True+ null _ = False+ nonNull _ = True+ directionTo _ (x1, y1) (x2, y2) = + if even y1+ then f1 . f2 . f3 $ []+ else f4 . f5 . f6 $ []+ where f1 ds = if y2 < y1 then South:ds else ds+ f2 ds = if x2 < x1 then Northwest:ds else ds+ f3 ds = if z2 < z1 then Northeast:ds else ds+ f4 ds = if y2 > y1 then North:ds else ds+ f5 ds = if x2 > x1 then Southeast:ds else ds+ f6 ds = if z2 > z1 then Southwest:ds else ds+ z1 = triZ x1 y1+ z2 = triZ x2 y2+ ++-- | For triangular tiles, it is convenient to define a third component +-- z.+triZ ∷ Int → Int → Int +triZ x y = if even y then -x - y else -x - y + 1++--+-- Triangular grids with triangular tiles+--++-- | A triangular grid with triangular tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data TriTriGrid = TriTriGrid Int [(Int, Int)] deriving Eq++instance Show TriTriGrid where + show (TriTriGrid s _) = "triTriGrid " ++ show s++instance Grid TriTriGrid where+ type Index TriTriGrid = (Int, Int)+ type Direction TriTriGrid = TriDirection+ indices (TriTriGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedTriGrid+ distance = distanceBasedOn UnboundedTriGrid+ contains (TriTriGrid s _) (x, y) = inTriTriGrid (x,y) s+ directionTo = directionToBasedOn UnboundedTriGrid++inTriTriGrid ∷ (Int, Int) → Int → Bool+inTriTriGrid (x, y) s = x ≥ 0 && y ≥ 0 && even (x+y) && abs z ≤ 2*s-2+ where z = triZ x y++instance FiniteGrid TriTriGrid where+ type Size TriTriGrid = Int+ size (TriTriGrid s _) = s++instance BoundedGrid TriTriGrid where+ tileSideCount _ = 3+ boundary g = west ++ east ++ south+ where s = size g+ west = [(0,k) | k ← [0,2..2*s-2]]+ east = [(k,2*s-2-k) | k ← [2,4..2*s-2]]+ south = [(k,0) | k ← [2*s-4,2*s-6..2]]+ centre g = case s `mod` 3 of+ 0 → trefoilWithTop (k-1,k+1) where k = (2*s) `div` 3+ 1 → [(k,k)] where k = (2*(s-1)) `div` 3+ 2 → [(k+1,k+1)] where k = (2*(s-2)) `div` 3+ _ → error "This will never happen."+ where s = size g+ trefoilWithTop (i,j) = [(i,j), (i+2, j-2), (i,j-2)]++-- | @'triTriGrid' s@ returns a triangular grid with sides of +-- length @s@, using triangular tiles. If @s@ is nonnegative, the +-- resulting grid will have @s^2@ tiles. Otherwise, the resulting grid+-- will be null and the list of indices will be null.+triTriGrid ∷ Int → TriTriGrid+triTriGrid s = + TriTriGrid s [(xx,yy) | xx ← [0..2*(s-1)], + yy ← [0..2*(s-1)], + (xx,yy) `inTriTriGrid` s]++--+-- Parallelogrammatical grids with triangular tiles+--++-- | A Parallelogrammatical grid with triangular tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data ParaTriGrid = ParaTriGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show ParaTriGrid where + show (ParaTriGrid (r,c) _) = "paraTriGrid " ++ show r ++ " " ++ show c++instance Grid ParaTriGrid where+ type Index ParaTriGrid = (Int, Int)+ type Direction ParaTriGrid = TriDirection+ indices (ParaTriGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedTriGrid+ distance = distanceBasedOn UnboundedTriGrid+ directionTo = directionToBasedOn UnboundedTriGrid+ contains g (x,y) = 0 ≤ x && x < 2*c && 0 ≤ y && y < 2*r && even (x+y)+ where (r,c) = size g++instance FiniteGrid ParaTriGrid where+ type Size ParaTriGrid = (Int, Int)+ size (ParaTriGrid s _) = s++instance BoundedGrid ParaTriGrid where+ tileSideCount _ = 3+ boundary g = west ++ north ++ east ++ south+ where (r,c) = size g+ west = [(0,k) | k ← [0,2..2*r-2], c>0]+ north = [(k,2*r-1) | k ← [1,3..2*c-1], r>0]+ east = [(2*c-1,k) | k ← [2*r-3,2*r-5..1], c>0]+ south = [(k,0) | k ← [2*c-2,2*c-4..2], r>0]+ centre g = f . size $ g+ where f (r,c)+ | odd r && odd c + = [(c-1,r-1), (c,r)]+ | even r && even c && r ≡ c + = bowtie (c-1,r-1)+ | even r && even c && r > c + = bowtie (c-1,r-3) ++ bowtie (c-1,r-1) ++ bowtie (c-1,r+1)+ | even r && even c && r < c + = bowtie (c-3,r-1) ++ bowtie (c-1,r-1) ++ bowtie (c+1,r-1)+ | otherwise + = [(c-1,r), (c,r-1)]+ bowtie (i,j) = [(i,j), (i+1,j+1)]++-- | @'paraTriGrid' r c@ returns a grid in the shape of a +-- parallelogram with @r@ rows and @c@ columns, using triangular +-- tiles. If @r@ and @c@ are both nonnegative, the resulting grid will+-- have @2*r*c@ tiles. Otherwise, the resulting grid will be null and+-- the list of indices will be null.+paraTriGrid ∷ Int → Int → ParaTriGrid+paraTriGrid r c = + ParaTriGrid (r,c) [(x,y) | x ← [0..2*c-1], y ← [0..2*r-1], even (x+y)]+++--+-- Rectangular grids with triangular tiles+--++-- | A rectangular grid with triangular tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data RectTriGrid = RectTriGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show RectTriGrid where + show (RectTriGrid (r,c) _) = "rectTriGrid " ++ show r ++ " " ++ show c++instance Grid RectTriGrid where+ type Index RectTriGrid = (Int, Int)+ type Direction RectTriGrid = TriDirection+ indices (RectTriGrid _ xs) = xs+ neighbours = neighboursBasedOn UnboundedTriGrid+ distance = distanceBasedOn UnboundedTriGrid+ directionTo = directionToBasedOn UnboundedTriGrid+ -- TODO Implement faster "contains"++instance FiniteGrid RectTriGrid where+ type Size RectTriGrid = (Int, Int)+ size (RectTriGrid s _) = s++instance BoundedGrid RectTriGrid where+ tileSideCount _ = 3++-- | @'rectTriGrid' r c@ returns a grid in the shape of a +-- rectangle (with jagged edges) that has @r@ rows and @c@ columns, +-- using triangular tiles. If @r@ and @c@ are both nonnegative, the +-- resulting grid will have @2*r*c@ tiles. Otherwise, the resulting grid will be null and+-- the list of indices will be null.+rectTriGrid ∷ Int → Int → RectTriGrid+rectTriGrid r c = RectTriGrid (r,c) [(x,y) | y ← [0..2*r-1], x ← [xMin y .. xMax c y], even (x+y)]+ where xMin y = if even y then w else w+1+ where w = -2*((y+1) `div` 4)+ xMax c2 y = xMin y + 2*(c2-1)+++--+-- Toroidal grids with triangular tiles+--++-- | A toroidal grid with triangular tiles.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data TorTriGrid = TorTriGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show TorTriGrid where + show (TorTriGrid (r,c) _) = "torTriGrid " ++ show r ++ " " ++ show c++instance Grid TorTriGrid where+ type Index TorTriGrid = (Int, Int)+ type Direction TorTriGrid = TriDirection+ indices (TorTriGrid _ xs) = xs+ neighbours = neighboursWrappedBasedOn UnboundedTriGrid+ neighbour = neighbourWrappedBasedOn UnboundedTriGrid+ distance = distanceWrappedBasedOn UnboundedTriGrid+ directionTo = directionToWrappedBasedOn UnboundedTriGrid+ isAdjacent g a b = distance g a b ≤ 1+ contains _ _ = True++instance FiniteGrid TorTriGrid where+ type Size TorTriGrid = (Int, Int)+ size (TorTriGrid s _) = s++instance WrappedGrid TorTriGrid where+ normalise g (x,y) | y < 0 = normalise g (x,y+2*r)+ | y > 2*r-1 = normalise g (x,y-2*r)+ | x < 0 = normalise g (x+2*c,y)+ | x > 2*c-1 = normalise g (x-2*c,y)+ | otherwise = (x,y)+ where (r, c) = size g+ denormalise g a = nub [ (x-2*c,y+2*r), (x,y+2*r), (x+2*c,y+2*r),+ (x-2*c,y), (x,y), (x+2*c,y),+ (x-2*c,y-2*r), (x,y-2*r), (x+2*c,y-2*r) ]+ where (r, c) = size g+ (x, y) = normalise g a++-- | @'torTriGrid' r c@ returns a toroidal grid with @r@ rows and @c@+-- columns, using triangular tiles. The indexing method is the same as+-- for @ParaTriGrid@. If @r@ and @c@ are both nonnegative, the +-- resulting grid will have @2*r*c@ tiles. Otherwise, the resulting+-- grid will be null and the list of indices will be null.+torTriGrid ∷ Int → Int → TorTriGrid+torTriGrid r c = + TorTriGrid (r,c) [(x,y) | x ← [0..2*c-1], y ← [0..2*r-1], even (x+y)]++--+-- Cylindrical grids with triangular tiles+--++-- | A cylindrical grid with triangular tiles, where the cylinder is+-- along the y-axis.+-- The grid and its indexing scheme are illustrated in the user guide,+-- available at <https://github.com/mhwombat/grid/wiki>.+data YCylTriGrid = YCylTriGrid (Int, Int) [(Int, Int)] deriving Eq++instance Show YCylTriGrid where + show (YCylTriGrid (r,c) _) = "yCylTriGrid " ++ show r ++ " " ++ show c++instance Grid YCylTriGrid where+ type Index YCylTriGrid = (Int, Int)+ type Direction YCylTriGrid = TriDirection+ indices (YCylTriGrid _ xs) = xs+ neighbours = neighboursWrappedBasedOn UnboundedTriGrid+ neighbour = neighbourWrappedBasedOn UnboundedTriGrid+ distance = distanceWrappedBasedOn UnboundedTriGrid+ directionTo = directionToWrappedBasedOn UnboundedTriGrid+ isAdjacent g a b = distance g a b ≤ 1+ contains g (x, y) = 0 ≤ y && y ≤ 2*r-1 && even (x+y) + where (r, _) = size g++instance FiniteGrid YCylTriGrid where+ type Size YCylTriGrid = (Int, Int)+ size (YCylTriGrid s _) = s++instance WrappedGrid YCylTriGrid where+ normalise g (x,y) | x < 0 = normalise g (x+2*c,y)+ | x > 2*c-1 = normalise g (x-2*c,y)+ | otherwise = (x,y)+ where (_, c) = size g+ denormalise g a = nub [ (x-2*c,y), (x,y), (x+2*c,y) ]+ where (_, c) = size g+ (x, y) = normalise g a++-- | @'yCylTriGrid' r c@ returns a cylindrical grid with @r@ rows and +-- @c@ columns, using triangular tiles, where the cylinder is along +-- the y-axis. The indexing method is the same as for @ParaTriGrid@. +-- If @r@ and @c@ are both nonnegative, the resulting grid will have +-- @2*r*c@ tiles. Otherwise, the resulting grid will be null and the +-- list of indices will be null.+yCylTriGrid ∷ Int → Int → YCylTriGrid+yCylTriGrid r c = + YCylTriGrid (r,c) [(x,y) | x ← [0..2*c-1], y ← [0..2*r-1], even (x+y)]+++
src/Math/Geometry/GridInternal.hs view
@@ -13,50 +13,21 @@ ------------------------------------------------------------------------ {-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-} -module Math.Geometry.GridInternal- (- Grid(..),- FiniteGrid(..),- BoundedGrid(..),- WrappedGrid(..),- UnboundedTriGrid,- TriTriGrid,- triTriGrid,- ParaTriGrid,- paraTriGrid,- RectTriGrid,- rectTriGrid,- TorTriGrid,- torTriGrid,- UnboundedSquareGrid,- RectSquareGrid,- rectSquareGrid,- TorSquareGrid,- torSquareGrid,- UnboundedHexGrid,- HexHexGrid,- hexHexGrid,- ParaHexGrid,- paraHexGrid,- UnboundedOctGrid,- RectOctGrid,- rectOctGrid,- TorOctGrid,- torOctGrid,- ) where+module Math.Geometry.GridInternal where import Prelude hiding (null) -import Data.Eq.Unicode ((≡), (≠))+import Data.Eq.Unicode ((≡)) import Data.Function (on) import Data.List (groupBy, nub, nubBy, sortBy) import Data.Ord (comparing)-import Data.Ord.Unicode ((≤), (≥)) -- | A regular arrangement of tiles.--- Minimal complete definition: @Index@, @indices@ and @distance@.+-- Minimal complete definition: @Index@, @Direction@, @indices@, +-- @distance@, @directionTo@. class Grid g where type Index g+ type Direction g -- | Returns the indices of all tiles in a grid. indices ∷ g → [Index g]@@ -75,29 +46,28 @@ -- any of @bs@ are not contained within @g@, the result is -- undefined. minDistance ∷ g → [Index g] → Index g → Int- minDistance g xs x = minimum . map (distance g x) $ xs+ minDistance = defaultMinDistance - -- | @'neighbours' g x@ returns the indices of the tiles in the grid- -- @g@ which are adjacent to the tile with index @x@.+ -- | @'neighbours' g a@ returns the indices of the tiles in the grid+ -- @g@ which are adjacent to the tile with index @a@. neighbours ∷ g → Index g → [Index g]- neighbours g x = filter (\a → distance g x a ≡ 1 ) $ indices g+ neighbours = defaultNeighbours - -- | @'numNeighbours' g x@ returns the number of tiles in the grid- -- @g@ which are adjacent to the tile with index @x@.+ -- | @'neighbour' g d a@ returns the indices of the tile in the grid+ -- @g@ which is adjacent to the tile with index @a@, in the + -- direction @d@.+ neighbour ∷ Eq (Direction g) ⇒ g → Index g → Direction g → Index g+ neighbour = defaultNeighbour++ -- | @'numNeighbours' g a@ returns the number of tiles in the grid+ -- @g@ which are adjacent to the tile with index @a@. numNeighbours ∷ g → Index g → Int numNeighbours g = length . neighbours g - -- | @g `'contains'` x@ returns @True@ if the index @x@ is contained + -- | @g `'contains'` a@ returns @True@ if the index @a@ is contained -- within the grid @g@, otherwise it returns false. contains ∷ Eq (Index g) ⇒ g → Index g → Bool- contains g x = x `elem` indices g-- -- | @'viewpoint' g x@ returns a list of pairs associating the index- -- of each tile in @g@ with its distance to the tile with index @x@.- -- If @x@ is not contained within @g@, the result is undefined.- viewpoint ∷ g → Index g → [(Index g, Int)]- viewpoint g p = map f (indices g)- where f x = (x, distance g p x)+ contains g a = a `elem` indices g -- | Returns the number of tiles in a grid. Compare with @'size'@. tileCount ∷ g → Int@@ -116,14 +86,21 @@ -- | A list of all edges in a grid, where the edges are represented by -- a pair of indices of adjacent tiles. edges ∷ Eq (Index g) ⇒ g → [(Index g,Index g)]- edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g+ edges = defaultEdges + -- | @'viewpoint' g a@ returns a list of pairs associating the index+ -- of each tile in @g@ with its distance to the tile with index @a@.+ -- If @a@ is not contained within @g@, the result is undefined.+ viewpoint ∷ g → Index g → [(Index g, Int)]+ viewpoint g p = map f (indices g)+ where f a = (a, distance g p a)+ -- | @'isAdjacent' g a b@ returns @True@ if the tile at index @a@ is -- adjacent to the tile at index @b@ in @g@. (Two tiles are adjacent -- if they share an edge.) If @a@ or @b@ are not contained within -- @g@, the result is undefined.- isAdjacent ∷ Eq (Index g) ⇒ g → Index g → Index g → Bool- isAdjacent g a b = a `elem` (neighbours g b)+ isAdjacent ∷ g → Index g → Index g → Bool+ isAdjacent = defaultIsAdjacent -- | @'adjacentTilesToward' g a b@ returns the indices of all tiles -- which are neighbours of the tile at index @a@, and which are@@ -132,8 +109,7 @@ -- or @b@ are not contained within @g@, or if there is no path from -- @a@ to @b@ (e.g., a disconnected grid), the result is undefined. adjacentTilesToward ∷ g → Index g → Index g → [Index g]- adjacentTilesToward g a b = filter f $ neighbours g a- where f x = distance g x b ≡ distance g a b - 1+ adjacentTilesToward = defaultAdjacentTilesToward -- | @'minimalPaths' g a b@ returns a list of all minimal paths from -- the tile at index @a@ to the tile at index @b@ in grid @g@. A@@ -147,19 +123,79 @@ -- consider modifying @'adjacentTilesToward'@ instead of -- @'minimalPaths'@. minimalPaths ∷ Eq (Index g) ⇒ g → Index g → Index g → [[Index g]]- minimalPaths g a b | a ≡ b = [[a]]- | distance g a b ≡ 1 = [[a,b]]- | otherwise = map (a:) xs- where xs = concatMap (\x → minimalPaths g x b) ys+ minimalPaths = defaultMinimalPaths++ -- | @'directionTo' g a b@ returns the direction(s) of the next + -- tile(s) in a /minimal/ path from the tile at index @a@ to the + -- tile at index @b@ in grid @g@.+ directionTo ∷ g → Index g → Index g → [Direction g]++ --+ -- These default implementations are broken out to make it easier to+ -- compare the results with custom implementations (for testing).+ --++ defaultMinDistance ∷ g → [Index g] → Index g → Int+ defaultMinDistance g xs a = minimum . map (distance g a) $ xs++ defaultNeighbours ∷ g → Index g → [Index g]+ defaultNeighbours g a = filter (\b → distance g a b ≡ 1 ) $ indices g++ defaultNeighbour ∷ Eq (Direction g) + ⇒ g → Index g → Direction g → Index g+ defaultNeighbour g a d =+ head . filter (\b → [d] ≡ directionTo g a b) . neighbours g $ a++ defaultTileCount ∷ g → Int+ defaultTileCount = length . indices++ defaultEdges ∷ Eq (Index g) ⇒ g → [(Index g,Index g)]+ defaultEdges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g++ defaultIsAdjacent ∷ g → Index g → Index g → Bool+ defaultIsAdjacent g a b = distance g a b ≡ 1++ defaultAdjacentTilesToward ∷ g → Index g → Index g → [Index g]+ defaultAdjacentTilesToward g a b = filter f $ neighbours g a+ where f c = distance g c b ≡ distance g a b - 1++ defaultMinimalPaths ∷ Eq (Index g)+ ⇒ g → Index g → Index g → [[Index g]]+ defaultMinimalPaths g a b + | a ≡ b = [[a]]+ | distance g a b ≡ 1 = [[a,b]]+ | otherwise = map (a:) xs+ where xs = concatMap (\c → minimalPaths g c b) ys ys = adjacentTilesToward g a b +--+-- Helper functions+--+ sameEdge ∷ Eq t ⇒ (t, t) → (t, t) → Bool sameEdge (a,b) (c,d) = (a,b) ≡ (c,d) || (a,b) ≡ (d,c) adjacentEdges ∷ Grid g ⇒ Index g → g → [(Index g, Index g)] adjacentEdges i g = map (\j → (i,j)) $ neighbours g i +cartesianIndices+ ∷ (Enum r, Enum c, Num r, Num c, Ord r, Ord c) ⇒+ (r, c) → [(c, r)]+cartesianIndices (r, c) = west ++ north ++ east ++ south+ where west = [(0,k) | k ← [0,1..r-1], c>0]+ north = [(k,r-1) | k ← [1,2..c-1], r>0]+ east = [(c-1,k) | k ← [r-2,r-3..0], c>1]+ south = [(k,0) | k ← [c-2,c-3..1], r>1] +cartesianCentre ∷ (Int, Int) → [(Int, Int)]+cartesianCentre (r,c) = [(i,j) | i ← cartesianMidpoints c, j ← cartesianMidpoints r]++cartesianMidpoints ∷ Int → [Int]+cartesianMidpoints k = if even k then [m-1,m] else [m]+ where m = floor (k'/2.0)+ k' = fromIntegral k ∷ Double++ -- | A regular arrangement of tiles where the number of tiles is finite. -- Minimal complete definition: @size@. class Grid g ⇒ FiniteGrid g where@@ -179,596 +215,105 @@ -- | Returns a the indices of all the tiles at the boundary of a grid. boundary ∷ g → [Index g] boundary g = map fst . filter f $ xds- where xds = map (\y → (y, numNeighbours g y)) $ indices g+ where xds = map (\b → (b, numNeighbours g b)) $ indices g f (_,n) = n < tileSideCount g - -- | @'isBoundary' g x@' returns @True@ if the tile with index @x@ is+ -- | @'isBoundary' g a@' returns @True@ if the tile with index @a@ is -- on a boundary of @g@, @False@ otherwise. (Corner tiles are also -- boundary tiles.) isBoundary ∷ Eq (Index g) ⇒ g → Index g → Bool- isBoundary g x = x `elem` boundary g+ isBoundary g a = a `elem` boundary g -- | Returns the index of the tile(s) that require the maximum number -- of moves to reach the nearest boundary tile. A grid may have more -- than one central tile (e.g., a rectangular grid with an even -- number of rows and columns will have four central tiles). centre ∷ g → [Index g]- centre g = map fst . head . reverse . groupBy ((≡) `on` snd) . + centre g = map fst . last . groupBy ((≡) `on` snd) . sortBy (comparing snd) $ xds- where xds = map (\y → (y, minDistance g bs y)) $ indices g+ where xds = map (\b → (b, minDistance g bs b)) $ indices g bs = boundary g - -- | @'isCentre' g x@' returns @True@ if the tile with index @x@ is+ -- | @'isCentre' g a@' returns @True@ if the tile with index @a@ is -- a centre tile of @g@, @False@ otherwise. isCentre ∷ Eq (Index g) ⇒ g → Index g → Bool- isCentre g x = x `elem` centre g+ isCentre g a = a `elem` centre g +-- | A regular arrangement of tiles where the boundaries are joined.+-- Minimal complete definition: @normalise@. class (Grid g) ⇒ WrappedGrid g where+ -- | @'normalise' g a@ returns the "normal" indices for @a@.+ -- TODO: need a clearer description and an illustration. normalise ∷ g → Index g → Index g+ -- | @'denormalise' g a@ returns all of the indices in @a@'s+ -- translation group. In other words, it returns @a@ plus the + -- indices obtained by translating @a@ in each direction by the+ -- extent of the grid along that direction.+ -- TODO: need a clearer description and an illustration.+ denormalise ∷ g → Index g → [Index g] --- Calculate the neighbours of a tile in a bounded grid by as we would --- in an unbounded grid, but then filter out the tiles that are not in--- bounds. neighboursBasedOn- ∷ (Eq (Index g), Grid u, Grid g, Index u ~ Index g) ⇒- g → u → Index g → [Index g]+ ∷ (Eq (Index u), Grid g, Grid u, Index g ~ Index u) ⇒+ u → g → Index g → [Index g] neighboursBasedOn u g = filter (g `contains`) . neighbours u --- Calculate the distance between two tiles in a bounded grid by as we --- would in an unbounded grid, but only if both tiles are in bounds. distanceBasedOn- ∷ (Eq (Index g), Grid u, Grid g, Index u ~ Index g) ⇒- g → u → Index g → Index g → Int+ ∷ (Eq (Index g), Grid g, Grid u, Index g ~ Index u) ⇒+ u → g → Index g → Index g → Int distanceBasedOn u g a b = if g `contains` a && g `contains` b then distance u a b else undefined ------ Triangular tiles------- | An unbounded grid with triangular tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data UnboundedTriGrid = UnboundedTriGrid deriving Show--instance Grid UnboundedTriGrid where- type Index UnboundedTriGrid = (Int, Int)- indices _ = undefined- neighbours _ (x,y) = if even y- then [(x-1,y+1), (x+1,y+1), (x+1,y-1)]- else [(x-1,y-1), (x-1,y+1), (x+1,y-1)]- distance _ (x1, y1) (x2, y2) = - maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]- where z1 = triZ x1 y1- z2 = triZ x2 y2- contains _ _ = True---- | For triangular tiles, it is convenient to define a third component --- z.-triZ ∷ Int → Int → Int -triZ x y = if even y then -x - y else -x - y + 1------- Triangular grids with triangular tiles------- | A triangular grid with triangular tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data TriTriGrid = TriTriGrid Int [(Int, Int)] deriving Eq--instance Show TriTriGrid where - show (TriTriGrid s _) = "triTriGrid " ++ show s--instance Grid TriTriGrid where- type Index TriTriGrid = (Int, Int)- indices (TriTriGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedTriGrid- distance = distanceBasedOn UnboundedTriGrid- contains (TriTriGrid s _) (x, y) = inTriTriGrid (x,y) s--inTriTriGrid ∷ (Int, Int) → Int → Bool-inTriTriGrid (x, y) s = x ≥ 0 && y ≥ 0 && even (x+y) && abs z ≤ 2*s-2- where z = triZ x y--instance FiniteGrid TriTriGrid where- type Size TriTriGrid = Int- size (TriTriGrid s _) = s--instance BoundedGrid TriTriGrid where- tileSideCount _ = 3- boundary g = west ++ east ++ south- where s = size g- west = [(0,k) | k ← [0,2..2*s-2]]- east = [(k,2*s-2-k) | k ← [2,4..2*s-2]]- south = [(k,0) | k ← [2*s-4,2*s-6..2]]- centre g = case s `mod` 3 of- 0 → trefoilWithTop (k-1,k+1) where k = (2*s) `div` 3- 1 → [(k,k)] where k = (2*(s-1)) `div` 3- 2 → [(k+1,k+1)] where k = (2*(s-2)) `div` 3- _ → error "This will never happen."- where s = size g- trefoilWithTop (i,j) = [(i,j), (i+2, j-2), (i,j-2)]---- | @'triTriGrid' s@ returns a triangular grid with sides of --- length @s@, using triangular tiles. If @s@ is nonnegative, the --- resulting grid will have @s^2@ tiles. Otherwise, the resulting grid--- will be null and the list of indices will be null.-triTriGrid ∷ Int → TriTriGrid-triTriGrid s = - TriTriGrid s [(xx,yy) | xx ← [0..2*(s-1)], - yy ← [0..2*(s-1)], - (xx,yy) `inTriTriGrid` s]------- Parallelogrammatical grids with triangular tiles------- | A Parallelogrammatical grid with triangular tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data ParaTriGrid = ParaTriGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show ParaTriGrid where - show (ParaTriGrid (r,c) _) = "paraTriGrid " ++ show r ++ " " ++ show c--instance Grid ParaTriGrid where- type Index ParaTriGrid = (Int, Int)- indices (ParaTriGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedTriGrid- distance = distanceBasedOn UnboundedTriGrid--instance FiniteGrid ParaTriGrid where- type Size ParaTriGrid = (Int, Int)- size (ParaTriGrid s _) = s--instance BoundedGrid ParaTriGrid where- tileSideCount _ = 3- boundary g = west ++ north ++ east ++ south- where (r,c) = size g- west = [(0,k) | k ← [0,2..2*r-2], c>0]- north = [(k,2*r-1) | k ← [1,3..2*c-1], r>0]- east = [(2*c-1,k) | k ← [2*r-3,2*r-5..1], c>0]- south = [(k,0) | k ← [2*c-2,2*c-4..2], r>0]- centre g = f . size $ g- where f (r,c)- | odd r && odd c - = [(c-1,r-1), (c,r)]- | even r && even c && r ≡ c - = bowtie (c-1,r-1)- | even r && even c && r > c - = bowtie (c-1,r-3) ++ bowtie (c-1,r-1) ++ bowtie (c-1,r+1)- | even r && even c && r < c - = bowtie (c-3,r-1) ++ bowtie (c-1,r-1) ++ bowtie (c+1,r-1)- | otherwise - = [(c-1,r), (c,r-1)]- bowtie (i,j) = [(i,j), (i+1,j+1)]---- | @'paraTriGrid' r c@ returns a grid in the shape of a --- parallelogram with @r@ rows and @c@ columns, using triangular --- tiles. If @r@ and @c@ are both nonnegative, the resulting grid will--- have @2*r*c@ tiles. Otherwise, the resulting grid will be null and--- the list of indices will be null.-paraTriGrid ∷ Int → Int → ParaTriGrid-paraTriGrid r c = - ParaTriGrid (r,c) [(x,y) | x ← [0..2*c-1], y ← [0..2*r-1], even (x+y)]-------- Rectangular grids with triangular tiles------- | A rectangular grid with triangular tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data RectTriGrid = RectTriGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show RectTriGrid where - show (RectTriGrid (r,c) _) = "rectTriGrid " ++ show r ++ " " ++ show c--instance Grid RectTriGrid where- type Index RectTriGrid = (Int, Int)- indices (RectTriGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedTriGrid- distance = distanceBasedOn UnboundedTriGrid--instance FiniteGrid RectTriGrid where- type Size RectTriGrid = (Int, Int)- size (RectTriGrid s _) = s--instance BoundedGrid RectTriGrid where- tileSideCount _ = 3---- | @'rectTriGrid' r c@ returns a grid in the shape of a --- rectangle (with jagged edges) that has @r@ rows and @c@ columns, --- using triangular tiles. If @r@ and @c@ are both nonnegative, the --- resulting grid will have @2*r*c@ tiles. Otherwise, the resulting grid will be null and--- the list of indices will be null.-rectTriGrid ∷ Int → Int → RectTriGrid-rectTriGrid r c = RectTriGrid (r,c) [(x,y) | y ← [0..2*r-1], x ← [xMin y .. xMax c y], even (x+y)]- where xMin y = if even y then w else w+1- where w = -2*((y+1) `div` 4)- xMax c2 y = xMin y + 2*(c2-1)-------- Toroidal grids with triangular tiles------- | A toroidal grid with triangular tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data TorTriGrid = TorTriGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show TorTriGrid where - show (TorTriGrid (r,c) _) = "torTriGrid " ++ show r ++ " " ++ show c--instance Grid TorTriGrid where- type Index TorTriGrid = (Int, Int)- indices (TorTriGrid _ xs) = xs- neighbours g = nub . map (normalise g) . neighbours UnboundedTriGrid- distance g (xa, ya) (xb, yb) = - if g `contains` (xa, ya) && g `contains` (xb, yb)- then minimum [distance UnboundedTriGrid (xa, ya) (xb, yb),- distance UnboundedTriGrid (xa, ya) (xb + 2*c, yb),- distance UnboundedTriGrid (xa, ya) (xb - r, yb + 2*r),- distance UnboundedTriGrid (xa, ya) (xb, yb),- distance UnboundedTriGrid (xa + 2*c, ya) (xb, yb),- distance UnboundedTriGrid (xa - r, ya + 2*r) (xb, yb)]- else undefined- where (r,c) = size g--xMinTorTri ∷ Int → Int-xMinTorTri y = if even y then w else w+1- where w = -2*((y+1) `div` 4)+directionToBasedOn+ ∷ (Eq (Index g), Eq (Direction g), Grid g, Grid u, Index g ~ Index u, + Direction g ~ Direction u) ⇒+ u → g → Index g → Index g → [Direction g]+directionToBasedOn u g a b = + if g `contains` a && g `contains` b+ then nub . concatMap (directionTo u a) . adjacentTilesToward g a $ b+ else undefined +neighboursWrappedBasedOn+ ∷ (Eq (Index g), WrappedGrid g, Grid u, Index g ~ Index u) ⇒+ u → g → Index g → [Index g]+neighboursWrappedBasedOn u g = + filter (g `contains`) . nub . map (normalise g) . neighbours u -instance FiniteGrid TorTriGrid where- type Size TorTriGrid = (Int, Int)- size (TorTriGrid s _) = s+neighbourWrappedBasedOn+ ∷ (Eq (Index g), Eq (Direction g), WrappedGrid g, Grid u, + Index g ~ Index u, Direction g ~ Direction u) ⇒+ u → g → Index g → Direction g → Index g+neighbourWrappedBasedOn u g a d =+ if g `contains` a+ then normalise g . neighbour u a $ d+ else undefined -instance WrappedGrid TorTriGrid where- normalise g (x,y)- | y < 0 = normalise g (x-r,y+2*r)- | y > 2*r-1 = normalise g (x+r,y-2*r)- | x < xMin = normalise g (x+2*c,y)- | x > xMin + 2*c-1 = normalise g (x-2*c,y)- | otherwise = (x,y)- where xMin = xMinTorTri y- (r, c) = size g+distanceWrappedBasedOn+ ∷ (Eq (Index g), WrappedGrid g, Grid u, Index g ~ Index u) ⇒+ u → g → Index g → Index g → Int+distanceWrappedBasedOn u g a b = + if g `contains` a && g `contains` b+ then minimum . map (distance u a') $ bs+ else undefined+ where a' = normalise g a+ bs = denormalise g b --- | @'torTriGrid' r c@ returns a toroidal grid with @r@ rows and @c@ --- columns, using triangular tiles. If @r@ is odd, the result is--- undefined because the grid edges would overlap. If @r@ and @c@ --- are both nonnegative, the resulting grid will have @2*r*c@ tiles. --- Otherwise, the resulting grid will be null and the list of indices--- will be null.-torTriGrid ∷ Int → Int → TorTriGrid-torTriGrid r c = - if even r- then TorTriGrid (r,c) [(x,y) | y ← [0..2*r-1], - x ← [xMinTorTri y .. xMax c y], - even (x+y)]+directionToWrappedBasedOn+ ∷ (Eq (Index g), Eq (Direction g), WrappedGrid g, Grid u, + Index g ~ Index u, Direction g ~ Direction u) ⇒+ u → g → Index g → Index g → [Direction g]+directionToWrappedBasedOn u g a b =+ if g `contains` a && g `contains` b+ then nub . concatMap (directionTo u a') $ ys' else undefined- where xMax c2 y = xMinTorTri y + 2*(c2-1)+ where a' = normalise g a+ ys = denormalise g b+ minD = distance g a b+ ys' = filter (\c -> distance u a' c == minD) ys ------ Square tiles--- --- | An unbounde grid with square tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data UnboundedSquareGrid = UnboundedSquareGrid deriving Show--instance Grid UnboundedSquareGrid where- type Index UnboundedSquareGrid = (Int, Int)- indices _ = undefined- neighbours _ (x,y) = [(x,y+1), (x,y-1), (x+1,y), (x-1,y)]- distance _ (x1, y1) (x2, y2) = abs (x2-x1) + abs (y2-y1)- contains _ _ = True------- Rectangular grids with square tiles------- | A rectangular grid with square tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data RectSquareGrid = RectSquareGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show RectSquareGrid where - show (RectSquareGrid (r,c) _) = - "rectSquareGrid " ++ show r ++ " " ++ show c--instance Grid RectSquareGrid where- type Index RectSquareGrid = (Int, Int)- indices (RectSquareGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedSquareGrid- distance = distanceBasedOn UnboundedSquareGrid- adjacentTilesToward g a@(x1, y1) (x2, y2) = - filter (\i → g `contains` i && i ≠ a) $ nub [(x1,y1+dy),(x1+dx,y1)]- where dx = signum (x2-x1)- dy = signum (y2-y1)--instance FiniteGrid RectSquareGrid where- type Size RectSquareGrid = (Int, Int)- size (RectSquareGrid s _) = s--instance BoundedGrid RectSquareGrid where- tileSideCount _ = 4- boundary g = cartesianIndices . size $ g- centre g = cartesianCentre . size $ g--cartesianIndices- ∷ (Enum r, Enum c, Num r, Num c, Ord r, Ord c) ⇒- (r, c) → [(c, r)]-cartesianIndices (r, c) = west ++ north ++ east ++ south- where west = [(0,k) | k ← [0,1..r-1], c>0]- north = [(k,r-1) | k ← [1,2..c-1], r>0]- east = [(c-1,k) | k ← [r-2,r-3..0], c>1]- south = [(k,0) | k ← [c-2,c-3..1], r>1]--cartesianCentre ∷ (Int, Int) → [(Int, Int)]-cartesianCentre (r,c) = [(i,j) | i ← midpoints c, j ← midpoints r]--midpoints ∷ Int → [Int]-midpoints k = if even k then [m-1,m] else [m]- where m = floor (k'/2.0)- k' = fromIntegral k ∷ Double---- | @'rectSquareGrid' r c@ produces a rectangular grid with @r@ rows--- and @c@ columns, using square tiles. If @r@ and @c@ are both --- nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, --- the resulting grid will be null and the list of indices will be --- null.-rectSquareGrid ∷ Int → Int → RectSquareGrid-rectSquareGrid r c = - RectSquareGrid (r,c) [(x,y) | x ← [0..c-1], y ← [0..r-1]]------- Toroidal grids with square tiles.------- | A toroidal grid with square tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data TorSquareGrid = TorSquareGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show TorSquareGrid where - show (TorSquareGrid (r,c) _) = "torSquareGrid " ++ show r ++ " " ++ show c--instance Grid TorSquareGrid where- type Index TorSquareGrid = (Int, Int)- indices (TorSquareGrid _ xs) = xs--- neighbours (TorSquareGrid (r,c) _) (x,y) = --- nub $ filter (\(xx,yy) → xx ≠ x || yy ≠ y) --- [((x-1) `mod` c,y), (x,(y+1) `mod` r), ((x+1) `mod` c,y), --- (x,(y-1) `mod` r)]- neighbours g = nub . map (normalise g) . neighbours UnboundedSquareGrid- distance g@(TorSquareGrid (r,c) _) (x1, y1) (x2, y2) = -- TODO redo- if g `contains` (x1, y1) && g `contains` (x2, y2)- then min adx (abs (c-adx)) + min ady (abs (r-ady))- else undefined - where adx = abs (x2 - x1)- ady = abs (y2 - y1)--instance FiniteGrid TorSquareGrid where- type Size TorSquareGrid = (Int, Int)- size (TorSquareGrid s _) = s--instance WrappedGrid TorSquareGrid where- normalise g (x,y) = (x `mod` c, y `mod` r)- where (r, c) = size g--denormaliseTor- :: (FiniteGrid g, Index g ~ (Int, Int), (Int, Int) ~ Size g) =>- g -> Index g -> [Index g]-denormaliseTor g (x,y) = nub [(x2,y1), (x,y1), (x1,y1), - (x2,y), (x,y), (x1,y),- (x2,y2), (x,y2), (x1,y2)]- where (r, c) = size g- x1 = x + c- y1 = y + r- x2 = x - c- y2 = y - r---- | @'torSquareGrid' r c@ returns a toroidal grid with @r@ --- rows and @c@ columns, using square tiles. If @r@ and @c@ are --- both nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, --- the resulting grid will be null and the list of indices will be null.-torSquareGrid ∷ Int → Int → TorSquareGrid-torSquareGrid r c = TorSquareGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]------- Hexagonal tiles------- | An unbounded grid with hexagonal tiles--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data UnboundedHexGrid = UnboundedHexGrid deriving Show--instance Grid UnboundedHexGrid where- type Index UnboundedHexGrid = (Int, Int)- indices _ = undefined- neighbours _ (x,y) = - [(x-1,y), (x-1,y+1), (x,y+1), (x+1,y), (x+1,y-1), (x,y-1)]- distance _ (x1, y1) (x2, y2) = - maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]- where z1 = -x1 - y1- z2 = -x2 - y2- contains _ _ = True------- Hexagonal grids with hexagonal tiles------- | A hexagonal grid with hexagonal tiles--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data HexHexGrid = HexHexGrid Int [(Int, Int)] deriving Eq--instance Show HexHexGrid where show (HexHexGrid s _) = "hexHexGrid " ++ show s--instance Grid HexHexGrid where- type Index HexHexGrid = (Int, Int)- indices (HexHexGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedHexGrid- distance = distanceBasedOn UnboundedHexGrid--instance FiniteGrid HexHexGrid where- type Size HexHexGrid = Int- size (HexHexGrid s _) = s--instance BoundedGrid HexHexGrid where- tileSideCount _ = 6- boundary g = - north ++ northeast ++ southeast ++ south ++ southwest ++ northwest- where s = size g- north = [(k,s-1) | k ← [-s+1,-s+2..0]]- northeast = [(k,s-1-k) | k ← [1,2..s-1]]- southeast = [(s-1,k) | k ← [-1,-2..(-s)+1]]- south = [(k,(-s)+1) | k ← [s-2,s-3..0]]- southwest = [(k,(-s)+1-k) | k ← [-1,-2..(-s)+1]]- northwest = [(-s+1,k) | k ← [1,2..s-2]]- centre _ = [(0,0)]---- | @'hexHexGrid' s@ returns a grid of hexagonal shape, with--- sides of length @s@, using hexagonal tiles. If @s@ is nonnegative, the --- resulting grid will have @3*s*(s-1) + 1@ tiles. Otherwise, the resulting --- grid will be null and the list of indices will be null.-hexHexGrid ∷ Int → HexHexGrid-hexHexGrid r = HexHexGrid r [(x, y) | x ← [-r+1..r-1], y ← f x]- where f x = if x < 0 then [1-r-x .. r-1] else [1-r .. r-1-x]------- Parallelogrammatical grids with hexagonal tiles------- | A parallelogramatical grid with hexagonal tiles--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data ParaHexGrid = ParaHexGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show ParaHexGrid where - show (ParaHexGrid (r,c) _) = "paraHexGrid " ++ show r ++ " " ++ show c--instance Grid ParaHexGrid where- type Index ParaHexGrid = (Int, Int)- indices (ParaHexGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedHexGrid- distance = distanceBasedOn UnboundedHexGrid--instance FiniteGrid ParaHexGrid where- type Size ParaHexGrid = (Int, Int)- size (ParaHexGrid s _) = s--instance BoundedGrid ParaHexGrid where- tileSideCount _ = 6- boundary g = cartesianIndices . size $ g- centre g = cartesianCentre . size $ g---- | @'paraHexGrid' r c@ returns a grid in the shape of a --- parallelogram with @r@ rows and @c@ columns, using hexagonal tiles. If --- @r@ and @c@ are both nonnegative, the resulting grid will have @r*c@ tiles.--- Otherwise, the resulting grid will be null and the list of indices will --- be null.-paraHexGrid ∷ Int → Int → ParaHexGrid-paraHexGrid r c = - ParaHexGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]-------- Octagonal tiles------- | An unbounded grid with octagonal tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data UnboundedOctGrid = UnboundedOctGrid deriving Show--instance Grid UnboundedOctGrid where- type Index UnboundedOctGrid = (Int, Int)- indices _ = undefined- neighbours _ (x,y) = [(x-1,y+1), (x,y+1), (x+1,y+1), (x+1,y), - (x+1,y-1), (x,y-1), (x-1,y-1), (x-1,y)]- distance _ (x1, y1) (x2, y2) = max (abs (x2-x1)) (abs (y2-y1))- contains _ _ = True------- Rectangular grids with octagonal tiles------- | A rectangular grid with octagonal tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data RectOctGrid = RectOctGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show RectOctGrid where - show (RectOctGrid (r,c) _) = - "rectOctGrid " ++ show r ++ " " ++ show c--instance Grid RectOctGrid where- type Index RectOctGrid = (Int, Int)- indices (RectOctGrid _ xs) = xs- neighbours = neighboursBasedOn UnboundedOctGrid- distance = distanceBasedOn UnboundedOctGrid--instance FiniteGrid RectOctGrid where- type Size RectOctGrid = (Int, Int)- size (RectOctGrid s _) = s--instance BoundedGrid RectOctGrid where- tileSideCount _ = 4- boundary g = cartesianIndices . size $ g- centre g = cartesianCentre . size $ g---- | @'rectOctGrid' r c@ produces a rectangular grid with @r@ rows--- and @c@ columns, using octagonal tiles. If @r@ and @c@ are both --- nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, --- the resulting grid will be null and the list of indices will be --- null.-rectOctGrid ∷ Int → Int → RectOctGrid-rectOctGrid r c = - RectOctGrid (r,c) [(x,y) | x ← [0..c-1], y ← [0..r-1]]------- Toroidal grids with octagonal tiles.------- | A toroidal grid with octagonal tiles.--- The grid and its indexing scheme are illustrated in the user guide,--- available at <https://github.com/mhwombat/grid/wiki>.-data TorOctGrid = TorOctGrid (Int, Int) [(Int, Int)] deriving Eq--instance Show TorOctGrid where - show (TorOctGrid (r,c) _) = "torOctGrid " ++ show r ++ " " ++ show c--instance Grid TorOctGrid where- type Index TorOctGrid = (Int, Int)- indices (TorOctGrid _ xs) = xs- neighbours g = nub . map (normalise g) . neighbours UnboundedOctGrid- distance g a b = minimum . map (distance UnboundedOctGrid a) $ bs- where bs = denormaliseTor g b--instance FiniteGrid TorOctGrid where- type Size TorOctGrid = (Int, Int)- size (TorOctGrid s _) = s--instance WrappedGrid TorOctGrid where- normalise g (x,y) = (x `mod` c, y `mod` r)- where (r, c) = size g---- | @'torOctGrid' r c@ returns a toroidal grid with @r@ --- rows and @c@ columns, using octagonal tiles. If @r@ and @c@ are --- both nonnegative, the resulting grid will have @r*c@ tiles. Otherwise, --- the resulting grid will be null and the list of indices will be null.-torOctGrid ∷ Int → Int → TorOctGrid-torOctGrid r c = TorOctGrid (r,c) [(x, y) | x ← [0..c-1], y ← [0..r-1]]
src/Math/Geometry/GridMap/Lazy.hs view
@@ -60,11 +60,13 @@ instance G.Grid g ⇒ G.Grid (LGridMap g v) where type Index (LGridMap g v) = G.Index g+ type Direction (LGridMap g v) = G.Direction g indices = G.indices . lgmGrid distance g = G.distance (lgmGrid g)+ directionTo g = G.directionTo (lgmGrid g) neighbours g k = lgmGrid g `G.neighbours` k contains g k = lgmGrid g `G.contains` k- viewpoint g k = lgmGrid g `G.viewpoint` k+-- viewpoint g k = lgmGrid g `G.viewpoint` k tileCount = G.tileCount . lgmGrid null = G.null . lgmGrid nonNull = G.nonNull . lgmGrid
test/Main.hs view
@@ -1,14 +1,20 @@ {-# LANGUAGE UnicodeSyntax #-} module Main where -import Math.Geometry.GridQC ( test )+import Math.Geometry.Grid.TriangularQC ( test )+import Math.Geometry.Grid.SquareQC ( test )+import Math.Geometry.Grid.HexagonalQC ( test )+import Math.Geometry.Grid.OctagonalQC ( test ) import Test.Framework as TF ( defaultMain, Test ) tests ∷ [TF.Test] tests = [ - Math.Geometry.GridQC.test+ Math.Geometry.Grid.TriangularQC.test,+ Math.Geometry.Grid.SquareQC.test,+ Math.Geometry.Grid.HexagonalQC.test,+ Math.Geometry.Grid.OctagonalQC.test ] main ∷ IO ()
test/Math/Geometry/GridQC.hs view
@@ -1,1059 +1,353 @@ {-# LANGUAGE UnicodeSyntax, FlexibleContexts, ExistentialQuantification,- TypeFamilies #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Math.Geometry.GridQC- (- test- ) where--import Math.Geometry.GridInternal --import Prelude hiding (null)-import qualified Prelude as P (null)-import Data.Eq.Unicode ((≡), (≠))-import Data.List (delete, nub, sort)-import Data.Ord.Unicode ((≤))-import qualified Math.Combinatorics.Exact.Binomial as M (choose)-import Test.Framework as TF (Test, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck - ((==>), Gen, Arbitrary, arbitrary, sized, choose, Property, property)---- | @'isqrt' n@ returns the greatest integer not greater than the square root --- of @n@.-isqrt ∷ Int → Int-isqrt n = (floor . sqrt) n'- where n' = fromIntegral n ∷ Float---- Given an arbitrary integer, select a corresponding point in the grid.-pointAt ∷ Grid g ⇒ g → Int → Index g-pointAt g i = indices g !! (i `mod` n)- where n = (length . indices) g--minPathCount- ∷ (Eq (Index g), Grid g) ⇒ g → Index g → Index g → Int-minPathCount g a b = length . minimalPaths g a $ b--minPathCount2- ∷ (Eq (Index g), Grid g) ⇒ g → [Index g] → Index g → Int-minPathCount2 g as b = sum . map (\x → minPathCount g x b) $ as--neighbourCount ∷ ∀ g. Grid g ⇒ g → Index g → Int-neighbourCount g x = length . neighbours g $ x------- Tests that should apply to and are identical for all grids-----prop_distance_reflexive ∷ Grid g ⇒ g → Int → Property-prop_distance_reflexive g i = nonNull g ==> distance g a a ≡ 0- where a = g `pointAt` i--prop_distance_symmetric ∷ Grid g ⇒ g → Int → Int → Property-prop_distance_symmetric g i j = - nonNull g ==> distance g a b ≡ distance g b a- where a = g `pointAt` i- b = g `pointAt` j---- "cw" = "consistent with"--prop_minDistance_cw_distance ∷ Grid g ⇒ g → Int → [Int] → Property-prop_minDistance_cw_distance g i js = - nonNull g && (not . P.null) js ==> - minDistance g (b:bs) a ≤ distance g b a- where a = g `pointAt` i- (b:bs) = map (g `pointAt`) js--prop_neighbours_cw_viewpoint - ∷ (Grid g, Ord (Index g)) ⇒ - g → Int → Property-prop_neighbours_cw_viewpoint g i = nonNull g ==> - sort (delete a (neighbours g a)) ≡ sort expected- where a = g `pointAt` i- expected = map fst $ filter (\p → 1 ≡ snd p) $ viewpoint g a--- Note: In a small but unbounded grid, a tile can be its own neighbour.--- However, when we calculate the distance between a tile and itself, we--- get 0, not 1. That's why we have to delete the tile from its list --- before comparing to the result from the neighbours function.--prop_edges_cw_neighbours ∷ (Grid g, Ord (Index g)) ⇒ g → Int → Property-prop_edges_cw_neighbours g i = nonNull g ==> - sort (neighbours g a) ≡ sort expected- where a = g `pointAt` i- nEdges = filter (`involves` a) $ edges g- expected = map f nEdges- f (b,c) = if a ≡ b then c else b--involves ∷ Eq a ⇒ (a, a) → a → Bool-involves (a, b) c = c ≡ a || c ≡ b--prop_edges_are_adjacent ∷ (Grid g, Ord (Index g)) ⇒ g → Property-prop_edges_are_adjacent g = property $ all f $ edges g- where f (a, b) = isAdjacent g a b--prop_adjacentTilesToward_moves_closer - ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property-prop_adjacentTilesToward_moves_closer g i j = nonNull g && a ≠ b ==> - ns ≡ [d-1]- where a = g `pointAt` i- b = g `pointAt` j- d = distance g a b- ns = nub $ map (\x → distance g x b) $ adjacentTilesToward g a b--prop_minimal_paths_have_min_length - ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property-prop_minimal_paths_have_min_length g i j = nonNull g ==> ns ≡ [d+1]- where a = g `pointAt` i- b = g `pointAt` j- d = distance g a b- ns = nub $ map length $ minimalPaths g a b--prop_minimal_paths_are_valid - ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property-prop_minimal_paths_are_valid g i j = nonNull g ==> - and $ map (subsequentTilesInPathAreAdjacent g) $ minimalPaths g a b- where a = g `pointAt` i- b = g `pointAt` j--subsequentTilesInPathAreAdjacent - ∷ (Grid g, Eq (Index g)) ⇒ g → [Index g] → Bool-subsequentTilesInPathAreAdjacent _ [] = True-subsequentTilesInPathAreAdjacent g [x] = x `elem` indices g-subsequentTilesInPathAreAdjacent g (a:b:xs) = - isAdjacent g a b && subsequentTilesInPathAreAdjacent g (b:xs)------- Tests that should apply to and are identical for all bounded grids-----prop_grid_and_boundary_are_both_null_or_not - ∷ BoundedGrid g ⇒ g → Property-prop_grid_and_boundary_are_both_null_or_not g = property $- (P.null . boundary) g ≡ null g--prop_boundary_in_grid ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Property-prop_boundary_in_grid g = property $- all (g `contains`) . boundary $ g--prop_boundary_tiles_have_fewer_neighbours - ∷ BoundedGrid g ⇒ g → Int → Property-prop_boundary_tiles_have_fewer_neighbours g i = nonNull g ==>- g `numNeighbours` b ≤ g `numNeighbours` a- where a = g `pointAt` i- (b:_) = boundary g--prop_centres_equidistant_from_boundary ∷ BoundedGrid g ⇒ g → Property-prop_centres_equidistant_from_boundary g = nonNull g ==>- (length . nub . map (minDistance g bs)) cs ≡ 1- where bs = boundary g- cs = centre g--prop_centres_farthest_from_boundary - ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Int → Property-prop_centres_farthest_from_boundary g i = - nonNull g && (not . isCentre g) a ==>- minDistance g bs a ≤ minDistance g bs c- where a = g `pointAt` i- (c:_) = centre g- bs = boundary g------- Triangular grids with triangular tiles------- We want the number of tiles in a test grid to be O(n)-sizedTriTriGrid ∷ Int → Gen TriTriGrid-sizedTriTriGrid n = return $ triTriGrid (2 * isqrt n)--instance Arbitrary TriTriGrid where- arbitrary = sized sizedTriTriGrid- -prop_TriTriGrid_tile_count_correct ∷ TriTriGrid → Property-prop_TriTriGrid_tile_count_correct g = property $ - (length . indices) g ≡ if s ≤ 0 then 0 else s*s- where s = size g--prop_TriTriGrid_distance_in_bounds ∷ TriTriGrid → Int → Int → Property-prop_TriTriGrid_distance_in_bounds g i j = nonNull g ==> - distance g a b ≤ 2*(s-1)- where s = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by triTriGrid is ever changed, this property--- may need to be changed too. It relies on the first and last elements being--- at corners.-prop_TriTriGrid_distance_edge_to_edge ∷ TriTriGrid → Property-prop_TriTriGrid_distance_edge_to_edge g = s > 0 ==> distance g a b ≡ 2*(s-1)- where ps = indices g- a = head ps- b = last ps- s = size g--prop_TriTriGrid_neighbour_count_in_bounds ∷ TriTriGrid → Int → Property-prop_TriTriGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 3- where x = g `pointAt` i--prop_TriTriGrid_boundary_count_correct ∷ TriTriGrid → Property-prop_TriTriGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (f . size) g- where f 0 = 0- f 1 = 1- f s = 3*(s-1)--prop_TriTriGrid_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Property-prop_TriTriGrid_boundary_tiles_have_fewer_neighbours g = property $- all (3>) . map (numNeighbours g) . boundary $ g------- Parallelogram-shaped grids with triangular tiles------- We want the number of tiles in a test grid to be O(n)-sizedParaTriGrid ∷ Int → Gen ParaTriGrid-sizedParaTriGrid n = do- r ← choose (0,n)- let c = n `div` (2*r + 1)- return $ paraTriGrid r c--instance Arbitrary ParaTriGrid where- arbitrary = sized sizedParaTriGrid--prop_ParaTriGrid_tile_count_correct ∷ ParaTriGrid → Property-prop_ParaTriGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else 2*r*c- where (r, c) = size g--prop_ParaTriGrid_distance_in_bounds ∷ ParaTriGrid → Int → Int → Property-prop_ParaTriGrid_distance_in_bounds g i j = nonNull g ==> - distance g a b ≤ 2*(r+c) - 3- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by paraTriGrid is ever changed, this--- property may need to be changed too. It relies on the first and last --- elements being at corners.-prop_ParaTriGrid_distance_corner_to_corner ∷ ParaTriGrid → Property-prop_ParaTriGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - distance g a b ≡ 2*(r+c) - 3- where ps = indices g- a = head ps- b = last ps- (r, c) = size g--prop_ParaTriGrid_neighbour_count_in_bounds ∷ ParaTriGrid → Int → Property-prop_ParaTriGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 3- where x = g `pointAt` i--prop_ParaTriGrid_boundary_count_correct ∷ ParaTriGrid → Property-prop_ParaTriGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (f . size) g- where f (0,_) = 0- f (_,0) = 0- f (1,c) = 2*c- f (r,1) = 2*r- f (r,c) = 2*(r+c-1)--prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours ∷ ParaTriGrid → Property-prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours g = property $- all (3>) . map (numNeighbours g) . boundary $ g------- Rectangular grids with triangular tiles------- We want the number of tiles in a test grid to be O(n)-sizedRectTriGrid ∷ Int → Gen RectTriGrid-sizedRectTriGrid n = do- r ← choose (0,n)- let c = n `div` (2*r + 1)- return $ rectTriGrid r c--instance Arbitrary RectTriGrid where- arbitrary = sized sizedRectTriGrid--prop_RectTriGrid_tile_count_correct ∷ RectTriGrid → Property-prop_RectTriGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else 2*r*c- where (r, c) = size g--prop_RectTriGrid_distance_in_bounds ∷ RectTriGrid → Int → Int → Property-prop_RectTriGrid_distance_in_bounds g i j = nonNull g ==> - distance g a b ≤ 2*(r+c) - 3- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j--prop_RectTriGrid_neighbour_count_in_bounds ∷ RectTriGrid → Int → Property-prop_RectTriGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 3- where x = g `pointAt` i--prop_RectTriGrid_boundary_count_correct ∷ RectTriGrid → Property-prop_RectTriGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (f . size) g- where f (0,_) = 0- f (_,0) = 0- f (1,c) = 2*c- f (r,1) = 2*r- f (r,c) = 2*(r+c-1)--prop_RectTriGrid_boundary_tiles_have_fewer_neighbours ∷ RectTriGrid → Property-prop_RectTriGrid_boundary_tiles_have_fewer_neighbours g = property $- all (3>) . map (numNeighbours g) . boundary $ g------- Toroidal grids with triangular tiles------- We want the number of tiles in a test grid to be O(n)-sizedTorTriGrid ∷ Int → Gen TorTriGrid-sizedTorTriGrid n = do- r0 ← choose (0,n `div` 2)- let r = 2*r0- let c = n `div` (2*r + 1)- return $ torTriGrid r c--instance Arbitrary TorTriGrid where- arbitrary = sized sizedTorTriGrid--prop_TorTriGrid_tile_count_correct ∷ TorTriGrid → Property-prop_TorTriGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else 2*r*c- where (r, c) = size g--prop_TorTriGrid_distance_in_bounds ∷ TorTriGrid → Int → Int → Property-prop_TorTriGrid_distance_in_bounds g i j = nonNull g ==> - distance g a b ≤ 2*(r+c) - 3- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j--prop_TorTriGrid_neighbour_count_in_bounds ∷ TorTriGrid → Int → Property-prop_TorTriGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 3- where x = g `pointAt` i------- Rectangular grids with square tiles------- We want the number of tiles in a test grid to be O(n)-sizedRectSquareGrid ∷ Int → Gen RectSquareGrid-sizedRectSquareGrid n = do- r ← choose (0,n)- let c = n `div` (r+1)- return $ rectSquareGrid r c--instance Arbitrary RectSquareGrid where- arbitrary = sized sizedRectSquareGrid--prop_RectSquareGrid_tile_count_correct ∷ RectSquareGrid → Property-prop_RectSquareGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c- where (r, c) = size g--prop_RectSquareGrid_distance_in_bounds ∷ RectSquareGrid → Int → Int → Property-prop_RectSquareGrid_distance_in_bounds g i j = nonNull g ==>- distance g a b ≤ r + c - 2- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by rectSquareGrid is ever changed, this--- property may need to be changed too. It relies on the first and last --- elements being at opposite corners.-prop_RectSquareGrid_distance_corner_to_corner ∷ RectSquareGrid → Property-prop_RectSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - distance g a b ≡ r + c - 2- where (r, c) = size g- ps = indices g- a = head ps- b = last ps--prop_RectSquareGrid_neighbour_count_in_bounds ∷ - RectSquareGrid → Int → Property-prop_RectSquareGrid_neighbour_count_in_bounds g i = nonNull g ==> - neighbourCount g x ≤ 4- where x = g `pointAt` i--prop_RectSquareGrid_num_min_paths_correct ∷ - RectSquareGrid → Int → Int → Property-prop_RectSquareGrid_num_min_paths_correct g i j = nonNull g ==>- minPathCount g a b ≡ M.choose (deltaX+deltaY) deltaX- where a = g `pointAt` i- b = g `pointAt` j- deltaX = abs $ fst b - fst a- deltaY = abs $ snd b - snd a--prop_RectSquareGrid_boundary_count_correct ∷ RectSquareGrid → Property-prop_RectSquareGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (cartesianBoundaryCount . size) g--cartesianBoundaryCount ∷ (Eq a, Num a) ⇒ (a, a) → a-cartesianBoundaryCount (0,_) = 0-cartesianBoundaryCount (_,0) = 0-cartesianBoundaryCount (1,c) = c-cartesianBoundaryCount (r,1) = r-cartesianBoundaryCount (r,c) = 2*(r+c) - 4--prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours ∷ RectSquareGrid → Property-prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours g = property $- all (4>) . map (numNeighbours g) . boundary $ g-------- Toroidal grids with square tiles------- We want the number of tiles in a test grid to be O(n)-sizedTorSquareGrid ∷ Int → Gen TorSquareGrid-sizedTorSquareGrid n = do- r ← choose (0,n)- let c = n `div` (r+1)- return $ torSquareGrid r c--instance Arbitrary TorSquareGrid where- arbitrary = sized sizedTorSquareGrid--prop_TorSquareGrid_tile_count_correct ∷ TorSquareGrid → Property-prop_TorSquareGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c- where (r, c) = size g--prop_TorSquareGrid_distance_in_bounds ∷ TorSquareGrid → Int → Int → Property-prop_TorSquareGrid_distance_in_bounds g i j = nonNull g ==>- distance g a b ≤ (r+c) `div` 2- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by torSquareGrid is ever changed, this property--- may need to be changed too.-prop_TorSquareGrid_distance_corner_to_corner ∷ TorSquareGrid → Property-prop_TorSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - distance g a b ≡ f- where (r, c) = size g- ps = indices g- a = head ps- b = last ps- f | r ≡ 1 && c ≡ 1 = 0 -- single-tile torus- | r ≡ 1 || c ≡ 1 = 1 -- a and b are the same- | otherwise = 2--prop_TorSquareGrid_neighbour_count_in_bounds ∷ TorSquareGrid → Int → Property-prop_TorSquareGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 4- where x = g `pointAt` i------- Circular hexagonal grids ------- We want the number of tiles in a test grid to be O(n)-sizedHexHexGrid ∷ Int → Gen HexHexGrid-sizedHexHexGrid n = return $ hexHexGrid s- where s = isqrt (n `div` 3)--instance Arbitrary HexHexGrid where- arbitrary = sized sizedHexHexGrid--prop_HexHexGrid_tile_count_correct ∷ HexHexGrid → Property-prop_HexHexGrid_tile_count_correct g = property $ - (length . indices) g ≡ if s ≤ 0 then 0 else 3*s*(s-1) + 1- where s = size g--prop_HexHexGrid_distance_in_bounds ∷ HexHexGrid → Int → Int → Property-prop_HexHexGrid_distance_in_bounds g i j = nonNull g ==>- distance g a b < 2*s- where s = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by hexHexGrid is ever changed, this property--- may need to be changed too. It relies on the first and last elements being--- on opposite edges.-prop_HexHexGrid_distance_edge_to_edge ∷ HexHexGrid → Property-prop_HexHexGrid_distance_edge_to_edge g = s > 0 ==> distance g a b ≡ 2*s - 2- where ps = indices g- a = head ps- b = last ps- s = size g--prop_HexHexGrid_neighbour_count_in_bounds ∷ HexHexGrid → Int → Property-prop_HexHexGrid_neighbour_count_in_bounds g i = nonNull g ==> - neighbourCount g x ≤ 6- where x = g `pointAt` i--prop_HexHexGrid_boundary_count_correct ∷ HexHexGrid → Property-prop_HexHexGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (f . size) g- where f 0 = 0- f 1 = 1- f s = 6*(s-1)--prop_HexHexGrid_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Property-prop_HexHexGrid_boundary_tiles_have_fewer_neighbours g = property $- all (5>) . map (numNeighbours g) . boundary $ g-------- Parallelogrammatical hexagonal grids ------- We want the number of tiles in a test grid to be O(n)-sizedParaHexGrid ∷ Int → Gen ParaHexGrid-sizedParaHexGrid n = do- r ← choose (0,n)- let c = n `div` (r+1)- return $ paraHexGrid r c--instance Arbitrary ParaHexGrid where- arbitrary = sized sizedParaHexGrid--prop_ParaHexGrid_tile_count_correct ∷ ParaHexGrid → Property-prop_ParaHexGrid_tile_count_correct g = property $ - tileCount g ≡ r*c- where (r, c) = size g--prop_ParaHexGrid_distance_in_bounds ∷ ParaHexGrid → Int → Int → Property-prop_ParaHexGrid_distance_in_bounds g i j = nonNull g ==>- property $ distance g a b ≤ r+c-2- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by paraHexGrid is ever changed, this property--- may need to be changed too. It relies on the first and last elements being--- at opposite corners on the longer diagonal.-prop_ParaHexGrid_distance_corner_to_corner ∷ ParaHexGrid → Property-prop_ParaHexGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - distance g a b ≡ r+c-2- where ps = indices g- a = head ps- b = last ps- (r, c) = size g--prop_ParaHexGrid_neighbour_count_in_bounds ∷ ParaHexGrid → Int → Property-prop_ParaHexGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 6- where x = g `pointAt` i--prop_ParaHexGrid_boundary_count_correct ∷ ParaHexGrid → Property-prop_ParaHexGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (cartesianBoundaryCount . size) g--prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Property-prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours g = property $- all (5>) . map (numNeighbours g) . boundary $ g------- Rectangular grids with octagonal tiles------- We want the number of tiles in a test grid to be O(n)-sizedRectOctGrid ∷ Int → Gen RectOctGrid-sizedRectOctGrid n = do- let n' = min n 12 -- calculation time for these grids grows quickly!- r ← choose (0,n')- let c = n' `div` (r+1)- return $ rectOctGrid r c--instance Arbitrary RectOctGrid where- arbitrary = sized sizedRectOctGrid--prop_RectOctGrid_tile_count_correct ∷ RectOctGrid → Property-prop_RectOctGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c- where (r, c) = size g--prop_RectOctGrid_distance_in_bounds ∷ RectOctGrid → Int → Int → Property-prop_RectOctGrid_distance_in_bounds g i j = nonNull g ==>- distance g a b ≤ max r c- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by rectOctGrid is ever changed, this--- property may need to be changed too. It relies on the first and last --- elements being at opposite corners.-prop_RectOctGrid_distance_corner_to_corner ∷ RectOctGrid → Property-prop_RectOctGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - a ≡ b || distance g a b ≡ (max r c) - 1- where (r, c) = size g- ps = indices g- a = head ps- b = last ps--prop_RectOctGrid_neighbour_count_in_bounds ∷ - RectOctGrid → Int → Property-prop_RectOctGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 8- where x = g `pointAt` i--prop_RectOctGrid_num_min_paths_correct ∷ - RectOctGrid → Int → Int → Property-prop_RectOctGrid_num_min_paths_correct g i j = nonNull g ==>- minPathCount g a b ≡- if a ≡ b then 1 else minPathCount2 g att b- where a = g `pointAt` i- b = g `pointAt` j- att = adjacentTilesToward g a b--prop_RectOctGrid_boundary_count_correct ∷ RectOctGrid → Property-prop_RectOctGrid_boundary_count_correct g = property $- (length . boundary) g ≡ (cartesianBoundaryCount . size) g--prop_RectOctGrid_boundary_tiles_have_fewer_neighbours ∷ RectOctGrid → Property-prop_RectOctGrid_boundary_tiles_have_fewer_neighbours g = property $- all (6>) . map (numNeighbours g) . boundary $ g-------- Toroidal grids with octagonal tiles------- We want the number of tiles in a test grid to be O(n)-sizedTorOctGrid ∷ Int → Gen TorOctGrid-sizedTorOctGrid n = do- r ← choose (0,n)- let c = n `div` (r+1)- return $ torOctGrid r c--instance Arbitrary TorOctGrid where- arbitrary = sized sizedTorOctGrid--prop_TorOctGrid_tile_count_correct ∷ TorOctGrid → Property-prop_TorOctGrid_tile_count_correct g = property $ - tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c- where (r, c) = size g--prop_TorOctGrid_distance_in_bounds ∷ TorOctGrid → Int → Int → Property-prop_TorOctGrid_distance_in_bounds g i j = nonNull g ==>- distance g a b ≤ min r c + abs (r-c)- where (r, c) = size g- a = g `pointAt` i- b = g `pointAt` j---- If the ordering produced by torOctGrid is ever changed, this property--- may need to be changed too.-prop_TorOctGrid_distance_corner_to_corner ∷ TorOctGrid → Property-prop_TorOctGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> - distance g a b ≡ if tileCount g ≡ 1 then 0 else 1- where (r, c) = size g- ps = indices g- a = head ps- b = last ps--prop_TorOctGrid_neighbour_count_in_bounds ∷ TorOctGrid → Int → Property-prop_TorOctGrid_neighbour_count_in_bounds g i = nonNull g ==>- neighbourCount g x ≤ 8- where x = g `pointAt` i---test ∷ Test-test = testGroup "Math.Geometry.GridQC"- [- -- TriTriGrid tests- testProperty "prop_TriTriGrid_tile_count_correct"- prop_TriTriGrid_tile_count_correct,- testProperty "prop_distance_reflexive - TriTriGrid"- (prop_distance_reflexive ∷ TriTriGrid → Int → Property),- testProperty "prop_distance_symmetric - TriTriGrid"- (prop_distance_symmetric ∷ TriTriGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - TriTriGrid"- (prop_minDistance_cw_distance ∷ TriTriGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - TriTriGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ TriTriGrid → Property),- testProperty "prop_boundary_in_grid - TriTriGrid"- (prop_boundary_in_grid ∷ TriTriGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - TriTriGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Int → Property),- testProperty "prop_TriTriGrid_boundary_count_correct"- prop_TriTriGrid_boundary_count_correct,- testProperty "prop_TriTriGrid_boundary_tiles_have_fewer_neighbours"- prop_TriTriGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - TriTriGrid"- (prop_centres_equidistant_from_boundary ∷ TriTriGrid → Property),- testProperty "prop_centres_farthest_from_boundary - TriTriGrid"- (prop_centres_farthest_from_boundary ∷ TriTriGrid → Int → Property),- testProperty "prop_TriTriGrid_distance_in_bounds"- prop_TriTriGrid_distance_in_bounds,- testProperty "prop_TriTriGrid_distance_edge_to_edge"- prop_TriTriGrid_distance_edge_to_edge,- testProperty "prop_TriTriGrid_neighbour_count_in_bounds"- prop_TriTriGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - TriTriGrid"- (prop_neighbours_cw_viewpoint ∷ TriTriGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - TriTriGrid"- (prop_edges_cw_neighbours ∷ TriTriGrid → Int → Property),- testProperty "prop_edges_are_adjacent - TriTriGrid"- (prop_edges_are_adjacent ∷ TriTriGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - TriTriGrid"- (prop_adjacentTilesToward_moves_closer ∷ - TriTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - TriTriGrid"- (prop_minimal_paths_have_min_length ∷ - TriTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - TriTriGrid"- (prop_minimal_paths_are_valid ∷ TriTriGrid → Int → Int → Property),-- -- ParaTriGrid tests- testProperty "prop_ParaTriGrid_tile_count_correct"- prop_ParaTriGrid_tile_count_correct,- testProperty "prop_distance_reflexive - ParaTriGrid"- (prop_distance_reflexive ∷ ParaTriGrid → Int → Property),- testProperty "prop_distance_symmetric - ParaTriGrid"- (prop_distance_symmetric ∷ ParaTriGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - ParaTriGrid"- (prop_minDistance_cw_distance ∷ ParaTriGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - ParaTriGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ ParaTriGrid → Property),- testProperty "prop_boundary_in_grid - ParaTriGrid"- (prop_boundary_in_grid ∷ ParaTriGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - ParaTriGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ ParaTriGrid → Int → Property),- testProperty "prop_ParaTriGrid_boundary_count_correct"- prop_ParaTriGrid_boundary_count_correct,- testProperty "prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours"- prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - ParaTriGrid"- (prop_centres_equidistant_from_boundary ∷ ParaTriGrid → Property),- testProperty "prop_centres_farthest_from_boundary - ParaTriGrid"- (prop_centres_farthest_from_boundary ∷ ParaTriGrid → Int → Property),- testProperty "prop_ParaTriGrid_distance_in_bounds"- prop_ParaTriGrid_distance_in_bounds,- testProperty "prop_ParaTriGrid_distance_corner_to_corner"- prop_ParaTriGrid_distance_corner_to_corner,- testProperty "prop_ParaTriGrid_neighbour_count_in_bounds"- prop_ParaTriGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - ParaTriGrid"- (prop_neighbours_cw_viewpoint ∷ ParaTriGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - ParaTriGrid"- (prop_edges_cw_neighbours ∷ ParaTriGrid → Int → Property),- testProperty "prop_edges_are_adjacent - ParaTriGrid"- (prop_edges_are_adjacent ∷ ParaTriGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - ParaTriGrid"- (prop_adjacentTilesToward_moves_closer ∷ - ParaTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - ParaTriGrid"- (prop_minimal_paths_have_min_length ∷ - ParaTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - ParaTriGrid"- (prop_minimal_paths_are_valid ∷ ParaTriGrid → Int → Int → Property),-- -- RectTriGrid tests- testProperty "prop_RectTriGrid_tile_count_correct"- prop_RectTriGrid_tile_count_correct,- testProperty "prop_distance_reflexive - RectTriGrid"- (prop_distance_reflexive ∷ RectTriGrid → Int → Property),- testProperty "prop_distance_symmetric - RectTriGrid"- (prop_distance_symmetric ∷ RectTriGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - RectTriGrid"- (prop_minDistance_cw_distance ∷ RectTriGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - RectTriGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ RectTriGrid → Property),- testProperty "prop_boundary_in_grid - RectTriGrid"- (prop_boundary_in_grid ∷ RectTriGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - RectTriGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ RectTriGrid → Int → Property),- testProperty "prop_RectTriGrid_boundary_count_correct"- prop_RectTriGrid_boundary_count_correct,- testProperty "prop_RectTriGrid_boundary_tiles_have_fewer_neighbours"- prop_RectTriGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - RectTriGrid"- (prop_centres_equidistant_from_boundary ∷ RectTriGrid → Property),- testProperty "prop_centres_farthest_from_boundary - RectTriGrid"- (prop_centres_farthest_from_boundary ∷ RectTriGrid → Int → Property),- testProperty "prop_RectTriGrid_distance_in_bounds"- prop_RectTriGrid_distance_in_bounds,- testProperty "prop_RectTriGrid_neighbour_count_in_bounds"- prop_RectTriGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - RectTriGrid"- (prop_neighbours_cw_viewpoint ∷ RectTriGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - RectTriGrid"- (prop_edges_cw_neighbours ∷ RectTriGrid → Int → Property),- testProperty "prop_edges_are_adjacent - RectTriGrid"- (prop_edges_are_adjacent ∷ RectTriGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - RectTriGrid"- (prop_adjacentTilesToward_moves_closer ∷ - RectTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - RectTriGrid"- (prop_minimal_paths_have_min_length ∷ - RectTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - RectTriGrid"- (prop_minimal_paths_are_valid ∷ RectTriGrid → Int → Int → Property),-- -- TorTriGrid tests- testProperty "prop_TorTriGrid_tile_count_correct"- prop_TorTriGrid_tile_count_correct,- testProperty "prop_distance_reflexive - TorTriGrid"- (prop_distance_reflexive ∷ TorTriGrid → Int → Property),- testProperty "prop_distance_symmetric - TorTriGrid"- (prop_distance_symmetric ∷ TorTriGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - TorTriGrid"- (prop_minDistance_cw_distance ∷ TorTriGrid → Int → [Int] → Property),- testProperty "prop_TorTriGrid_distance_in_bounds"- prop_TorTriGrid_distance_in_bounds,- testProperty "prop_TorTriGrid_neighbour_count_in_bounds"- prop_TorTriGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - TorTriGrid"- (prop_neighbours_cw_viewpoint ∷ TorTriGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - TorTriGrid"- (prop_edges_cw_neighbours ∷ TorTriGrid → Int → Property),- testProperty "prop_edges_are_adjacent - TorTriGrid"- (prop_edges_are_adjacent ∷ TorTriGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - TorTriGrid"- (prop_adjacentTilesToward_moves_closer ∷ - TorTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - TorTriGrid"- (prop_minimal_paths_have_min_length ∷ - TorTriGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - TorTriGrid"- (prop_minimal_paths_are_valid ∷ TorTriGrid → Int → Int → Property),-- -- RectSquareGrid tests- testProperty "prop_RectSquareGrid_tile_count_correct"- prop_RectSquareGrid_tile_count_correct,- testProperty "prop_distance_reflexive - RectSquareGrid"- (prop_distance_reflexive ∷ RectSquareGrid → Int → Property),- testProperty "prop_distance_symmetric - RectSquareGrid"- (prop_distance_symmetric ∷ RectSquareGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - RectSquareGrid"- (prop_minDistance_cw_distance ∷ RectSquareGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - RectSquareGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ RectSquareGrid → Property),- testProperty "prop_boundary_in_grid - RectSquareGrid"- (prop_boundary_in_grid ∷ RectSquareGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - RectSquareGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ RectSquareGrid → Int → Property),- testProperty "prop_RectSquareGrid_boundary_count_correct"- prop_RectSquareGrid_boundary_count_correct,- testProperty "prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours"- prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - RectSquareGrid"- (prop_centres_equidistant_from_boundary ∷ RectSquareGrid → Property),- testProperty "prop_centres_farthest_from_boundary - RectSquareGrid"- (prop_centres_farthest_from_boundary ∷ RectSquareGrid → Int → Property),- testProperty "prop_RectSquareGrid_distance_in_bounds"- prop_RectSquareGrid_distance_in_bounds,- testProperty "prop_RectSquareGrid_distance_corner_to_corner"- prop_RectSquareGrid_distance_corner_to_corner,- testProperty "prop_RectSquareGrid_neighbour_count_in_bounds"- prop_RectSquareGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - RectSquareGrid"- (prop_neighbours_cw_viewpoint ∷ RectSquareGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - RectSquareGrid"- (prop_edges_cw_neighbours ∷ RectSquareGrid → Int → Property),- testProperty "prop_edges_are_adjacent - RectSquareGrid"- (prop_edges_are_adjacent ∷ RectSquareGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - RectSquareGrid"- (prop_adjacentTilesToward_moves_closer ∷ - RectSquareGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - RectSquareGrid"- (prop_minimal_paths_have_min_length ∷ - RectSquareGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - RectSquareGrid"- (prop_minimal_paths_are_valid ∷ RectSquareGrid → Int → Int → Property),- testProperty "prop_RectSquareGrid_num_min_paths_correct"- prop_RectSquareGrid_num_min_paths_correct,-- -- TorSquareGrid tests- testProperty "prop_TorSquareGrid_tile_count_correct"- prop_TorSquareGrid_tile_count_correct,- testProperty "prop_distance_reflexive - TorSquareGrid"- (prop_distance_reflexive ∷ TorSquareGrid → Int → Property),- testProperty "prop_distance_symmetric - TorSquareGrid"- (prop_distance_symmetric ∷ TorSquareGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - TorSquareGrid"- (prop_minDistance_cw_distance ∷ TorSquareGrid → Int → [Int] → Property),- testProperty "prop_TorSquareGrid_distance_in_bounds"- prop_TorSquareGrid_distance_in_bounds,- testProperty "prop_TorSquareGrid_distance_corner_to_corner"- prop_TorSquareGrid_distance_corner_to_corner,- testProperty "prop_TorSquareGrid_neighbour_count_in_bounds"- prop_TorSquareGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - TorSquareGrid"- (prop_neighbours_cw_viewpoint ∷ TorSquareGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - TorSquareGrid"- (prop_edges_cw_neighbours ∷ TorSquareGrid → Int → Property),- testProperty "prop_edges_are_adjacent - TorSquareGrid"- (prop_edges_are_adjacent ∷ TorSquareGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - TorSquareGrid"- (prop_adjacentTilesToward_moves_closer ∷ - TorSquareGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - TorSquareGrid"- (prop_minimal_paths_have_min_length ∷ - TorSquareGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - TorSquareGrid"- (prop_minimal_paths_are_valid ∷ TorSquareGrid → Int → Int → Property),-- -- HexHexGrid tests- testProperty "prop_HexHexGrid_tile_count_correct"- prop_HexHexGrid_tile_count_correct,- testProperty "prop_distance_reflexive - HexHexGrid"- (prop_distance_reflexive ∷ HexHexGrid → Int → Property),- testProperty "prop_distance_symmetric - HexHexGrid"- (prop_distance_symmetric ∷ HexHexGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - HexHexGrid"- (prop_minDistance_cw_distance ∷ HexHexGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - HexHexGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ HexHexGrid → Property),- testProperty "prop_boundary_in_grid - HexHexGrid"- (prop_boundary_in_grid ∷ HexHexGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - HexHexGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Int → Property),- testProperty "prop_HexHexGrid_boundary_count_correct"- prop_HexHexGrid_boundary_count_correct,- testProperty "prop_HexHexGrid_boundary_tiles_have_fewer_neighbours"- prop_HexHexGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - HexHexGrid"- (prop_centres_equidistant_from_boundary ∷ HexHexGrid → Property),- testProperty "prop_centres_farthest_from_boundary - HexHexGrid"- (prop_centres_farthest_from_boundary ∷ HexHexGrid → Int → Property),- testProperty "prop_HexHexGrid_distance_in_bounds"- prop_HexHexGrid_distance_in_bounds,- testProperty "prop_HexHexGrid_distance_edge_to_edge"- prop_HexHexGrid_distance_edge_to_edge,- testProperty "prop_HexHexGrid_neighbour_count_in_bounds"- prop_HexHexGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - HexHexGrid"- (prop_neighbours_cw_viewpoint ∷ HexHexGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - HexHexGrid"- (prop_edges_cw_neighbours ∷ HexHexGrid → Int → Property),- testProperty "prop_edges_are_adjacent - HexHexGrid"- (prop_edges_are_adjacent ∷ HexHexGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - HexHexGrid"- (prop_adjacentTilesToward_moves_closer ∷ - HexHexGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - HexHexGrid"- (prop_minimal_paths_have_min_length ∷ - HexHexGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - HexHexGrid"- (prop_minimal_paths_are_valid ∷ HexHexGrid → Int → Int → Property),-- -- ParaHexGrid tests- testProperty "prop_ParaHexGrid_tile_count_correct"- prop_ParaHexGrid_tile_count_correct,- testProperty "prop_distance_reflexive - ParaHexGrid"- (prop_distance_reflexive ∷ ParaHexGrid → Int → Property),- testProperty "prop_distance_symmetric - ParaHexGrid"- (prop_distance_symmetric ∷ ParaHexGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - ParaHexGrid"- (prop_minDistance_cw_distance ∷ ParaHexGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - ParaHexGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ ParaHexGrid → Property),- testProperty "prop_boundary_in_grid - ParaHexGrid"- (prop_boundary_in_grid ∷ ParaHexGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - TriTriGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Int → Property),- testProperty "prop_ParaHexGrid_boundary_count_correct"- prop_ParaHexGrid_boundary_count_correct,- testProperty "prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours"- prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - ParaHexGrid"- (prop_centres_equidistant_from_boundary ∷ ParaHexGrid → Property),- testProperty "prop_centres_farthest_from_boundary - ParaHexGrid"- (prop_centres_farthest_from_boundary ∷ ParaHexGrid → Int → Property),- testProperty "prop_ParaHexGrid_distance_in_bounds"- prop_ParaHexGrid_distance_in_bounds,- testProperty "prop_ParaHexGrid_distance_corner_to_corner"- prop_ParaHexGrid_distance_corner_to_corner,- testProperty "prop_ParaHexGrid_neighbour_count_in_bounds"- prop_ParaHexGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - ParaHexGrid"- (prop_neighbours_cw_viewpoint ∷ ParaHexGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - ParaHexGrid"- (prop_edges_cw_neighbours ∷ ParaHexGrid → Int → Property),- testProperty "prop_adjacentTilesToward_moves_closer - ParaHexGrid"- (prop_adjacentTilesToward_moves_closer ∷ - ParaHexGrid → Int → Int → Property),- testProperty "prop_edges_are_adjacent - ParaHexGrid"- (prop_edges_are_adjacent ∷ ParaHexGrid → Property),- testProperty "prop_minimal_paths_have_min_length - ParaHexGrid"- (prop_minimal_paths_have_min_length ∷ - ParaHexGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - ParaHexGrid"- (prop_minimal_paths_are_valid ∷ ParaHexGrid → Int → Int → Property),-- -- RectOctGrid tests- testProperty "prop_RectOctGrid_tile_count_correct"- prop_RectOctGrid_tile_count_correct,- testProperty "prop_distance_reflexive - RectOctGrid"- (prop_distance_reflexive ∷ RectOctGrid → Int → Property),- testProperty "prop_distance_symmetric - RectOctGrid"- (prop_distance_symmetric ∷ RectOctGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - RectOctGrid"- (prop_minDistance_cw_distance ∷ RectOctGrid → Int → [Int] → Property),- testProperty "prop_grid_and_boundary_are_both_null_or_not - RectOctGrid"- (prop_grid_and_boundary_are_both_null_or_not ∷ RectOctGrid → Property),- testProperty "prop_boundary_in_grid - RectOctGrid"- (prop_boundary_in_grid ∷ RectOctGrid → Property),- testProperty "prop_boundary_tiles_have_fewer_neighbours - RectOctGrid"- (prop_boundary_tiles_have_fewer_neighbours ∷ RectOctGrid → Int → Property),- testProperty "prop_RectOctGrid_boundary_count_correct"- prop_RectOctGrid_boundary_count_correct,- testProperty "prop_RectOctGrid_boundary_tiles_have_fewer_neighbours"- prop_RectOctGrid_boundary_tiles_have_fewer_neighbours,- testProperty "prop_centres_equidistant_from_boundary - RectOctGrid"- (prop_centres_equidistant_from_boundary ∷ RectOctGrid → Property),- testProperty "prop_centres_farthest_from_boundary - RectOctGrid"- (prop_centres_farthest_from_boundary ∷ RectOctGrid → Int → Property),- testProperty "prop_RectOctGrid_distance_in_bounds"- prop_RectOctGrid_distance_in_bounds,- testProperty "prop_RectOctGrid_distance_corner_to_corner"- prop_RectOctGrid_distance_corner_to_corner,- testProperty "prop_RectOctGrid_neighbour_count_in_bounds"- prop_RectOctGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - RectOctGrid"- (prop_neighbours_cw_viewpoint ∷ RectOctGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - RectOctGrid"- (prop_edges_cw_neighbours ∷ RectOctGrid → Int → Property),- testProperty "prop_edges_are_adjacent - RectOctGrid"- (prop_edges_are_adjacent ∷ RectOctGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - RectOctGrid"- (prop_adjacentTilesToward_moves_closer ∷ - RectOctGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - RectOctGrid"- (prop_minimal_paths_have_min_length ∷ - RectOctGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - RectOctGrid"- (prop_minimal_paths_are_valid ∷ RectOctGrid → Int → Int → Property),- testProperty "prop_RectOctGrid_num_min_paths_correct"- prop_RectOctGrid_num_min_paths_correct,-- -- TorOctGrid tests- testProperty "prop_TorOctGrid_tile_count_correct"- prop_TorOctGrid_tile_count_correct,- testProperty "prop_distance_reflexive - TorOctGrid"- (prop_distance_reflexive ∷ TorOctGrid → Int → Property),- testProperty "prop_distance_symmetric - TorOctGrid"- (prop_distance_symmetric ∷ TorOctGrid → Int → Int → Property),- testProperty "prop_minDistance_cw_distance - TorOctGrid"- (prop_minDistance_cw_distance ∷ TorOctGrid → Int → [Int] → Property),- testProperty "prop_TorOctGrid_distance_in_bounds"- prop_TorOctGrid_distance_in_bounds,- testProperty "prop_TorOctGrid_distance_corner_to_corner"- prop_TorOctGrid_distance_corner_to_corner,- testProperty "prop_TorOctGrid_neighbour_count_in_bounds"- prop_TorOctGrid_neighbour_count_in_bounds,- testProperty "prop_neighbours_cw_viewpoint - TorOctGrid"- (prop_neighbours_cw_viewpoint ∷ TorOctGrid → Int → Property),- testProperty "prop_edges_cw_neighbours - TorOctGrid"- (prop_edges_cw_neighbours ∷ TorOctGrid → Int → Property),- testProperty "prop_edges_are_adjacent - TorOctGrid"- (prop_edges_are_adjacent ∷ TorOctGrid → Property),- testProperty "prop_adjacentTilesToward_moves_closer - TorOctGrid"- (prop_adjacentTilesToward_moves_closer ∷ - TorOctGrid → Int → Int → Property),- testProperty "prop_minimal_paths_have_min_length - TorOctGrid"- (prop_minimal_paths_have_min_length ∷ - TorOctGrid → Int → Int → Property),- testProperty "prop_minimal_paths_are_valid - TorOctGrid"- (prop_minimal_paths_are_valid ∷ TorOctGrid → Int → Int → Property)- ]+ TypeFamilies, MultiParamTypeClasses #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Math.Geometry.GridQC where++import Math.Geometry.GridInternal ++import Prelude hiding (null)+import qualified Prelude as P (null)+import Data.Eq.Unicode ((≡), (≠))+import Data.List (delete, nub, sort)+import Data.Ord.Unicode ((≤))+import Test.Framework as TF (Test)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck + ((==>), Gen, Arbitrary, arbitrary, choose, Property, property,+ vectorOf, elements)++-- | @'isqrt' n@ returns the greatest integer not greater than the square root +-- of @n@.+isqrt ∷ Int → Int+isqrt n = (floor . sqrt) n'+ where n' = fromIntegral n ∷ Float++-- Given an arbitrary integer, select a corresponding point in the grid.+pointAt ∷ Grid g ⇒ g → Int → Index g+pointAt g i = indices g !! (i `mod` n)+ where n = (length . indices) g++minPathCount+ ∷ (Eq (Index g), Grid g) ⇒ g → Index g → Index g → Int+minPathCount g a b = length . minimalPaths g a $ b++minPathCount2+ ∷ (Eq (Index g), Grid g) ⇒ g → [Index g] → Index g → Int+minPathCount2 g as b = sum . map (\x → minPathCount g x b) $ as++cartesianBoundaryCount ∷ (Eq a, Num a) ⇒ (a, a) → a+cartesianBoundaryCount (0,_) = 0+cartesianBoundaryCount (_,0) = 0+cartesianBoundaryCount (1,c) = c+cartesianBoundaryCount (r,1) = r+cartesianBoundaryCount (r,c) = 2*(r+c) - 4++involves ∷ Eq a ⇒ (a, a) → a → Bool+involves (a, b) c = c ≡ a || c ≡ b++chooseIndices ∷ Grid g ⇒ g → Int → Gen [Index g]+chooseIndices g n = do+ k ← choose (0,n)+ if null g + then return [] + else vectorOf (k+2) (elements . indices $ g)++chooseClosePointsUnbounded ∷ Gen ((Int, Int), (Int, Int))+chooseClosePointsUnbounded = do+ (x1,y1) ← arbitrary+ x2 ← choose (x1-2,x1+2)+ y2 ← choose (y1-2,y1+2)+ return ((x1,y1), (x2,y2))++chooseClosePoints ∷ Grid g ⇒ g → Gen (Index g, Index g)+chooseClosePoints g = do+ a ← elements . indices $ g+ b ← elements . filter (\b → distance g a b < 6) . indices $ g+ return (a, b)++makeTests ∷ (Arbitrary t, Show t) ⇒ [(String, t → Property)] → [Test]+makeTests ts = map (\(s,t) → testProperty s t) ts++--+-- Tests that should apply to and are identical for all grids+--++class TestData t where+ type BaseGrid t+ grid ∷ t → BaseGrid t+ points ∷ t → [Index (BaseGrid t)]+ neighbourCountBounds ∷ t → (Int, Int)+ twoClosePoints ∷ t → (Index (BaseGrid t),Index (BaseGrid t))++prop_indices_are_contained ∷ (TestData t, Grid (BaseGrid t), + Eq (Index (BaseGrid t))) ⇒ t → Property+prop_indices_are_contained t = nonNull g ==> g `contains` a+ where g = grid t+ (a:_) = points t++prop_distance_reflexive ∷ (TestData t, Grid (BaseGrid t)) ⇒ t → Property+prop_distance_reflexive t = nonNull g ==> distance g a a ≡ 0+ where g = grid t+ (a:_) = points t++prop_distance_symmetric ∷ (TestData t, Grid (BaseGrid t)) ⇒ t → Property+prop_distance_symmetric t = + nonNull g ==> distance g a b ≡ distance g b a+ where g = grid t+ (a:b:_) = points t++prop_custom_MinDistance_eq_default + ∷ (TestData t, Grid (BaseGrid t)) ⇒ t → Property+prop_custom_MinDistance_eq_default t = nonNull g ==> + minDistance g bs a ≡ defaultMinDistance g bs a+ where g = grid t+ (a:bs) = points t++-- "cw" = "consistent with"++prop_minDistance_cw_distance ∷ (TestData t, Grid (BaseGrid t)) ⇒ t → Property+prop_minDistance_cw_distance t = + nonNull g && (not . P.null) bs ==> + minDistance g (b:bs) a ≤ distance g b a+ where g = grid t+ (a:b:bs) = points t++prop_neighbour_count_in_bounds+ ∷ (TestData t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_neighbour_count_in_bounds t = nonNull g ==> + nMin ≤ n && n ≤ nMax+ where g = grid t+ (a:_) = points t+ n = length . neighbours g $ a+ (nMin, nMax) = neighbourCountBounds t++prop_neighbours_are_adjacent+ ∷ (TestData t, Grid (BaseGrid t))+ ⇒ t → Property+prop_neighbours_are_adjacent t = nonNull g ==> + and (map (isAdjacent g a) ns)+ where g = grid t+ (a:_) = points t+ ns = neighbours g a++prop_adjacentTilesToward_moves_closer+ ∷ (TestData t, Grid (BaseGrid t), Eq (Index (BaseGrid t)))+ ⇒ t → Property+prop_adjacentTilesToward_moves_closer t = nonNull g && a ≠ b ==> + and (map (< d) ns)+ where g = grid t+ (a:b:_) = points t+ d = distance g a b+ ns = nub $ map (\x → distance g x b) $ adjacentTilesToward g a b++prop_minimal_paths_have_min_length+ ∷ (TestData t, Grid (BaseGrid t), Eq (Index (BaseGrid t)))+ ⇒ t → Property+prop_minimal_paths_have_min_length t = nonNull g ==> ns ≡ [d+1]+ where g = grid t+ (a,b) = twoClosePoints t+ d = distance g a b+ ns = nub . map length . minimalPaths g a $ b++prop_minimal_paths_are_valid+ ∷ (TestData t, Grid (BaseGrid t), Eq (Index (BaseGrid t)))+ ⇒ t → Property+prop_minimal_paths_are_valid t = nonNull g ==> + and $ map (subsequentTilesInPathAreAdjacent g) $ minimalPaths g a b+ where g = grid t+ (a,b) = twoClosePoints t++subsequentTilesInPathAreAdjacent + ∷ (Grid g, Eq (Index g)) ⇒ g → [Index g] → Bool+subsequentTilesInPathAreAdjacent _ [] = True+subsequentTilesInPathAreAdjacent g [x] = g `contains` x+subsequentTilesInPathAreAdjacent g (a:b:xs) = + isAdjacent g a b && subsequentTilesInPathAreAdjacent g (b:xs)++prop_neighbour_cw_directionTo+ ∷ (TestData t, Grid (BaseGrid t), Eq (Index (BaseGrid t)), + Eq (Direction (BaseGrid t)))+ ⇒ t → Property+prop_neighbour_cw_directionTo t = nonNull g && a ≠ b ==> + (neighbour g a d) `elem` nextSteps+ where g = grid t+ (a,b) = twoClosePoints t+ d = head . directionTo g a $ b+ nextSteps = map (!!1) . minimalPaths g a $ b++gridProperties + ∷ (TestData t, Grid (BaseGrid t), Arbitrary t, + Eq (Index (BaseGrid t)), Ord (Index (BaseGrid t)), + Eq (Direction (BaseGrid t))) + ⇒ String → [(String, t → Property)]+gridProperties s = + [+ ("prop_indices_are_contained: " ++ s, prop_indices_are_contained),+ ("prop_distance_reflexive: " ++ s, prop_distance_reflexive),+ ("prop_distance_symmetric: " ++ s, prop_distance_symmetric),+ ("prop_custom_MinDistance_eq_default: " ++ s, prop_custom_MinDistance_eq_default),+ ("prop_minDistance_cw_distance: " ++ s, prop_minDistance_cw_distance),+ ("prop_neighbour_count_in_bounds: " ++ s, prop_neighbour_count_in_bounds),+ ("prop_neighbours_are_adjacent: " ++ s, prop_neighbours_are_adjacent),+ ("prop_adjacentTilesToward_moves_closer: " ++ s, prop_adjacentTilesToward_moves_closer),+ ("prop_minimal_paths_have_min_length: " ++ s, prop_minimal_paths_have_min_length),+ ("prop_minimal_paths_are_valid: " ++ s, prop_minimal_paths_are_valid),+ ("prop_neighbour_cw_directionTo: " ++ s, prop_neighbour_cw_directionTo)+ ]++--+-- Tests that should apply to and are identical for all finite grids+--++class TestDataF t where+ expectedTileCount ∷ t → Int+ maxDistance ∷ t → Int++prop_tile_count_correct+ ∷ (TestData t, TestDataF t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_tile_count_correct t = nonNull g ==>+ tileCount g ≡ expectedTileCount t + where g = grid t++prop_custom_tileCount_eq_default + ∷ (TestData t, Grid (BaseGrid t)) ⇒ t → Property+prop_custom_tileCount_eq_default t = nonNull g ==> + tileCount g ≡ defaultTileCount g+ where g = grid t++prop_distance_in_bounds+ ∷ (TestData t, TestDataF t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_distance_in_bounds t = nonNull g ==> + 0 ≤ n && n ≤ maxDistance t+ where g = grid t+ (a:b:_) = points t+ n = distance g a b++prop_neighbours_cw_viewpoint + ∷ (TestData t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_neighbours_cw_viewpoint t = nonNull g ==> + sort (delete a (neighbours g a)) ≡ sort expected+ where g = grid t+ (a:_) = points t+ expected = map fst $ filter (\p → 1 ≡ snd p) $ viewpoint g a+-- Note: In a small but unbounded grid, a tile can be its own neighbour.+-- However, when we calculate the distance between a tile and itself, we+-- get 0, not 1. That's why we have to delete the tile from its list +-- before comparing to the result from the neighbours function.++prop_custom_edges_eq_default + ∷ (TestData t, Grid (BaseGrid t), Eq (Index (BaseGrid t)), + Ord (Index (BaseGrid t))) ⇒ t → Property+prop_custom_edges_eq_default t = nonNull g ==> + sort (edges g) ≡ sort (defaultEdges g)+ where g = grid t++prop_edges_cw_neighbours+ ∷ (TestData t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_edges_cw_neighbours t = nonNull g ==> + sort (neighbours g a) ≡ sort expected+ where g = grid t+ (a:_) = points t+ nEdges = filter (`involves` a) $ edges g+ expected = map f nEdges+ f (b,c) = if a ≡ b then c else b++prop_edges_are_adjacent+ ∷ (TestData t, Grid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_edges_are_adjacent t = property $ all f $ edges g+ where g = grid t+ f (a, b) = isAdjacent g a b++finiteGridProperties + ∷ (TestData t, TestDataF t, Grid (BaseGrid t), Arbitrary t, + Eq (Index (BaseGrid t)), Ord (Index (BaseGrid t))) + ⇒ String → [(String, t → Property)]+finiteGridProperties s = + [+ ("prop_tile_count_correct: " ++ s, prop_tile_count_correct),+ ("prop_custom_tileCount_eq_default: " ++ s, prop_custom_tileCount_eq_default),+ ("prop_distance_in_bounds: " ++ s, prop_distance_in_bounds),+ ("prop_neighbours_cw_viewpoint: " ++ s, prop_neighbours_cw_viewpoint),+ ("prop_custom_edges_eq_default: " ++ s, prop_custom_edges_eq_default),+ ("prop_edges_cw_neighbours: " ++ s, prop_edges_cw_neighbours),+ ("prop_edges_are_adjacent: " ++ s, prop_edges_are_adjacent)+ ]++--+-- Tests that should apply to and are identical for all bounded grids+--++class TestDataB t where+ expectedBoundaryCount ∷ t → Int++prop_boundary_count_correct+ ∷ (TestData t, TestDataB t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_boundary_count_correct t = nonNull g ==>+ (length . boundary) g ≡ expectedBoundaryCount t + where g = grid t++prop_grid_and_boundary_are_both_null_or_not + ∷ (TestData t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_grid_and_boundary_are_both_null_or_not t = property $+ (P.null . boundary) g ≡ null g+ where g = grid t++prop_boundary_in_grid+ ∷ (TestData t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_boundary_in_grid t = property $+ all (g `contains`) . boundary $ g+ where g = grid t++prop_boundary_tiles_have_fewer_neighbours+ ∷ (TestData t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_boundary_tiles_have_fewer_neighbours t = nonNull g ==>+ g `numNeighbours` b ≤ g `numNeighbours` a+ where g = grid t+ (a:_) = points t+ (b:_) = boundary g++prop_centres_equidistant_from_boundary+ ∷ (TestData t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_centres_equidistant_from_boundary t = nonNull g ==>+ (length . nub . map (minDistance g bs)) cs ≡ 1+ where g = grid t+ bs = boundary g+ cs = centre g++prop_centres_farthest_from_boundary+ ∷ (TestData t, BoundedGrid (BaseGrid t), Ord (Index (BaseGrid t)))+ ⇒ t → Property+prop_centres_farthest_from_boundary t = + nonNull g && (not . isCentre g) a ==>+ minDistance g bs a ≤ minDistance g bs c+ where g = grid t+ (a:_) = points t+ (c:_) = centre g+ bs = boundary g++boundedGridProperties + ∷ (TestData t, TestDataB t, BoundedGrid (BaseGrid t), Arbitrary t, + Eq (Index (BaseGrid t)), Ord (Index (BaseGrid t))) + ⇒ String → [(String, t → Property)]+boundedGridProperties s = + [+ ("prop_boundary_count_correct: " ++ s, prop_boundary_count_correct),+ ("prop_grid_and_boundary_are_both_null_or_not: " ++ s, prop_grid_and_boundary_are_both_null_or_not),+ ("prop_boundary_in_grid: " ++ s, prop_boundary_in_grid),+ ("prop_boundary_tiles_have_fewer_neighbours: " ++ s, prop_boundary_tiles_have_fewer_neighbours),+ ("prop_centres_equidistant_from_boundary: " ++ s, prop_centres_equidistant_from_boundary),+ ("prop_centres_farthest_from_boundary: " ++ s, prop_centres_farthest_from_boundary)+ ]