packages feed

grid 3.1 → 4.0

raw patch · 6 files changed

+940/−414 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Math.Geometry.Grid: empty :: Grid g s x => g -> Bool
- Math.Geometry.Grid: nonEmpty :: Grid g s x => g -> Bool
- Math.Geometry.GridInternal: empty :: Grid g s x => g -> Bool
- Math.Geometry.GridInternal: instance BoundedGrid HexHexGrid Int (Int, Int)
- Math.Geometry.GridInternal: instance BoundedGrid ParaHexGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance BoundedGrid ParaTriGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance BoundedGrid RectSquareGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance BoundedGrid TriTriGrid Int (Int, Int)
- Math.Geometry.GridInternal: instance Constructor C1_0HexHexGrid
- Math.Geometry.GridInternal: instance Constructor C1_0ParaHexGrid
- Math.Geometry.GridInternal: instance Constructor C1_0ParaTriGrid
- Math.Geometry.GridInternal: instance Constructor C1_0RectSquareGrid
- Math.Geometry.GridInternal: instance Constructor C1_0TorSquareGrid
- Math.Geometry.GridInternal: instance Constructor C1_0TriTriGrid
- Math.Geometry.GridInternal: instance Datatype D1HexHexGrid
- Math.Geometry.GridInternal: instance Datatype D1ParaHexGrid
- Math.Geometry.GridInternal: instance Datatype D1ParaTriGrid
- Math.Geometry.GridInternal: instance Datatype D1RectSquareGrid
- Math.Geometry.GridInternal: instance Datatype D1TorSquareGrid
- Math.Geometry.GridInternal: instance Datatype D1TriTriGrid
- Math.Geometry.GridInternal: instance Generic HexHexGrid
- Math.Geometry.GridInternal: instance Generic ParaHexGrid
- Math.Geometry.GridInternal: instance Generic ParaTriGrid
- Math.Geometry.GridInternal: instance Generic RectSquareGrid
- Math.Geometry.GridInternal: instance Generic TorSquareGrid
- Math.Geometry.GridInternal: instance Generic TriTriGrid
- Math.Geometry.GridInternal: instance Grid HexHexGrid Int (Int, Int)
- Math.Geometry.GridInternal: instance Grid ParaHexGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance Grid ParaTriGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance Grid RectSquareGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance Grid TorSquareGrid (Int, Int) (Int, Int)
- Math.Geometry.GridInternal: instance Grid TriTriGrid Int (Int, Int)
- Math.Geometry.GridInternal: instance Serialize HexHexGrid
- Math.Geometry.GridInternal: instance Serialize ParaHexGrid
- Math.Geometry.GridInternal: instance Serialize ParaTriGrid
- Math.Geometry.GridInternal: instance Serialize RectSquareGrid
- Math.Geometry.GridInternal: instance Serialize TorSquareGrid
- Math.Geometry.GridInternal: instance Serialize TriTriGrid
- Math.Geometry.GridInternal: nonEmpty :: Grid g s x => g -> Bool
- Math.Geometry.GridMap: data GridMap g k v
- Math.Geometry.GridMap: empty :: Grid g s x => g -> Bool
- Math.Geometry.GridMap: fold :: (a -> b -> a) -> a -> GridMap g k b -> a
- Math.Geometry.GridMap: fold' :: (a -> b -> a) -> a -> GridMap g k b -> a
- Math.Geometry.GridMap: foldWithKey :: (a -> k -> b -> a) -> a -> GridMap g k b -> a
- Math.Geometry.GridMap: foldWithKey' :: (a -> k -> b -> a) -> a -> GridMap g k b -> a
- Math.Geometry.GridMap: instance (Eq g, Eq k, Eq v) => Eq (GridMap g k v)
- Math.Geometry.GridMap: instance (Eq k, Grid g s k) => Grid (GridMap g k v) s k
- Math.Geometry.GridMap: instance (Show g, Show v) => Show (GridMap g k v)
- Math.Geometry.GridMap: keysSet :: GridMap g k a -> Set k
- Math.Geometry.GridMap: lazyGridMap :: (Ord k, Grid g s k) => g -> [v] -> GridMap g k v
- Math.Geometry.GridMap: mapAccum :: (a -> b -> (a, c)) -> a -> GridMap g k b -> (a, GridMap g k c)
- Math.Geometry.GridMap: mapAccumWithKey :: (a -> k -> b -> (a, c)) -> a -> GridMap g k b -> (a, GridMap g k c)
- Math.Geometry.GridMap: nonEmpty :: Grid g s x => g -> Bool
+ Math.Geometry.Grid: class Grid g => FiniteGrid g where type family Size s
+ Math.Geometry.Grid: data RectTriGrid
+ Math.Geometry.Grid: data TorTriGrid
+ Math.Geometry.Grid: data UnboundedHexGrid
+ Math.Geometry.Grid: data UnboundedSquareGrid
+ Math.Geometry.Grid: data UnboundedTriGrid
+ Math.Geometry.Grid: nonNull :: Grid g => g -> Bool
+ Math.Geometry.Grid: null :: Grid g => g -> Bool
+ Math.Geometry.Grid: rectTriGrid :: Int -> Int -> RectTriGrid
+ Math.Geometry.Grid: tileSideCount :: BoundedGrid g => g -> Int
+ Math.Geometry.Grid: torTriGrid :: Int -> Int -> TorTriGrid
+ Math.Geometry.GridInternal: class Grid g => FiniteGrid g where type family Size s
+ Math.Geometry.GridInternal: class Grid g => WrappedGrid g
+ Math.Geometry.GridInternal: data RectTriGrid
+ Math.Geometry.GridInternal: data TorTriGrid
+ Math.Geometry.GridInternal: data UnboundedHexGrid
+ Math.Geometry.GridInternal: data UnboundedSquareGrid
+ Math.Geometry.GridInternal: data UnboundedTriGrid
+ Math.Geometry.GridInternal: instance BoundedGrid HexHexGrid
+ Math.Geometry.GridInternal: instance BoundedGrid ParaHexGrid
+ Math.Geometry.GridInternal: instance BoundedGrid ParaTriGrid
+ Math.Geometry.GridInternal: instance BoundedGrid RectSquareGrid
+ Math.Geometry.GridInternal: instance BoundedGrid RectTriGrid
+ Math.Geometry.GridInternal: instance BoundedGrid TriTriGrid
+ Math.Geometry.GridInternal: instance Eq RectTriGrid
+ Math.Geometry.GridInternal: instance Eq TorTriGrid
+ Math.Geometry.GridInternal: instance FiniteGrid HexHexGrid
+ Math.Geometry.GridInternal: instance FiniteGrid ParaHexGrid
+ Math.Geometry.GridInternal: instance FiniteGrid ParaTriGrid
+ Math.Geometry.GridInternal: instance FiniteGrid RectSquareGrid
+ Math.Geometry.GridInternal: instance FiniteGrid RectTriGrid
+ 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 RectSquareGrid
+ Math.Geometry.GridInternal: instance Grid RectTriGrid
+ 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 UnboundedSquareGrid
+ Math.Geometry.GridInternal: instance Grid UnboundedTriGrid
+ Math.Geometry.GridInternal: instance Show RectTriGrid
+ Math.Geometry.GridInternal: instance Show TorTriGrid
+ Math.Geometry.GridInternal: instance Show UnboundedHexGrid
+ Math.Geometry.GridInternal: instance Show UnboundedSquareGrid
+ Math.Geometry.GridInternal: instance Show UnboundedTriGrid
+ Math.Geometry.GridInternal: instance WrappedGrid TorSquareGrid
+ Math.Geometry.GridInternal: instance WrappedGrid TorTriGrid
+ Math.Geometry.GridInternal: nonNull :: Grid g => g -> Bool
+ Math.Geometry.GridInternal: normalise :: WrappedGrid g => g -> Index g -> Index g
+ Math.Geometry.GridInternal: null :: Grid g => g -> Bool
+ Math.Geometry.GridInternal: rectTriGrid :: Int -> Int -> RectTriGrid
+ Math.Geometry.GridInternal: tileSideCount :: BoundedGrid g => g -> Int
+ Math.Geometry.GridInternal: torTriGrid :: Int -> Int -> TorTriGrid
+ Math.Geometry.GridMap: adjacentTilesToward :: Grid g => g -> Index g -> Index g -> [Index g]
+ Math.Geometry.GridMap: boundary :: BoundedGrid g => g -> [Index g]
+ Math.Geometry.GridMap: centre :: BoundedGrid g => g -> [Index g]
+ Math.Geometry.GridMap: 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.GridMap: class (Grid (BaseGrid gm v), Foldable gm) => GridMap (gm :: * -> *) v where type family BaseGrid gm v ! gm k = toMap gm ! k toList = toList . toMap lookup k = lookup k . toMap adjust f = adjustWithKey (\ _ v -> f v) findWithDefault v k = findWithDefault v k . toMap elems = elems . toMap map f = mapWithKey (\ _ v -> f v)
+ Math.Geometry.GridMap: edges :: (Grid g, Eq (Index g)) => g -> [(Index g, Index g)]
+ Math.Geometry.GridMap: foldl :: (a -> b -> a) -> a -> Map k b -> a
+ Math.Geometry.GridMap: foldl' :: (a -> b -> a) -> a -> Map k b -> a
+ Math.Geometry.GridMap: foldr :: (a -> b -> b) -> b -> Map k a -> b
+ Math.Geometry.GridMap: foldr' :: (a -> b -> b) -> b -> Map k a -> b
+ Math.Geometry.GridMap: isAdjacent :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> Bool
+ Math.Geometry.GridMap: isBoundary :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
+ Math.Geometry.GridMap: isCentre :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
+ Math.Geometry.GridMap: minDistance :: Grid g => g -> [Index g] -> Index g -> Int
+ Math.Geometry.GridMap: minimalPaths :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> [[Index g]]
+ Math.Geometry.GridMap: nonNull :: Grid g => g -> Bool
+ Math.Geometry.GridMap: null :: Grid g => g -> Bool
+ Math.Geometry.GridMap: numNeighbours :: Grid g => g -> Index g -> Int
+ Math.Geometry.GridMap: toGrid :: GridMap gm v => gm v -> BaseGrid gm v
+ Math.Geometry.GridMap: toMap :: (GridMap gm v, k ~ (Index (BaseGrid gm v))) => gm v -> Map k v
+ Math.Geometry.GridMap.Lazy: data LGridMap g v
+ Math.Geometry.GridMap.Lazy: instance (Eq g, Eq (Index g), Eq v) => Eq (LGridMap g v)
+ Math.Geometry.GridMap.Lazy: instance (Grid g, Ord (Index g)) => Functor (LGridMap g)
+ Math.Geometry.GridMap.Lazy: instance (Show g, Show v) => Show (LGridMap g v)
+ Math.Geometry.GridMap.Lazy: instance FiniteGrid g => FiniteGrid (LGridMap g v)
+ Math.Geometry.GridMap.Lazy: instance Foldable (LGridMap g)
+ Math.Geometry.GridMap.Lazy: instance Grid g => Grid (LGridMap g v)
+ Math.Geometry.GridMap.Lazy: instance Grid g => GridMap (LGridMap g) v
+ Math.Geometry.GridMap.Lazy: lazyGridMap :: (Ord (Index g), Grid g) => g -> [v] -> LGridMap g v
- Math.Geometry.Grid: adjacentTilesToward :: Grid g s x => g -> x -> x -> [x]
+ Math.Geometry.Grid: adjacentTilesToward :: Grid g => g -> Index g -> Index g -> [Index g]
- Math.Geometry.Grid: boundary :: BoundedGrid g s x => g -> [x]
+ Math.Geometry.Grid: boundary :: BoundedGrid g => g -> [Index g]
- Math.Geometry.Grid: centre :: BoundedGrid g s x => g -> [x]
+ Math.Geometry.Grid: centre :: BoundedGrid g => g -> [Index g]
- Math.Geometry.Grid: class Grid g s x => BoundedGrid g s x where 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 (\ 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 Eq x => Grid g s x | g -> s, g -> x where 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 empty g = tileCount g ≡ 0 nonEmpty = not . empty edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g isAdjacent g a b = distance g a b ≡ 1 adjacentTilesToward g a b | a ≡ b = [] | otherwise = 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 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: contains :: Grid g s x => g -> x -> Bool
+ Math.Geometry.Grid: contains :: (Grid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.Grid: distance :: Grid g s x => g -> x -> x -> Int
+ Math.Geometry.Grid: distance :: Grid g => g -> Index g -> Index g -> Int
- Math.Geometry.Grid: edges :: Grid g s x => g -> [(x, x)]
+ Math.Geometry.Grid: edges :: (Grid g, Eq (Index g)) => g -> [(Index g, Index g)]
- Math.Geometry.Grid: indices :: Grid g s x => g -> [x]
+ Math.Geometry.Grid: indices :: Grid g => g -> [Index g]
- Math.Geometry.Grid: isAdjacent :: (Grid g s x, Grid g s x) => g -> x -> x -> Bool
+ Math.Geometry.Grid: isAdjacent :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> Bool
- Math.Geometry.Grid: isBoundary :: BoundedGrid g s x => g -> x -> Bool
+ Math.Geometry.Grid: isBoundary :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.Grid: isCentre :: BoundedGrid g s x => g -> x -> Bool
+ Math.Geometry.Grid: isCentre :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.Grid: minDistance :: Grid g s x => g -> [x] -> x -> Int
+ Math.Geometry.Grid: minDistance :: Grid g => g -> [Index g] -> Index g -> Int
- Math.Geometry.Grid: minimalPaths :: Grid g s x => g -> x -> x -> [[x]]
+ Math.Geometry.Grid: minimalPaths :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> [[Index g]]
- Math.Geometry.Grid: neighbours :: Grid g s x => g -> x -> [x]
+ Math.Geometry.Grid: neighbours :: Grid g => g -> Index g -> [Index g]
- Math.Geometry.Grid: numNeighbours :: Grid g s x => g -> x -> Int
+ Math.Geometry.Grid: numNeighbours :: Grid g => g -> Index g -> Int
- Math.Geometry.Grid: size :: Grid g s x => g -> s
+ Math.Geometry.Grid: size :: FiniteGrid g => g -> Size g
- Math.Geometry.Grid: tileCount :: Grid g s x => g -> Int
+ Math.Geometry.Grid: tileCount :: Grid g => g -> Int
- Math.Geometry.Grid: viewpoint :: Grid g s x => g -> x -> [(x, Int)]
+ Math.Geometry.Grid: viewpoint :: Grid g => g -> Index g -> [(Index g, Int)]
- Math.Geometry.GridInternal: adjacentTilesToward :: Grid g s x => g -> x -> x -> [x]
+ Math.Geometry.GridInternal: adjacentTilesToward :: Grid g => g -> Index g -> Index g -> [Index g]
- Math.Geometry.GridInternal: boundary :: BoundedGrid g s x => g -> [x]
+ Math.Geometry.GridInternal: boundary :: BoundedGrid g => g -> [Index g]
- Math.Geometry.GridInternal: centre :: BoundedGrid g s x => g -> [x]
+ Math.Geometry.GridInternal: centre :: BoundedGrid g => g -> [Index g]
- Math.Geometry.GridInternal: class Grid g s x => BoundedGrid g s x where 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 (\ 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 Eq x => Grid g s x | g -> s, g -> x where 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 empty g = tileCount g ≡ 0 nonEmpty = not . empty edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g isAdjacent g a b = distance g a b ≡ 1 adjacentTilesToward g a b | a ≡ b = [] | otherwise = 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 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: contains :: Grid g s x => g -> x -> Bool
+ Math.Geometry.GridInternal: contains :: (Grid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.GridInternal: distance :: Grid g s x => g -> x -> x -> Int
+ Math.Geometry.GridInternal: distance :: Grid g => g -> Index g -> Index g -> Int
- Math.Geometry.GridInternal: edges :: Grid g s x => g -> [(x, x)]
+ Math.Geometry.GridInternal: edges :: (Grid g, Eq (Index g)) => g -> [(Index g, Index g)]
- Math.Geometry.GridInternal: indices :: Grid g s x => g -> [x]
+ Math.Geometry.GridInternal: indices :: Grid g => g -> [Index g]
- Math.Geometry.GridInternal: isAdjacent :: (Grid g s x, Grid g s x) => g -> x -> x -> Bool
+ Math.Geometry.GridInternal: isAdjacent :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> Bool
- Math.Geometry.GridInternal: isBoundary :: BoundedGrid g s x => g -> x -> Bool
+ Math.Geometry.GridInternal: isBoundary :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.GridInternal: isCentre :: BoundedGrid g s x => g -> x -> Bool
+ Math.Geometry.GridInternal: isCentre :: (BoundedGrid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.GridInternal: minDistance :: Grid g s x => g -> [x] -> x -> Int
+ Math.Geometry.GridInternal: minDistance :: Grid g => g -> [Index g] -> Index g -> Int
- Math.Geometry.GridInternal: minimalPaths :: Grid g s x => g -> x -> x -> [[x]]
+ Math.Geometry.GridInternal: minimalPaths :: (Grid g, Eq (Index g)) => g -> Index g -> Index g -> [[Index g]]
- Math.Geometry.GridInternal: neighbours :: Grid g s x => g -> x -> [x]
+ Math.Geometry.GridInternal: neighbours :: Grid g => g -> Index g -> [Index g]
- Math.Geometry.GridInternal: numNeighbours :: Grid g s x => g -> x -> Int
+ Math.Geometry.GridInternal: numNeighbours :: Grid g => g -> Index g -> Int
- Math.Geometry.GridInternal: size :: Grid g s x => g -> s
+ Math.Geometry.GridInternal: size :: FiniteGrid g => g -> Size g
- Math.Geometry.GridInternal: tileCount :: Grid g s x => g -> Int
+ Math.Geometry.GridInternal: tileCount :: Grid g => g -> Int
- Math.Geometry.GridInternal: viewpoint :: Grid g s x => g -> x -> [(x, Int)]
+ Math.Geometry.GridInternal: viewpoint :: Grid g => g -> Index g -> [(Index g, Int)]
- Math.Geometry.GridMap: (!) :: Ord k => GridMap g k v -> k -> v
+ Math.Geometry.GridMap: (!) :: (GridMap gm v, k ~ (Index (BaseGrid gm v)), Ord k) => gm v -> k -> v
- Math.Geometry.GridMap: adjust :: Ord k => (v -> v) -> k -> GridMap g k v -> GridMap g k v
+ Math.Geometry.GridMap: adjust :: (GridMap gm v, k ~ (Index (BaseGrid gm v)), Ord k) => (v -> v) -> k -> gm v -> gm v
- Math.Geometry.GridMap: adjustWithKey :: Ord k => (k -> v -> v) -> k -> GridMap g k v -> GridMap g k v
+ Math.Geometry.GridMap: adjustWithKey :: (GridMap gm v, k ~ (Index (BaseGrid gm v)), Ord k) => (k -> v -> v) -> k -> gm v -> gm v
- Math.Geometry.GridMap: contains :: Grid g s x => g -> x -> Bool
+ Math.Geometry.GridMap: contains :: (Grid g, Eq (Index g)) => g -> Index g -> Bool
- Math.Geometry.GridMap: distance :: Grid g s x => g -> x -> x -> Int
+ Math.Geometry.GridMap: distance :: Grid g => g -> Index g -> Index g -> Int
- Math.Geometry.GridMap: elems :: GridMap g k a -> [a]
+ Math.Geometry.GridMap: elems :: GridMap gm v => gm v -> [v]
- Math.Geometry.GridMap: findWithDefault :: Ord k => v -> k -> GridMap g k v -> v
+ Math.Geometry.GridMap: findWithDefault :: (GridMap gm v, k ~ (Index (BaseGrid gm v)), Ord k) => v -> k -> gm v -> v
- Math.Geometry.GridMap: indices :: Grid g s x => g -> [x]
+ Math.Geometry.GridMap: indices :: Grid g => g -> [Index g]
- Math.Geometry.GridMap: lookup :: Ord k => k -> GridMap g k v -> Maybe v
+ Math.Geometry.GridMap: lookup :: (GridMap gm v, k ~ (Index (BaseGrid gm v)), Ord k) => k -> gm v -> Maybe v
- Math.Geometry.GridMap: map :: (a -> b) -> GridMap g k a -> GridMap g k b
+ Math.Geometry.GridMap: map :: (GridMap gm v, GridMap gm b) => (v -> b) -> gm v -> gm b
- Math.Geometry.GridMap: mapWithKey :: (k -> a -> b) -> GridMap g k a -> GridMap g k b
+ Math.Geometry.GridMap: mapWithKey :: (GridMap gm v, k ~ Index (BaseGrid gm v), GridMap gm v2) => (k -> v -> v2) -> gm v -> gm v2
- Math.Geometry.GridMap: neighbours :: Grid g s x => g -> x -> [x]
+ Math.Geometry.GridMap: neighbours :: Grid g => g -> Index g -> [Index g]
- Math.Geometry.GridMap: size :: Grid g s x => g -> s
+ Math.Geometry.GridMap: size :: FiniteGrid g => g -> Size g
- Math.Geometry.GridMap: tileCount :: Grid g s x => g -> Int
+ Math.Geometry.GridMap: tileCount :: Grid g => g -> Int
- Math.Geometry.GridMap: toList :: GridMap g k a -> [(k, a)]
+ Math.Geometry.GridMap: toList :: (GridMap gm v, k ~ (Index (BaseGrid gm v))) => gm v -> [(k, v)]
- Math.Geometry.GridMap: viewpoint :: Grid g s x => g -> x -> [(x, Int)]
+ Math.Geometry.GridMap: viewpoint :: Grid g => g -> Index g -> [(Index g, Int)]

Files

grid.cabal view
@@ -1,5 +1,5 @@ name:           grid-version:        3.1+version:        4.0 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@@ -8,7 +8,10 @@                 toroidal layouts.                 The userguide is available at                  <https://github.com/mhwombat/grid/wiki>.-+                .+                NOTE: Version 4.0 uses associated (type) synonyms+                instead of multi-parameter type classes.+                .                 NOTE: Version 3.0 changed the order of parameters                 for many functions. This makes it easier for the user                 to write mapping and folding operations.@@ -31,7 +34,8 @@   ghc-options:     -Wall   exposed-modules: Math.Geometry.Grid,                    Math.Geometry.GridInternal,-                   Math.Geometry.GridMap+                   Math.Geometry.GridMap,+                   Math.Geometry.GridMap.Lazy  test-suite grid-tests   type:            exitcode-stdio-1.0
src/Math/Geometry/Grid.hs view
@@ -12,6 +12,9 @@ -- The userguide is available at  -- <https://github.com/mhwombat/grid/wiki>. --+-- NOTE: Version 4.0 uses associated (type) synonyms instead of +-- multi-parameter type classes.+ -- NOTE: Version 3.0 changed the order of parameters for many functions. -- This makes it easier for the user to write mapping and folding -- operations.@@ -24,18 +27,26 @@   (     -- * The Grid class     Grid(..),+    FiniteGrid(..),     BoundedGrid(..),     -- * Grids with triangular tiles+    UnboundedTriGrid,     TriTriGrid,     triTriGrid,     ParaTriGrid,     paraTriGrid,+    RectTriGrid,+    rectTriGrid,+    TorTriGrid,+    torTriGrid,     -- * Grids with square tiles+    UnboundedSquareGrid,     RectSquareGrid,     rectSquareGrid,     TorSquareGrid,     torSquareGrid,     -- * Grids with hexagonal tiles+    UnboundedHexGrid,     HexHexGrid,     hexHexGrid,     ParaHexGrid,@@ -44,10 +55,12 @@     -- $Example   ) where -import Math.Geometry.GridInternal (Grid(..), BoundedGrid(..), -  TriTriGrid, triTriGrid, ParaTriGrid, paraTriGrid, RectSquareGrid, -  rectSquareGrid, TorSquareGrid, torSquareGrid, HexHexGrid, hexHexGrid, -  ParaHexGrid, paraHexGrid)+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)  {- $Example    Create a grid.@@ -56,14 +69,21 @@ >ghci> indices g >[(-2,0),(-2,1),(-2,2),(-1,-1),(-1,0),(-1,1),(-1,2),(0,-2),(0,-1),(0,0),(0,1),(0,2),(1,-2),(1,-1),(1,0),(1,1),(2,-2),(2,-1),(2,0)] -   Find out the minimum number of moves to go from one tile in a grid to another-   tile, moving between adjacent tiles at each step.+   Find out if the specified index is contained within the grid. +>ghci> g `contains` (0,-2)+>True+>ghci> g `contains` (99,99)+>False++   Find out the minimum number of moves to go from one tile in a grid to+   another tile, moving between adjacent tiles at each step.+ >ghci> distance g (0,-2) (0,2) >4 -   Find out the minimum number of moves to go from one tile in a grid to any -   other tile, moving between adjacent tiles at each step.+   Find out the minimum number of moves to go from one tile in a grid to+   any other tile, moving between adjacent tiles at each step.  >ghci> viewpoint g (1,-2) >[((-2,0),3),((-2,1),3),((-2,2),4),((-1,-1),2),((-1,0),2),((-1,1),3),((-1,2),4),((0,-2),1),((0,-1),1),((0,0),2),((0,1),3),((0,2),4),((1,-2),0),((1,-1),1),((1,0),2),((1,1),3),((2,-2),1),((2,-1),2),((2,0),3)]@@ -73,8 +93,15 @@ >ghci> neighbours g (-1,1) >[(-2,1),(-2,2),(-1,2),(0,1),(0,0),(-1,0)] -   Find out if a tile is within the grid boundary.+   Find how many tiles are adjacent to a particular tile.+   (Note that the result is consistent with the result from the previous+   step.) +>ghci> numNeighbours g (-1,1)+>6++   Find out if an index is valid for the grid.+ >ghci> g `contains` (0,0) >True >ghci> g `contains` (0,12)@@ -85,22 +112,45 @@ >ghci> size g >3 +   Get the list of boundary tiles for a grid.++>ghci> boundary g+>[(-2,2),(-1,2),(0,2),(1,1),(2,0),(2,-1),(2,-2),(1,-2),(0,-2),(-1,-1),(-2,0),(-2,1)]+    Find out the number of tiles in the grid.  >ghci> tileCount g >19 -   Check if a grid is empty (contains no tiles).+   Check if a grid is null (contains no tiles). ->ghci> empty g+>ghci> null g >False->ghci> nonEmpty g+>ghci> nonNull g >True +   Find the central tile(s) (the tile(s) furthest from the boundary).++>ghci> centre g+>[(0,0)]+    Find all of the minimal paths between two points. -ghci> let g = hexHexGrid 3-ghci> minimalPaths g (0,0) (2,-1)-[[(0,0),(1,0),(2,-1)],[(0,0),(1,-1),(2,-1)]]+>ghci> let g = hexHexGrid 3+>ghci> minimalPaths g (0,0) (2,-1)+>[[(0,0),(1,0),(2,-1)],[(0,0),(1,-1),(2,-1)]] +   Find all of the pairs of tiles that are adjacent.++>ghci> edges g+>[((-2,0),(-2,1)),((-2,0),(-1,0)),((-2,0),(-1,-1)),((-2,1),(-2,2)),((-2,1),(-1,1)),((-2,1),(-1,0)),((-2,2),(-1,2)),((-2,2),(-1,1)),((-1,-1),(-1,0)),((-1,-1),(0,-1)),((-1,-1),(0,-2)),((-1,0),(-1,1)),((-1,0),(0,0)),((-1,0),(0,-1)),((-1,1),(-1,2)),((-1,1),(0,1)),((-1,1),(0,0)),((-1,2),(0,2)),((-1,2),(0,1)),((0,-2),(0,-1)),((0,-2),(1,-2)),((0,-1),(0,0)),((0,-1),(1,-1)),((0,-1),(1,-2)),((0,0),(0,1)),((0,0),(1,0)),((0,0),(1,-1)),((0,1),(0,2)),((0,1),(1,1)),((0,1),(1,0)),((0,2),(1,1)),((1,-2),(1,-1)),((1,-2),(2,-2)),((1,-1),(1,0)),((1,-1),(2,-1)),((1,-1),(2,-2)),((1,0),(1,1)),((1,0),(2,0)),((1,0),(2,-1)),((1,1),(2,0)),((2,-2),(2,-1)),((2,-1),(2,0))]++   Find out if two tiles are adjacent.++>ghci> isAdjacent g (-2,0) (-2,1)+>True+>ghci> isAdjacent g (-2,0) (0,1)+>False+ -}+
src/Math/Geometry/GridInternal.hs view
@@ -11,53 +11,61 @@ -- use @Grid@ instead. This module is subject to change without notice. -- -------------------------------------------------------------------------{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, -    FunctionalDependencies, TypeSynonymInstances, FlexibleInstances, -    FlexibleContexts, DeriveGeneric #-}+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts #-}  module Math.Geometry.GridInternal   (     -- * Generic     Grid(..),+    FiniteGrid(..),     BoundedGrid(..),+    WrappedGrid(..),     -- * Grids with triangular tiles+    UnboundedTriGrid,     TriTriGrid,     triTriGrid,     ParaTriGrid,     paraTriGrid,+    RectTriGrid,+    rectTriGrid,+    TorTriGrid,+    torTriGrid,     -- * Grids with square tiles+    UnboundedSquareGrid,     RectSquareGrid,     rectSquareGrid,     TorSquareGrid,     torSquareGrid,     -- * Grids with hexagonal tiles+    UnboundedHexGrid,     HexHexGrid,     hexHexGrid,     ParaHexGrid,     paraHexGrid   ) where +import Prelude hiding (null)+ import Data.Eq.Unicode ((≡), (≠)) import Data.Function (on) import Data.List (groupBy, nub, nubBy, sortBy) import Data.Ord (comparing) import Data.Ord.Unicode ((≤), (≥))-import Data.Serialize (Serialize)-import GHC.Generics (Generic)  -- | A regular arrangement of tiles.---   Minimal complete definition: @indices@, @distance@ and @size@.-class Eq x ⇒ Grid g s x | g → s, g → x where+--   Minimal complete definition: @indices@ and @distance@.+class Grid g where+  type Index g    -- | Returns the indices of all tiles in a grid.-  indices ∷ g → [x]+  indices ∷ g → [Index g]    -- | @'distance' g a b@ returns the minimum number of moves required   --   to get from the tile at index @a@ to the tile at index @b@ in   --   grid @g@, moving between adjacent tiles at each step. (Two tiles   --   are adjacent if they share an edge.) If @a@ or @b@ are not   --   contained within @g@, the result is undefined.-  distance ∷ g → x → x → Int+  distance ∷ g → Index g → Index g → Int    -- | @'minDistance' g bs a@ returns the minimum number of moves    --   required to get from any of the tiles at indices @bs@ to the tile@@ -65,33 +73,28 @@   --   step. (Two tiles are adjacent if they share an edge.) If @a@ or   --   any of @bs@ are not contained within @g@, the result is    --   undefined.-  minDistance ∷ g → [x] → x → Int+  minDistance ∷ g → [Index g] → Index g → Int   minDistance g xs x = minimum . map (distance g x) $ xs -  -- | Returns the dimensions of the grid. -  --   For example, if @g@ is a 4x3 rectangular grid, @'size' g@ would-  --   return @(4, 3)@, while @'tileCount' g@ would return @12@.-  size ∷ g → s-   -- | @'neighbours' g x@ returns the indices of the tiles in the grid   --   @g@ which are adjacent to the tile with index @x@.-  neighbours ∷ g → x → [x]+  neighbours ∷ g → Index g → [Index g]   neighbours g x = filter (\a → distance g x a ≡ 1 ) $ indices g    -- | @'numNeighbours' g x@ returns the number of tiles in the grid   --   @g@ which are adjacent to the tile with index @x@.-  numNeighbours ∷ g → x → Int+  numNeighbours ∷ g → Index g → Int   numNeighbours g = length . neighbours g    -- | @g `'contains'` x@ returns @True@ if the index @x@ is contained    --   within the grid @g@, otherwise it returns false.-  contains ∷ g → x → Bool+  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 → x → [(x, Int)]+  viewpoint ∷ g → Index g → [(Index g, Int)]   viewpoint g p = map f (indices g)     where f x = (x, distance g p x) @@ -101,25 +104,25 @@    -- | Returns @True@ if the number of tiles in a grid is zero, @False@    --   otherwise.-  empty ∷ g → Bool-  empty g = tileCount g ≡ 0+  null ∷ g → Bool+  null g = tileCount g ≡ 0    -- | Returns @False@ if the number of tiles in a grid is zero, @True@    --   otherwise.-  nonEmpty ∷ g → Bool-  nonEmpty = not . empty+  nonNull ∷ g → Bool+  nonNull = not . null    -- | A list of all edges in a grid, where the edges are represented by   --   a pair of indices of adjacent tiles.-  edges ∷ g → [(x,x)]+  edges ∷ Eq (Index g) ⇒ g → [(Index g,Index g)]   edges g = nubBy sameEdge $ concatMap (`adjacentEdges` g) $ indices g    -- | @'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 ∷ Grid g s x ⇒ g → x → x → Bool-  isAdjacent g a b = distance g a b ≡ 1+  isAdjacent ∷ Eq (Index g) ⇒ g → Index g → Index g → Bool+  isAdjacent g a b = a `elem` (neighbours g b)    -- | @'adjacentTilesToward' g a b@ returns the indices of all tiles   --   which are neighbours of the tile at index @a@, and which are@@ -127,10 +130,8 @@   --   the possible next steps on a minimal path from @a@ to @b@. If @a@   --   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 → x → x → [x]-  adjacentTilesToward g a b-    | a ≡ b            = []-    | otherwise        = filter f $ neighbours g a+  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    -- | @'minimalPaths' g a b@ returns a list of all minimal paths from @@ -144,7 +145,7 @@   --   @'adjacentTilesToward'@. If you want to use a custom algorithm,   --   consider modifying @'adjacentTilesToward'@ instead of    --   @'minimalPaths'@.-  minimalPaths ∷ g → x → x → [[x]]+  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@@ -154,62 +155,98 @@ sameEdge ∷ Eq t ⇒ (t, t) → (t, t) → Bool sameEdge (a,b) (c,d) = (a,b) ≡ (c,d) || (a,b) ≡ (d,c) -adjacentEdges ∷ Grid g s t ⇒ t → g → [(t, t)]+adjacentEdges ∷ Grid g ⇒ Index g → g → [(Index g, Index g)] adjacentEdges i g = map (\j → (i,j)) $ neighbours g i  +-- | A regular arrangement of tiles where the number of tiles is finite.+--   Minimal complete definition: @size@.+class Grid g ⇒ FiniteGrid g where+  type Size s+  -- | Returns the dimensions of the grid. +  --   For example, if @g@ is a 4x3 rectangular grid, @'size' g@ would+  --   return @(4, 3)@, while @'tileCount' g@ would return @12@.+  size ∷ g → Size g++ -- | A regular arrangement of tiles with an edge.---   Minimal complete definition: @boundary@.-class Grid g s x ⇒ BoundedGrid g s x where-  -- | Returns a the indices of all the tiles at the boundary of a grid, -  --   including corner tiles.-  boundary ∷ g → [x]+--   Minimal complete definition: @tileSideCount@.+class Grid g ⇒ BoundedGrid g where+  -- | Returns the number of sides a tile has+  tileSideCount ∷ g → Int +  -- | 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+          f (_,n) = n < tileSideCount g ++   -- | @'isBoundary' g x@' returns @True@ if the tile with index @x@ is   --   on a boundary of @g@, @False@ otherwise. (Corner tiles are also   --   boundary tiles.)-  isBoundary ∷ g → x → Bool+  isBoundary ∷ Eq (Index g) ⇒ g → Index g → Bool   isBoundary g x = x `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 → [x]-  centre g = map fst . head . reverse . groupBy ((==) `on` snd) . +  centre ∷ g → [Index 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+    where xds = map (\y → (y, minDistance g bs y)) $ indices g           bs = boundary g     -- | @'isCentre' g x@' returns @True@ if the tile with index @x@ is   --   a centre tile of @g@, @False@ otherwise.-  isCentre ∷ g → x → Bool+  isCentre ∷ Eq (Index g) ⇒ g → Index g → Bool   isCentre g x = x `elem` centre g +class (Grid g) ⇒ WrappedGrid g where+  normalise ∷ 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]+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+distanceBasedOn u g a b = +  if g `contains` a && g `contains` b+    then distance u a b+    else undefined+ -- -- Triangular tiles -- +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 | even y    = -x - y-         | otherwise = -x - y + 1--triDistance ∷ Grid g s (Int, Int) ⇒ g → (Int, Int) → (Int, Int) → Int-triDistance g (x1, y1) (x2, y2) = -    if g `contains` (x1, y1) && g `contains` (x2, y2)-      then maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]-      else undefined-        where z1 = triZ x1 y1-              z2 = triZ x2 y2--triNeighbours ∷ Grid g s (Int, Int) ⇒ g → (Int, Int) → [(Int, Int)]-triNeighbours g (x,y) = filter (g `contains`) xs-    where xs | even y    = [(x-1,y+1), (x+1,y+1), (x+1,y-1)]-             | otherwise = [(x-1,y-1), (x-1,y+1), (x+1,y-1)]+triZ x y = if even y then -x - y else -x - y + 1  -- -- Triangular grids with triangular tiles@@ -218,29 +255,28 @@ -- | 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, Generic)+data TriTriGrid = TriTriGrid Int [(Int, Int)] deriving Eq  instance Show TriTriGrid where    show (TriTriGrid s _) = "triTriGrid " ++ show s -instance Serialize TriTriGrid--instance Grid TriTriGrid Int (Int, Int) where+instance Grid TriTriGrid where+  type Index TriTriGrid = (Int, Int)   indices (TriTriGrid _ xs) = xs-  neighbours = triNeighbours-  distance = triDistance-  contains (TriTriGrid s _) (x, y) = inTriGrid (x,y) s-  size (TriTriGrid s _) = s+  neighbours = neighboursBasedOn UnboundedTriGrid+  distance = distanceBasedOn UnboundedTriGrid+  contains (TriTriGrid s _) (x, y) = inTriTriGrid (x,y) s -inTriGrid ∷ (Int, Int) → Int → Bool-inTriGrid (x, y) s = x ≥ 0 && y ≥ 0 && even (x+y) && abs z ≤ 2*s-2+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 BoundedGrid TriTriGrid Int (Int, Int) where---  corners g = if empty g ---                then [] ---                else nub [(0,0), (0,2*s-2), (2*s-2, 0)] ---    where s = size g+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]]@@ -252,19 +288,17 @@     2 → [(k+1,k+1)] where k = (2*(s-2)) `div` 3     _ → error "This will never happen."     where s = size g--trefoilWithTop ∷ (Int, Int) → [(Int,Int)]-trefoilWithTop (i,j) = [(i,j), (i+2, j-2), (i,j-2)]+          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 empty and the list of indices will be null.+--   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) `inTriGrid` s]+                          (xx,yy) `inTriTriGrid` s]  -- -- Parallelogrammatical grids with triangular tiles@@ -273,80 +307,194 @@ -- | 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, Generic)+data ParaTriGrid = ParaTriGrid (Int, Int) [(Int, Int)] deriving Eq  instance Show ParaTriGrid where    show (ParaTriGrid (r,c) _) = "paraTriGrid " ++ show r ++ " " ++ show c -instance Serialize ParaTriGrid--instance Grid ParaTriGrid (Int, Int) (Int, Int) where+instance Grid ParaTriGrid where+  type Index ParaTriGrid = (Int, Int)   indices (ParaTriGrid _ xs) = xs-  neighbours = triNeighbours-  distance = triDistance+  neighbours = neighboursBasedOn UnboundedTriGrid+  distance = distanceBasedOn UnboundedTriGrid++instance FiniteGrid ParaTriGrid where+  type Size ParaTriGrid = (Int, Int)   size (ParaTriGrid s _) = s -instance BoundedGrid ParaTriGrid (Int, Int) (Int, Int) where+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 = paraTriGridCentre . size $ g--paraTriGridCentre ∷ (Int, Int) → [(Int, Int)]-paraTriGridCentre (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 :: (Int,Int) -> [(Int,Int)]-bowtie (i,j) = [(i,j), (i+1,j+1)]+  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 empty and+--   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)+++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-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++-- | @'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)]+    else undefined+  where xMax c2 y = xMinTorTri y + 2*(c2-1)+++--+-- Square tiles+--++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, Generic)+data RectSquareGrid = RectSquareGrid (Int, Int) [(Int, Int)] deriving Eq  instance Show RectSquareGrid where    show (RectSquareGrid (r,c) _) =      "rectSquareGrid " ++ show r ++ " " ++ show c -instance Serialize RectSquareGrid--instance Grid RectSquareGrid (Int, Int) (Int, Int) where+instance Grid RectSquareGrid where+  type Index RectSquareGrid = (Int, Int)   indices (RectSquareGrid _ xs) = xs-  neighbours g (x, y) = -    filter (g `contains`) [(x-1,y), (x,y+1), (x+1,y), (x,y-1)]-  distance g (x1, y1) (x2, y2) = -    if g `contains` (x1, y1) && g `contains` (x2, y2)-      then abs (x2-x1) + abs (y2-y1)-      else undefined-  size (RectSquareGrid s _) = s+  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 BoundedGrid RectSquareGrid (Int, Int) (Int, Int) where+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 @@ -370,7 +518,7 @@ -- | @'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 empty and the list of indices will be +--   the resulting grid will be null and the list of indices will be  --   null. rectSquareGrid ∷ Int → Int → RectSquareGrid rectSquareGrid r c = @@ -383,31 +531,38 @@ -- | 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, Generic)+data TorSquareGrid = TorSquareGrid (Int, Int) [(Int, Int)] deriving Eq  instance Show TorSquareGrid where    show (TorSquareGrid (r,c) _) = "torSquareGrid " ++ show r ++ " " ++ show c -instance Serialize TorSquareGrid--instance Grid TorSquareGrid (Int, Int) (Int, Int) where+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 (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) =     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+ -- | @'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 empty and the list of indices will be null.+--   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]] @@ -415,14 +570,19 @@ -- Hexagonal tiles -- -hexDistance ∷ Grid g s (Int, Int) ⇒ g → (Int, Int) → (Int, Int) → Int-hexDistance g (x1, y1) (x2, y2) = -  if g `contains` (x1, y1) && g `contains` (x2, y2)-    then maximum [abs (x2-x1), abs (y2-y1), abs(z2-z1)]-    else undefined-  where z1 = -x1 - y1-        z2 = -x2 - y2+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 --@@ -430,20 +590,22 @@ -- | 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, Generic)+data HexHexGrid = HexHexGrid Int [(Int, Int)] deriving Eq  instance Show HexHexGrid where show (HexHexGrid s _) = "hexHexGrid " ++ show s -instance Serialize HexHexGrid--instance Grid HexHexGrid Int (Int, Int) where+instance Grid HexHexGrid where+  type Index HexHexGrid = (Int, Int)   indices (HexHexGrid _ xs) = xs-  neighbours g (x,y) = filter (g `contains`) -    [(x-1,y), (x-1,y+1), (x,y+1), (x+1,y), (x+1,y-1), (x,y-1)]-  distance = hexDistance+  neighbours = neighboursBasedOn UnboundedHexGrid+  distance = distanceBasedOn UnboundedHexGrid++instance FiniteGrid HexHexGrid where+  type Size HexHexGrid = Int   size (HexHexGrid s _) = s -instance BoundedGrid HexHexGrid Int (Int, Int) where+instance BoundedGrid HexHexGrid where+  tileSideCount _ = 6   boundary g =      north ++ northeast ++ southeast ++ south ++ southwest ++ northwest     where s = size g@@ -458,7 +620,7 @@ -- | @'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 empty and the list of indices will be null.+--   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]@@ -470,28 +632,30 @@ -- | 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, Generic)+data ParaHexGrid = ParaHexGrid (Int, Int) [(Int, Int)] deriving Eq  instance Show ParaHexGrid where    show (ParaHexGrid (r,c) _) = "paraHexGrid " ++ show r ++ " " ++ show c -instance Serialize ParaHexGrid--instance Grid ParaHexGrid (Int, Int) (Int, Int) where+instance Grid ParaHexGrid where+  type Index ParaHexGrid = (Int, Int)   indices (ParaHexGrid _ xs) = xs-  neighbours g (x,y) = filter (g `contains`) -    [(x-1,y), (x-1,y+1), (x,y+1), (x+1,y), (x+1,y-1), (x,y-1)]-  distance = hexDistance+  neighbours = neighboursBasedOn UnboundedHexGrid+  distance = distanceBasedOn UnboundedHexGrid++instance FiniteGrid ParaHexGrid where+  type Size ParaHexGrid = (Int, Int)   size (ParaHexGrid s _) = s -instance BoundedGrid ParaHexGrid (Int, Int) (Int, Int) where+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 empty and the list of indices will +--   Otherwise, the resulting grid will be null and the list of indices will  --   be null. paraHexGrid ∷ Int → Int → ParaHexGrid paraHexGrid r c = 
src/Math/Geometry/GridMap.hs view
@@ -1,42 +1,57 @@------------------------------------------------------------------------------+------------------------------------------------------------------------ -- | -- Module      :  Math.Geometry.GridMap--- Copyright   :  (c) Amy de Buitléir 2012+-- Copyright   :  (c) Amy de Buitléir 2012-2013 -- License     :  BSD-style -- Maintainer  :  amy@nualeargais.ie -- Stability   :  experimental -- Portability :  portable -- -- Ordered maps from tiles on a grid to values.--- This module is a wrapper around @'Math.Geometry.Grid'@ and @'Data.Map'@,--- in order to combine the functionality of grids and maps into a single type.+-- This module is a wrapper around @'Math.Geometry.Grid'@ and +-- @'Data.Map'@, in order to combine the functionality of grids and maps+-- into a single type. ---------------------------------------------------------------------------------{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, FlexibleInstances, -    UndecidableInstances #-}+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts, +    MultiParamTypeClasses, UndecidableInstances #-}  module Math.Geometry.GridMap   (     -- * Differences between @GridMap@ and @Map@.     -- $Compare -    -- * Map type+    -- * Map classes and types     GridMap,+    BaseGrid,+    G.Index,+    G.Grid, -    -- * Construction-    lazyGridMap,+    -- * Deconstruction+    toMap,+    toGrid,+    toList,      -- * Grid functions-    indices,-    distance,-    size,-    neighbours,-    contains,-    viewpoint,-    tileCount,-    empty,-    nonEmpty,-    +    G.indices,+    G.distance,+    G.minDistance,+    G.neighbours,+    G.numNeighbours,+    G.contains,+    G.viewpoint,+    G.tileCount,+    G.null,+    G.nonNull,+    G.edges,+    G.isAdjacent,+    G.adjacentTilesToward,+    G.minimalPaths,+    G.size,+    G.boundary,+    G.isBoundary,+    G.centre,+    G.isCentre,          -- * Map functions     -- ** Operators@@ -50,209 +65,229 @@     adjust,     adjustWithKey, -    -- ** Map+    -- ** Traversal     map,     mapWithKey,-    mapAccum,-    mapAccumWithKey,      -- ** Folds-    fold,-    foldWithKey,-    fold',-    foldWithKey',+--    fold,+--    foldMap,+    M.foldr,+    M.foldr',+    M.foldl,+    M.foldl',      -- ** Conversion-    elems,-    keysSet,--    -- ** Lists-    toList+    elems   ) where -import Prelude hiding (lookup, map)+import Prelude hiding (lookup, map, foldr, foldl, foldr1, foldl1, null)++import qualified Prelude as P (map)+import Data.Foldable (Foldable) import qualified Data.Map as M --import qualified Data.Map.Strict as Strict (Map)-import Data.Maybe (fromMaybe)-import Data.Set (Set)-import Math.Geometry.Grid (Grid(..))---- | A Map from tile positions in a grid to values. -data GridMap g k v = LGridMap { toGrid ∷ g, toMap ∷ M.Map k v }-  deriving Eq--- Future: add alternative constructor for strict maps--instance (Show g, Show v) ⇒ Show (GridMap g k v) where-  show (LGridMap g m) = "lazyGridMap (" ++ show g ++ ") " ++ show (M.elems m)---- | Construct a grid map which is strict in the keys (tile positions), but---   lazy in the values.-lazyGridMap ∷ (Ord k, Grid g s k) ⇒ g → [v] → GridMap g k v-lazyGridMap g vs = LGridMap g (M.fromList kvs)-  where kvs = zip ks vs-        ks = indices g--instance (Eq k, Grid g s k) ⇒ Grid (GridMap g k v) s k where-  indices = indices . toGrid-  distance g = distance (toGrid g)-  size = size . toGrid-  neighbours g k = toGrid g `neighbours` k-  contains g k = toGrid g `contains` k-  viewpoint g k = toGrid g `viewpoint` k-  tileCount  = tileCount . toGrid-  empty = empty . toGrid-  nonEmpty = nonEmpty . toGrid---- | /O(min(n,W))/. Find the value at a tile position in the grid.--- Calls 'error' when the element can not be found.-(!) ∷ Ord k ⇒ GridMap g k v → k → v-(!) m k = toMap m M.! k--modifyMap ∷ (M.Map k a → M.Map k b) → GridMap g k a → GridMap g k b-modifyMap f m = m { toMap = f (toMap m)}--applyToMap ∷ (M.Map k v → c) → GridMap g k v → c-applyToMap f = f . toMap---- | /O(min(n,W))/. Lookup the value at a tile position in the grid map.-lookup ∷ Ord k ⇒ k → GridMap g k v → Maybe v-lookup k = applyToMap $ M.lookup k---- | /O(min(n,W))/. Adjust a value at a specific tile position. When the tile--- is not within the bounds of the grid map, the original grid map is--- returned.-adjust ∷ Ord k ⇒ (v → v) → k → GridMap g k v → GridMap g k v-adjust f k = modifyMap (M.adjust f k)---- | /O(min(n,W))/. Adjust a value at a specific key. When the tile--- is not within the bounds of the grid map, the original grid map is--- returned.-adjustWithKey ∷ Ord k ⇒ (k → v → v) → k → GridMap g k v → GridMap g k v-adjustWithKey f k = modifyMap (M.adjustWithKey f k)+import qualified Math.Geometry.Grid as G --- | /O(min(n,W))/. The expression @('findWithDefault' def k map)@--- returns the value at tile position @k@ or returns @def@ when the tile--- is not within the bounds of the grid map.-findWithDefault ∷ Ord k ⇒ v → k → GridMap g k v → v-findWithDefault v k m = fromMaybe v $ applyToMap (M.lookup k) m+-- | A regular arrangement of tiles, having a value associated with+--   each tile.+--   Minimal complete definition: @toMap@, @toGrid@, @adjustWithKey@,+--   @mapWithKey.+--+--   Note: Some of the methods have an @Ord@ constraint on the grid +--   index. This is purely to make it easier to write implementations.+--   While tile positions can be ordered (e.g., @(1,2) < (2,1)@), the+--   ordering may not be particularly meaningful. (Comparisons such as +--   /east of/ or /south of/ may be more sensible.) However, it is+--   convenient to write implementations of this class using+--   @Data.Map@, with the grid indices as keys. Many of the functions+--   in @Data.Map@ impose the @Ord@ constraint on map keys, so we'll+--   live with it. In summary, to use some methods in this class, your+--   grid indices must be orderable.+class (G.Grid (BaseGrid gm v), Foldable gm) ⇒ +    GridMap (gm ∷ * → *) v where+  type BaseGrid gm v --- | /O(n)/. Map a function over all values in the grid map.-map ∷ (a → b) → GridMap g k a → GridMap g k b-map f = modifyMap (M.map f)+  -- | Find the value at a tile position in the grid.+  (!) ∷ (k ~ (G.Index (BaseGrid gm v)), Ord k) ⇒ gm v → k → v+  (!) gm k = toMap gm M.! k --- | /O(n)/. Map a function over all values in the grid map.-mapWithKey ∷ (k → a → b) → GridMap g k a → GridMap g k b-mapWithKey f = modifyMap (M.mapWithKey f)+  -- | Returns a map of grid indices to values.+  toMap ∷ k ~ (G.Index (BaseGrid gm v)) ⇒ gm v → M.Map k v --- | /O(n)/. The function @'mapAccum'@ threads an accumulating--- argument through the grid map.--- WARNING: The order in which the elements are processed is not guaranteed.-mapAccum ∷ (a → b → (a, c)) → a → GridMap g k b → (a, GridMap g k c)-mapAccum f = mapAccumWithKey (\a _ x → f a x)+  -- | Returns the grid on which this map is based.+  toGrid ∷ gm v → BaseGrid gm v --- | /O(n)/. The function @'mapAccumWithKey'@ threads an accumulating--- argument through the grid map.--- WARNING: The order in which the elements are processed is not guaranteed.-mapAccumWithKey ∷ -  (a → k → b → (a, c)) → a → GridMap g k b → (a, GridMap g k c)-mapAccumWithKey f a gm = (b, gm {toMap=m'})-  where (b, m') = applyToMap (M.mapAccumWithKey f a) gm+  -- | Convert the map to a list of key/value pairs.+  toList ∷ k ~ (G.Index (BaseGrid gm v)) ⇒ gm v → [(k, v)]+  toList = M.toList . toMap --- | /O(n)/. Fold the values in the grid map using the given left-associative--- binary operator.--- WARNING: The order in which the elements are processed is not guaranteed.-fold ∷ (a → b → a) → a → GridMap g k b → a-fold f x = applyToMap (M.foldl f x)+  -- | Lookup the value at a tile position in the grid map.+  lookup ∷ (k ~ (G.Index (BaseGrid gm v)), Ord k) ⇒ k → gm v → Maybe v+  lookup k = M.lookup k . toMap --- | /O(n)/. Fold the keys and values in the grid map using the given --- left-associative binary operator.--- WARNING: The order in which the elements are processed is not guaranteed.-foldWithKey ∷ (a → k → b → a) → a → GridMap g k b → a-foldWithKey f x = applyToMap (M.foldlWithKey f x)+  -- | Adjust a value at a specific tile position. When the tile is not+  --   within the bounds of the grid map, the original grid map is+  --   returned.+  adjust ∷ (k ~ (G.Index (BaseGrid gm v)), Ord k) ⇒ +    (v → v) → k → gm v → gm v+  adjust f = adjustWithKey (\_ v → f v) --- | /O(n)/. A strict version of 'fold'.-fold' ∷ (a → b → a) → a → GridMap g k b → a-fold' f x = applyToMap (M.foldl' f x)+  -- | Adjust a value at a specific tile position. When the tile is not+  --   within the bounds of the grid map, the original grid map is+  --   returned.+  adjustWithKey ∷ (k ~ (G.Index (BaseGrid gm v)), Ord k) ⇒ +    (k → v → v) → k → gm v → gm v --- | /O(n)/. A strict version of 'foldWithKey'.-foldWithKey' ∷ (a → k → b → a) → a → GridMap g k b → a-foldWithKey' f x = applyToMap (M.foldlWithKey' f x)+  -- | The expression @('findWithDefault' def k map)@ returns the value+  --   at tile position @k@ or returns @def@ when the tile is not within+  --   the bounds of the grid map.+  findWithDefault ∷ (k ~ (G.Index (BaseGrid gm v)), Ord k) ⇒ +    v → k → gm v → v+  findWithDefault v k = M.findWithDefault v k . toMap --- | /O(n)/.--- Return all elements of the grid map. The order is not guaranteed.-elems ∷ GridMap g k a → [a]-elems = applyToMap M.elems+  -- | Returns all values in the map +  elems ∷ gm v → [v]+  elems = M.elems . toMap --- | /O(n*min(n,W))/. The set of all tile positions in the grid map.-keysSet ∷ GridMap g k a → Set k-keysSet = applyToMap M.keysSet+  -- | Map a function over all values in the map.+  map ∷ GridMap gm b ⇒ (v → b) → gm v → gm b+  map f = mapWithKey (\_ v → f v) --- | /O(n)/. Returns all key (tile position)\/value pairs in the grid map.-toList ∷ GridMap g k a → [(k, a)]-toList = applyToMap M.toList+  -- | Map a function over all values in the map.+  mapWithKey +    ∷ (k ~ G.Index (BaseGrid gm v), GridMap gm v2) ⇒ +      (k → v → v2) → gm v → gm v2  {- $Compare Some functions in @Data.Map@ have been replaced in @GridMap@. These changes are listed in the table below.  @-Map function    | corresponding GridMap function-----------------+--------------------------------assocs          | 'toList'-empty           | 'lazyGridMap' g []-foldl           | 'fold'-foldl'          | 'fold''-foldlWithKey    | 'foldWithKey'-foldlWithKey'   | 'foldWithKey''-foldr           | 'fold'-foldr'          | 'fold''-foldrWithKey    | 'foldWithKey'-foldrWithKey'   | 'foldWithKey''-fromList        | 'lazyGridMap'-fromListWithKey | 'lazyGridMap'-fromListWith    | 'lazyGridMap'-fromSet         | 'lazyGridMap'-keys            | 'indices'-member          | 'inGrid'-notMember       | not 'inGrid'-null            | 'empty'-singleton       | 'lazyGridMap' g [v]-size            | 'size', 'tileCount'+Map function        | corresponding GridMap function+--------------------+----------------------------------------------+!                   | !+\\                  | See note 1+empty               | 'lazyGridMap' g []+findWithDefault     | 'findWithDefault'+insert              | See notes 1, 2+lookup              | 'lookup'+lookupLE            | See notes 1, 3+lookupLT            | See notes 1, 3+lookupGE            | See notes 1, 3+lookupGT            | See notes 1, 3+member              | 'inGrid'+notMember           | not 'inGrid'+null                | 'null'+singleton           | 'lazyGridMap' g [v]+size                | 'size', 'tileCount'*+insert              | See notes 1, 2+insertWith          | See notes 1, 2+insertWithKey       | See notes 1, 2+insertLookupWithKey | See notes 1, 2+delete              | See notes 1, 2+adjust              | 'adjust'+adjustWithKey       | 'adjustWithKey'+update              | See notes 1, 2+updateWithKey       | See notes 1, 2+updateLookupWithKey | See notes 1, 2+alter               | See notes 1, 2+union               | See notes 1, 2+unionWith           | See notes 1, 2+unionWithKey        | See notes 1, 2+unions              | See notes 1, 2+unionsWith          | See notes 1, 2+difference          | See notes 1, 2+differenceWith      | See notes 1, 2+differenceWithKey   | See notes 1, 2+intersection        | See notes 1, 2+intersectionWith    | See notes 1, 2+intersectionWithKey | See notes 1, 2+mergeWithKey        | See notes 1, 2+M.map               | fmap, or see note 1+mapWithKey          | See note 1+traverseWithKey     | See notes 1, 2+mapAccum            | See note 1+mapAccumWithKey     | See note 1+mapAccumRWithKey    | See note 1+mapKeys             | See note 1+mapKeysWith         | See note 1+mapKeysMonotonic    | See note 1+foldr               | See note 1+foldl               | See note 1+foldrWithKey        | See note 1+foldlWithKey        | See note 1+foldr'              | See note 1+foldl'              | See note 1+foldrWithKey'       | See note 1+foldlWithKey'       | See note 1+elems               | 'elems'+keys                | 'indices'+assocs              | See note 1+keysSet             | See note 1+fromSet             | 'lazyGridMap' (constructor)+toList              | See note 1+fromList            | 'lazyGridMap' (constructor)+fromListWithKey     | 'lazyGridMap' (constructor)+fromListWith        | 'lazyGridMap' (constructor)+toAscList           | See notes 1, 3+toDescList          | See notes 1, 3+fromAscList         | See notes 1, 3+fromAscListWith     | See notes 1, 3+fromAscListWithKey  | See notes 1, 3+fromDistinctAscList | See notes 1, 3+filter              | See notes 1, 2+filterWithKey       | See notes 1, 2+partition           | See notes 1, 2+partitionWithKey    | See notes 1, 2+mapMaybe            | See notes 1, 2+mapMaybeWithKey     | See notes 1, 2+mapEither           | See notes 1, 2+mapEitherWithKey    | See notes 1, 2+split               | See notes 1, 2+splitLookup         | See notes 1, 2+isSubmapOf          | See note 1+isSubmapOfBy        | See note 1+isProperSubmapOf    | See note 1+isProperSubmapOfBy  | See note 1+lookupIndex         | See note 1+findIndex           | See note 1+elemAt              | See note 1+updateAt            | See note 1+deleteAt            | See notes 1, 2+findMin             | See notes 1, 3+findMax             | See notes 1, 3+deleteMin           | See notes 1, 2, 3+deleteMax           | See notes 1, 2, 3+deleteFindMin       | See notes 1, 2, 3+deleteFindMax       | See notes 1, 2, 3+updateMin           | See notes 1, 2, 3+updateMax           | See notes 1, 2, 3+updateMinWithKey    | See notes 1, 2, 3+updateMaxWithKey    | See notes 1, 2, 3+minView             | See notes 1, 3+maxView             | See notes 1, 3+minViewWithKey      | See notes 1, 2, 3+maxViewWithKey      | See notes 1, 2, 3+showTree            | See note 1+showTreeWith        | See note 1+valid               | See note 1 @ -The functions (\\), @alter@, @delete@, @deleteFindMax@, @deleteFindMin@,-@deleteMax@, @deleteMin@, @difference@, @differenceWith@, @differenceWithKey@,-@filter@, @filterWithKey@, @insert@, @insertLookupWithKey@, @insertWith@,-@insertWithKey@, @intersection@, @intersectionWith@, @intersectionWithKey@,-@isProperSubmapOf@, @isProperSubmapOfBy@, @isSubmapOf@, @isSubmapOf@,-@isSubmapOfBy@, @mapEither@, @mapEitherWithKey@, @mapKeys@, @mapKeysWith@,-@mapMaybe@, @mapMaybeWithKey@, @mergeWithKey@, @partition@,-@partitionWithKey@, @split@, @splitLookup@, @traverseWithKey@, @union@,-@unions@, @unionsWith@, @unionWith@, @unionWithKey@, @update@,-@updateLookupWithKey@ and @updateWithKey@ are not implemented because the-resulting map might have different dimensions than the original, or because-they combine maps of different dimensions. -As a result, these functions may not be as useful for grid maps.-If you need one of these functions, you can extract the map using @toMap@-and apply the function from @Data.Map@ to the result.+Notes:+1. You can extract the map using @'toMap'@ and apply the function from+@Data.Map@ to the result. -The functions @deleteAt@, @elemAt@, @findIndex@, @findMax@, @findMin@, -@fromAscList@, @fromAscListWith@, @fromAscListWithKey@, @fromDistinctAscList@,-@lookupGE@, @lookupGT@, @lookupIndex@, @lookupLE@, @lookupLT@, -@mapAccumRWithKey@, @mapKeysMonotonic@, @maxView@, @maxViewWithKey@, -@minView@, @minViewWithKey@, @toAscList@, @toDescList@, @updateAt@, -@updateMax@, @updateMaxWithKey@, @updateMin@ and @updateMinWithKey@ are not-implemented because they rely on a meaningful ordering of keys.-While tile positions can be ordered (e.g., @(1,2) < (2,1)@), the ordering-may not be relevant to grid maps.-(Comparisons such as /east of/ or /south of/ may be more meaningful.)-If you need one of these functions, you can extract the map using @toMap@-and apply the function from @Data.Map@ to the result.+2. Not implemented because the resulting map might have different +dimensions than the original input @GridMap@(s). However, you can+extract the map using @'toMap'@ and apply the function from @Data.Map@+to the result. -The debugging functions @showTree@, @showTreeWith@ and @valid@ are not-implemented.-If you need one of these functions, you can extract the map using @toMap@-and apply the function from @Data.Map@ to the result.+3. Not implemented because, although tile positions can be ordered+(e.g., @(1,2) < (2,1)@), the ordering may not be meaningful for grid +maps. Comparisons such as /east of/ or /south of/ may be more useful.+However, you can extract the map using @'toMap'@ and apply the function+from @Data.Map@ to the result. -}  
+ src/Math/Geometry/GridMap/Lazy.hs view
@@ -0,0 +1,92 @@+------------------------------------------------------------------------+-- |+-- Module      :  Math.Geometry.GridMap+-- Copyright   :  (c) Amy de Buitléir 2012-2013+-- License     :  BSD-style+-- Maintainer  :  amy@nualeargais.ie+-- Stability   :  experimental+-- Portability :  portable+--+-- Ordered maps from tiles on a grid to values.+-- This module is a wrapper around @'Math.Geometry.Grid'@ and +-- @'Data.Map'@, in order to combine the functionality of grids and maps+-- into a single type.+--+------------------------------------------------------------------------+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts,+    FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}++module Math.Geometry.GridMap.Lazy+  (+    LGridMap,+    lazyGridMap+  ) where++import Prelude hiding (lookup, map, foldr, foldl, foldr1, foldl1, null)++import qualified Prelude as P (map)+import Data.Eq.Unicode ((≡))+import qualified Data.Foldable as F (Foldable(..))+import qualified Data.Map as M+--import qualified Data.Map.Strict as Strict (Map)+import Data.Maybe (fromMaybe)+import qualified Math.Geometry.Grid as G+import Math.Geometry.GridMap++-- | A map from tile positions in a grid to values. +data LGridMap g v = +  LGridMap { lgmGrid ∷ g, lgmMap ∷ M.Map (G.Index g) v }++-- | Construct a grid map which is strict in the keys (tile positions), but+--   lazy in the values.+lazyGridMap ∷ (Ord (G.Index g), G.Grid g) ⇒ g → [v] → LGridMap g v+lazyGridMap g vs = LGridMap g (M.fromList kvs)+  where kvs = zip ks vs+        ks = G.indices g++instance (G.Grid g, Ord (G.Index g)) ⇒ Functor (LGridMap g) where+  fmap f gm = lazyGridMap (lgmGrid gm) (P.map f vs)+    where vs = M.elems (lgmMap gm)++instance F.Foldable (LGridMap g) where+  fold = F.fold . lgmMap+  foldMap f g = F.foldMap f (lgmMap g)+  foldr f x g = F.foldr f x (lgmMap g)+  foldr' f x g = F.foldr' f x (lgmMap g)+  foldl f x g = F.foldl f x (lgmMap g)+  foldl' f x g = F.foldl' f x (lgmMap g)+--  foldr1 f x g = foldr1 f x (lgmMap g)+--  foldl1 f x g = foldl1 f x (lgmMap g)++instance G.Grid g ⇒ G.Grid (LGridMap g v) where+  type Index (LGridMap g v) = G.Index g+  indices = G.indices . lgmGrid+  distance g = G.distance (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+  tileCount  = G.tileCount . lgmGrid+  null = G.null . lgmGrid+  nonNull = G.nonNull . lgmGrid++instance G.FiniteGrid g ⇒ G.FiniteGrid (LGridMap g v) where+  type Size (LGridMap g v) = G.Size g+  size (LGridMap g _) = G.size g++instance (G.Grid g) ⇒ GridMap (LGridMap g) v where+  type BaseGrid (LGridMap g) v = g+  (!) gm k = toMap gm M.! k+  toMap = lgmMap+  toGrid = lgmGrid+  lookup k = M.lookup k . toMap+  adjustWithKey f k gm = gm { lgmMap = M.adjustWithKey f k (lgmMap gm)}+  findWithDefault v k = fromMaybe v . lookup k+  map f (LGridMap g m) = LGridMap g (M.map f m)+  mapWithKey f (LGridMap g m) = LGridMap g (M.mapWithKey f m)++instance (Eq g, Eq (G.Index g), Eq v) ⇒ Eq (LGridMap g v) where+  (==) (LGridMap g1 gm1) (LGridMap g2 gm2) = g1 ≡ g2 && gm1 ≡ gm2++instance (Show g, Show v) ⇒ Show (LGridMap g v) where+  show (LGridMap g m) = "lazyGridMap (" ++ show g ++ ") " ++ show (M.elems m)+
test/Math/Geometry/GridQC.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE UnicodeSyntax, ExistentialQuantification #-}+{-# LANGUAGE UnicodeSyntax, FlexibleContexts, ExistentialQuantification,+    TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module Math.Geometry.GridQC@@ -8,8 +9,10 @@  import Math.Geometry.GridInternal  +import Prelude hiding (null)+import qualified Prelude as P (null) import Data.Eq.Unicode ((≡), (≠))-import Data.List (nub, sort)+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)@@ -24,7 +27,7 @@   where n' = fromIntegral n ∷ Float  -- Given an arbitrary integer, select a corresponding point in the grid.-pointAt ∷ Grid g s x ⇒ g → Int → x+pointAt ∷ Grid g ⇒ g → Int → Index g pointAt g i = indices g !! (i `mod` n)   where n = (length . indices) g @@ -32,69 +35,78 @@ -- Tests that should apply to and are identical for all grids -- -prop_distance_reflexive ∷ Grid g s x ⇒ g → Int → Property-prop_distance_reflexive g i = nonEmpty g ==> distance g a a ≡ 0+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 s x ⇒ g → Int → Int → Property+prop_distance_symmetric ∷ Grid g ⇒ g → Int → Int → Property prop_distance_symmetric g i j = -  nonEmpty g ==> distance g a b ≡ distance g b a+  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 s x ⇒ g → Int → [Int] → Property+prop_minDistance_cw_distance ∷ Grid g ⇒ g → Int → [Int] → Property prop_minDistance_cw_distance g i js = -  nonEmpty g && (not . null) 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 s x, Ord x) ⇒ g → Int → Property-prop_neighbours_cw_viewpoint g i = n > 0 ==> -  sort (neighbours g a) ≡ sort expected-    where n = (length . indices) g-          a = indices g !! (i `mod` n) -- make sure point is in grid+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 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 s x, Ord x) ⇒ g → Int → Property-prop_edges_cw_neighbours g i = n > 0 ==> +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 n = (length . indices) g-          a = indices g !! (i `mod` n) -- make sure point is in grid+    where a = g `pointAt` i           nEdges = filter (`involves` a) $ edges g-          expected = filter (≠ a) $ nub $ map fst nEdges ++ map snd nEdges+          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 s x, Ord x) ⇒ g → Property+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 s x ⇒ g → Int → Int → Property-prop_adjacentTilesToward_moves_closer g i j = nonEmpty 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 s x ⇒ g → Int → Int → Property-prop_minimal_paths_have_min_length g i j = nonEmpty g ==> ns ≡ [d+1]+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 s x ⇒ g → Int → Int → Property-prop_minimal_paths_are_valid g i j = nonEmpty g ==> +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 s x ⇒ g → [x] → Bool+subsequentTilesInPathAreAdjacent +  ∷ (Grid g, Eq (Index g)) ⇒ g → [Index g] → Bool subsequentTilesInPathAreAdjacent _ [] = True subsequentTilesInPathAreAdjacent g [x] = x `elem` indices g subsequentTilesInPathAreAdjacent g (a:b:xs) = @@ -105,25 +117,31 @@ --  prop_grid_and_boundary_are_both_null_or_not -  ∷ BoundedGrid g s x ⇒ g → Property+  ∷ BoundedGrid g ⇒ g → Property prop_grid_and_boundary_are_both_null_or_not g = property $-  (null . boundary) g ≡ empty g+  (P.null . boundary) g ≡ null g -prop_boundary_in_grid ∷ BoundedGrid g s x ⇒ g → Property+prop_boundary_in_grid ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Property prop_boundary_in_grid g = property $   all (g `contains`) . boundary $ g -prop_centres_equidistant_from_boundary ∷ BoundedGrid g s x ⇒ g → Property-prop_centres_equidistant_from_boundary g = nonEmpty 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 --- Note: We only need to test one of the centres, because the previous--- test proves they are all equidistant from the boundary.-prop_centres_farthest_from_boundary ∷ BoundedGrid g s x ⇒ g → Int → Property+prop_centres_farthest_from_boundary +  ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Int → Property prop_centres_farthest_from_boundary g i = -  nonEmpty g && (not . isCentre g) a ==>+  nonNull g && (not . isCentre g) a ==>     minDistance g bs a ≤ minDistance g bs c   where a = g `pointAt` i         (c:_) = centre g@@ -133,7 +151,7 @@ -- Triangular grids with triangular tiles -- --- We want the number of tiles in a test grid to be ~ n+-- 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) @@ -146,7 +164,7 @@     where s = size g  prop_TriTriGrid_distance_in_bounds ∷ TriTriGrid → Int → Int → Property-prop_TriTriGrid_distance_in_bounds g i j = nonEmpty g ==> +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@@ -163,7 +181,7 @@         s = size g  prop_TriTriGrid_neighbour_count_in_bounds ∷ TriTriGrid → Int → Property-prop_TriTriGrid_neighbour_count_in_bounds g i = nonEmpty g ==>+prop_TriTriGrid_neighbour_count_in_bounds g i = nonNull g ==>   if tileCount g ≡ 1     then length (neighbours g x) ≡ 0     else length (neighbours g x) `elem` [1,2,3]@@ -184,7 +202,7 @@ -- Parallelogram-shaped grids with triangular tiles -- --- We want the number of tiles in a test grid to be ~ n+-- 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)@@ -200,7 +218,7 @@     where (r, c) = size g  prop_ParaTriGrid_distance_in_bounds ∷ ParaTriGrid → Int → Int → Property-prop_ParaTriGrid_distance_in_bounds g i j = nonEmpty g ==> +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@@ -218,7 +236,7 @@           (r, c) = size g  prop_ParaTriGrid_neighbour_count_in_bounds ∷ ParaTriGrid → Int → Property-prop_ParaTriGrid_neighbour_count_in_bounds g i = nonEmpty g ==>+prop_ParaTriGrid_neighbour_count_in_bounds g i = nonNull g ==>   if tileCount g ≡ 1     then length (neighbours g x) ≡ 0     else length (neighbours g x) `elem` [1,2,3]@@ -238,10 +256,90 @@   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 ==>+  if tileCount g ≡ 1+    then length (neighbours g x) ≡ 0+    else length (neighbours g x) `elem` [1,2,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 ==>+  if tileCount g ≡ 1+    then length (neighbours g x) ≡ 0+    else length (neighbours g x) `elem` [1,2,3]+  where x = g `pointAt` i++-- -- Rectangular grids with square tiles -- --- We want the number of tiles in a test grid to be ~ n+-- 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)@@ -257,7 +355,7 @@     where (r, c) = size g  prop_RectSquareGrid_distance_in_bounds ∷ RectSquareGrid → Int → Int → Property-prop_RectSquareGrid_distance_in_bounds g i j = nonEmpty g ==>+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@@ -276,7 +374,7 @@  prop_RectSquareGrid_neighbour_count_in_bounds ∷    RectSquareGrid → Int → Property-prop_RectSquareGrid_neighbour_count_in_bounds g i = nonEmpty g ==> f+prop_RectSquareGrid_neighbour_count_in_bounds g i = nonNull g ==> f   where x = g `pointAt` i         neighbourCount = length (neighbours g x)         (r, c) = size g@@ -286,7 +384,7 @@  prop_RectSquareGrid_num_min_paths_correct ∷    RectSquareGrid → Int → Int → Property-prop_RectSquareGrid_num_min_paths_correct g i j = nonEmpty g ==>+prop_RectSquareGrid_num_min_paths_correct g i j = nonNull g ==>   length (minimalPaths g a b) ≡ M.choose (deltaX+deltaY) deltaX     where a = g `pointAt` i           b = g `pointAt` j@@ -313,7 +411,7 @@ -- Toroidal grids with square-ish tiles -- --- We want the number of tiles in a test grid to be ~ n+-- 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)@@ -329,7 +427,7 @@     where (r, c) = size g  prop_TorSquareGrid_distance_in_bounds ∷ TorSquareGrid → Int → Int → Property-prop_TorSquareGrid_distance_in_bounds g i j = nonEmpty g ==>+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@@ -349,19 +447,22 @@             | otherwise      = 2  prop_TorSquareGrid_neighbour_count_in_bounds ∷ TorSquareGrid → Int → Property-prop_TorSquareGrid_neighbour_count_in_bounds g i = nonEmpty g ==> f+prop_TorSquareGrid_neighbour_count_in_bounds g i = nonNull g ==> f   where x = g `pointAt` i-        neighbourCount = length (neighbours g x)+        neighbourCount = length . neighbours g $ x         (r, c) = size g-        f | tileCount g ≡ 1 = neighbourCount ≡ 0-          | r ≡ 1 || c ≡ 1  = neighbourCount `elem` [1,2]-          | otherwise       = neighbourCount `elem` [2,3,4]+        f | tileCount g ≡ 1                = neighbourCount ≡ 1+          | (r,c) ≡ (1,2) || (r,c) ≡ (2,1) = neighbourCount ≡ 2+          | (r,c) ≡ (2,2)                  = neighbourCount ≡ 2+          | r ≡ 1 || c ≡ 1                 = neighbourCount ≡ 3+          | r ≡ 2 || c ≡ 2                 = neighbourCount ≡ 3+          | otherwise                      = neighbourCount ≡ 4  -- -- Circular hexagonal grids    -- --- We want the number of tiles in a test grid to be ~ n+-- 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)@@ -375,7 +476,7 @@     where s = size g  prop_HexHexGrid_distance_in_bounds ∷ HexHexGrid → Int → Int → Property-prop_HexHexGrid_distance_in_bounds g i j = nonEmpty g ==>+prop_HexHexGrid_distance_in_bounds g i j = nonNull g ==>   distance g a b < 2*s     where s = size g           a = g `pointAt` i@@ -392,7 +493,7 @@         s = size g  prop_HexHexGrid_neighbour_count_in_bounds ∷ HexHexGrid → Int → Property-prop_HexHexGrid_neighbour_count_in_bounds g i = nonEmpty g ==> +prop_HexHexGrid_neighbour_count_in_bounds g i = nonNull g ==>    if tileCount g ≡ 1     then length (neighbours g x) ≡ 0     else length (neighbours g x) `elem` [2,3,4,5,6]@@ -414,7 +515,7 @@ -- Parallelogrammatical hexagonal grids    -- --- We want the number of tiles in a test grid to be ~ n+-- 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)@@ -430,7 +531,7 @@     where (r, c) = size g  prop_ParaHexGrid_distance_in_bounds ∷ ParaHexGrid → Int → Int → Property-prop_ParaHexGrid_distance_in_bounds g i j = nonEmpty g ==>+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@@ -448,7 +549,7 @@           (r, c) = size g  prop_ParaHexGrid_neighbour_count_in_bounds ∷ ParaHexGrid → Int → Property-prop_ParaHexGrid_neighbour_count_in_bounds g i = nonEmpty g ==> f+prop_ParaHexGrid_neighbour_count_in_bounds g i = nonNull g ==> f   where x = g `pointAt` i         neighbourCount = length (neighbours g x)         (r, c) = size g@@ -481,6 +582,8 @@       (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"@@ -523,6 +626,8 @@       (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"@@ -552,6 +657,76 @@     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,@@ -565,6 +740,8 @@       (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"@@ -639,6 +816,8 @@       (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"@@ -681,6 +860,8 @@       (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"