{-# LANGUAGE UnicodeSyntax, FlexibleContexts, ExistentialQuantification, TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Math.Geometry.GridQC ( test ) where import Math.Geometry.GridInternal import Prelude hiding (null) import qualified Prelude as P (null) import Data.Eq.Unicode ((≡), (≠)) import Data.List (delete, nub, sort) import Data.Ord.Unicode ((≤)) import qualified Math.Combinatorics.Exact.Binomial as M (choose) import Test.Framework as TF (Test, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck ((==>), Gen, Arbitrary, arbitrary, sized, choose, Property, property) -- | @'isqrt' n@ returns the greatest integer not greater than the square root -- of @n@. isqrt ∷ Int → Int isqrt n = (floor . sqrt) n' where n' = fromIntegral n ∷ Float -- Given an arbitrary integer, select a corresponding point in the grid. pointAt ∷ Grid g ⇒ g → Int → Index g pointAt g i = indices g !! (i `mod` n) where n = (length . indices) g -- -- Tests that should apply to and are identical for all grids -- prop_distance_reflexive ∷ Grid g ⇒ g → Int → Property prop_distance_reflexive g i = nonNull g ==> distance g a a ≡ 0 where a = g `pointAt` i prop_distance_symmetric ∷ Grid g ⇒ g → Int → Int → Property prop_distance_symmetric g i j = nonNull g ==> distance g a b ≡ distance g b a where a = g `pointAt` i b = g `pointAt` j -- "cw" = "consistent with" prop_minDistance_cw_distance ∷ Grid g ⇒ g → Int → [Int] → Property prop_minDistance_cw_distance g i js = nonNull g && (not . P.null) js ==> minDistance g (b:bs) a ≤ distance g b a where a = g `pointAt` i (b:bs) = map (g `pointAt`) js prop_neighbours_cw_viewpoint ∷ (Grid g, Ord (Index g)) ⇒ g → Int → Property prop_neighbours_cw_viewpoint g i = nonNull g ==> sort (delete a (neighbours g a)) ≡ sort expected where a = g `pointAt` i expected = map fst $ filter (\p → 1 ≡ snd p) $ viewpoint g a -- Note: In a small grid, a tile can be its own neighbour. However, when -- we calculate the distance between a tile and itself, we get 0, not 1. -- That's why we have to delete the tile from its list before comparing -- to the result from the neighbours function. prop_edges_cw_neighbours ∷ (Grid g, Ord (Index g)) ⇒ g → Int → Property prop_edges_cw_neighbours g i = nonNull g ==> sort (neighbours g a) ≡ sort expected where a = g `pointAt` i nEdges = filter (`involves` a) $ edges g expected = map f nEdges f (b,c) = if a ≡ b then c else b involves ∷ Eq a ⇒ (a, a) → a → Bool involves (a, b) c = c ≡ a || c ≡ b prop_edges_are_adjacent ∷ (Grid g, Ord (Index g)) ⇒ g → Property prop_edges_are_adjacent g = property $ all f $ edges g where f (a, b) = isAdjacent g a b prop_adjacentTilesToward_moves_closer ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property prop_adjacentTilesToward_moves_closer g i j = nonNull g && a ≠ b ==> ns ≡ [d-1] where a = g `pointAt` i b = g `pointAt` j d = distance g a b ns = nub $ map (\x → distance g x b) $ adjacentTilesToward g a b prop_minimal_paths_have_min_length ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property prop_minimal_paths_have_min_length g i j = nonNull g ==> ns ≡ [d+1] where a = g `pointAt` i b = g `pointAt` j d = distance g a b ns = nub $ map length $ minimalPaths g a b prop_minimal_paths_are_valid ∷ (Grid g, Eq (Index g)) ⇒ g → Int → Int → Property prop_minimal_paths_are_valid g i j = nonNull g ==> and $ map (subsequentTilesInPathAreAdjacent g) $ minimalPaths g a b where a = g `pointAt` i b = g `pointAt` j subsequentTilesInPathAreAdjacent ∷ (Grid g, Eq (Index g)) ⇒ g → [Index g] → Bool subsequentTilesInPathAreAdjacent _ [] = True subsequentTilesInPathAreAdjacent g [x] = x `elem` indices g subsequentTilesInPathAreAdjacent g (a:b:xs) = isAdjacent g a b && subsequentTilesInPathAreAdjacent g (b:xs) -- -- Tests that should apply to and are identical for all bounded grids -- prop_grid_and_boundary_are_both_null_or_not ∷ BoundedGrid g ⇒ g → Property prop_grid_and_boundary_are_both_null_or_not g = property $ (P.null . boundary) g ≡ null g prop_boundary_in_grid ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Property prop_boundary_in_grid g = property $ all (g `contains`) . boundary $ g prop_boundary_tiles_have_fewer_neighbours ∷ BoundedGrid g ⇒ g → Int → Property prop_boundary_tiles_have_fewer_neighbours g i = nonNull g ==> g `numNeighbours` b ≤ g `numNeighbours` a where a = g `pointAt` i (b:_) = boundary g prop_centres_equidistant_from_boundary ∷ BoundedGrid g ⇒ g → Property prop_centres_equidistant_from_boundary g = nonNull g ==> (length . nub . map (minDistance g bs)) cs ≡ 1 where bs = boundary g cs = centre g prop_centres_farthest_from_boundary ∷ (BoundedGrid g, Eq (Index g)) ⇒ g → Int → Property prop_centres_farthest_from_boundary g i = nonNull g && (not . isCentre g) a ==> minDistance g bs a ≤ minDistance g bs c where a = g `pointAt` i (c:_) = centre g bs = boundary g -- -- Triangular grids with triangular tiles -- -- We want the number of tiles in a test grid to be O(n) sizedTriTriGrid ∷ Int → Gen TriTriGrid sizedTriTriGrid n = return $ triTriGrid (2 * isqrt n) instance Arbitrary TriTriGrid where arbitrary = sized sizedTriTriGrid prop_TriTriGrid_tile_count_correct ∷ TriTriGrid → Property prop_TriTriGrid_tile_count_correct g = property $ (length . indices) g ≡ if s ≤ 0 then 0 else s*s where s = size g prop_TriTriGrid_distance_in_bounds ∷ TriTriGrid → Int → Int → Property prop_TriTriGrid_distance_in_bounds g i j = nonNull g ==> distance g a b ≤ 2*(s-1) where s = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by triTriGrid is ever changed, this property -- may need to be changed too. It relies on the first and last elements being -- at corners. prop_TriTriGrid_distance_edge_to_edge ∷ TriTriGrid → Property prop_TriTriGrid_distance_edge_to_edge g = s > 0 ==> distance g a b ≡ 2*(s-1) where ps = indices g a = head ps b = last ps s = size g prop_TriTriGrid_neighbour_count_in_bounds ∷ TriTriGrid → Int → Property prop_TriTriGrid_neighbour_count_in_bounds g i = nonNull g ==> 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_TriTriGrid_boundary_count_correct ∷ TriTriGrid → Property prop_TriTriGrid_boundary_count_correct g = property $ (length . boundary) g ≡ (f . size) g where f 0 = 0 f 1 = 1 f s = 3*(s-1) prop_TriTriGrid_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Property prop_TriTriGrid_boundary_tiles_have_fewer_neighbours g = property $ all (3>) . map (numNeighbours g) . boundary $ g -- -- Parallelogram-shaped grids with triangular tiles -- -- We want the number of tiles in a test grid to be O(n) sizedParaTriGrid ∷ Int → Gen ParaTriGrid sizedParaTriGrid n = do r ← choose (0,n) let c = n `div` (2*r + 1) return $ paraTriGrid r c instance Arbitrary ParaTriGrid where arbitrary = sized sizedParaTriGrid prop_ParaTriGrid_tile_count_correct ∷ ParaTriGrid → Property prop_ParaTriGrid_tile_count_correct g = property $ tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else 2*r*c where (r, c) = size g prop_ParaTriGrid_distance_in_bounds ∷ ParaTriGrid → Int → Int → Property prop_ParaTriGrid_distance_in_bounds g i j = nonNull g ==> distance g a b ≤ 2*(r+c) - 3 where (r, c) = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by paraTriGrid is ever changed, this -- property may need to be changed too. It relies on the first and last -- elements being at corners. prop_ParaTriGrid_distance_corner_to_corner ∷ ParaTriGrid → Property prop_ParaTriGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> distance g a b ≡ 2*(r+c) - 3 where ps = indices g a = head ps b = last ps (r, c) = size g prop_ParaTriGrid_neighbour_count_in_bounds ∷ ParaTriGrid → Int → Property prop_ParaTriGrid_neighbour_count_in_bounds g i = nonNull g ==> 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_ParaTriGrid_boundary_count_correct ∷ ParaTriGrid → Property prop_ParaTriGrid_boundary_count_correct g = property $ (length . boundary) g ≡ (f . size) g where f (0,_) = 0 f (_,0) = 0 f (1,c) = 2*c f (r,1) = 2*r f (r,c) = 2*(r+c-1) prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours ∷ ParaTriGrid → Property prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours g = property $ all (3>) . map (numNeighbours g) . boundary $ g -- -- Rectangular grids with triangular tiles -- -- We want the number of tiles in a test grid to be O(n) sizedRectTriGrid ∷ Int → Gen RectTriGrid sizedRectTriGrid n = do r ← choose (0,n) let c = n `div` (2*r + 1) return $ rectTriGrid r c instance Arbitrary RectTriGrid where arbitrary = sized sizedRectTriGrid prop_RectTriGrid_tile_count_correct ∷ RectTriGrid → Property prop_RectTriGrid_tile_count_correct g = property $ tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else 2*r*c where (r, c) = size g prop_RectTriGrid_distance_in_bounds ∷ RectTriGrid → Int → Int → Property prop_RectTriGrid_distance_in_bounds g i j = nonNull g ==> distance g a b ≤ 2*(r+c) - 3 where (r, c) = size g a = g `pointAt` i b = g `pointAt` j prop_RectTriGrid_neighbour_count_in_bounds ∷ RectTriGrid → Int → Property prop_RectTriGrid_neighbour_count_in_bounds g i = nonNull g ==> 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 O(n) sizedRectSquareGrid ∷ Int → Gen RectSquareGrid sizedRectSquareGrid n = do r ← choose (0,n) let c = n `div` (r+1) return $ rectSquareGrid r c instance Arbitrary RectSquareGrid where arbitrary = sized sizedRectSquareGrid prop_RectSquareGrid_tile_count_correct ∷ RectSquareGrid → Property prop_RectSquareGrid_tile_count_correct g = property $ tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c where (r, c) = size g prop_RectSquareGrid_distance_in_bounds ∷ RectSquareGrid → Int → Int → Property prop_RectSquareGrid_distance_in_bounds g i j = nonNull g ==> distance g a b ≤ r + c - 2 where (r, c) = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by rectSquareGrid is ever changed, this -- property may need to be changed too. It relies on the first and last -- elements being at opposite corners. prop_RectSquareGrid_distance_corner_to_corner ∷ RectSquareGrid → Property prop_RectSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> distance g a b ≡ r + c - 2 where (r, c) = size g ps = indices g a = head ps b = last ps prop_RectSquareGrid_neighbour_count_in_bounds ∷ RectSquareGrid → Int → Property prop_RectSquareGrid_neighbour_count_in_bounds g i = nonNull g ==> f where x = g `pointAt` i 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] prop_RectSquareGrid_num_min_paths_correct ∷ RectSquareGrid → Int → Int → Property 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 deltaX = abs $ fst b - fst a deltaY = abs $ snd b - snd a prop_RectSquareGrid_boundary_count_correct ∷ RectSquareGrid → Property prop_RectSquareGrid_boundary_count_correct g = property $ (length . boundary) g ≡ (cartesianBoundaryCount . size) g cartesianBoundaryCount ∷ (Eq a, Num a) ⇒ (a, a) → a cartesianBoundaryCount (0,_) = 0 cartesianBoundaryCount (_,0) = 0 cartesianBoundaryCount (1,c) = c cartesianBoundaryCount (r,1) = r cartesianBoundaryCount (r,c) = 2*(r+c) - 4 prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours ∷ RectSquareGrid → Property prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours g = property $ all (4>) . map (numNeighbours g) . boundary $ g -- -- Toroidal grids with square-ish tiles -- -- We want the number of tiles in a test grid to be O(n) sizedTorSquareGrid ∷ Int → Gen TorSquareGrid sizedTorSquareGrid n = do r ← choose (0,n) let c = n `div` (r+1) return $ torSquareGrid r c instance Arbitrary TorSquareGrid where arbitrary = sized sizedTorSquareGrid prop_TorSquareGrid_tile_count_correct ∷ TorSquareGrid → Property prop_TorSquareGrid_tile_count_correct g = property $ tileCount g ≡ if r ≤ 0 || c ≤ 0 then 0 else r*c where (r, c) = size g prop_TorSquareGrid_distance_in_bounds ∷ TorSquareGrid → Int → Int → Property prop_TorSquareGrid_distance_in_bounds g i j = nonNull g ==> distance g a b ≤ (r+c) `div` 2 where (r, c) = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by torSquareGrid is ever changed, this property -- may need to be changed too. prop_TorSquareGrid_distance_corner_to_corner ∷ TorSquareGrid → Property prop_TorSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> distance g a b ≡ f where (r, c) = size g ps = indices g a = head ps b = last ps f | r ≡ 1 && c ≡ 1 = 0 -- zero-size torus | r ≡ 1 || c ≡ 1 = 1 -- a and b are the same | otherwise = 2 prop_TorSquareGrid_neighbour_count_in_bounds ∷ TorSquareGrid → Int → Property prop_TorSquareGrid_neighbour_count_in_bounds g i = nonNull g ==> f where x = g `pointAt` i neighbourCount = length . neighbours g $ x (r, c) = size g 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 O(n) sizedHexHexGrid ∷ Int → Gen HexHexGrid sizedHexHexGrid n = return $ hexHexGrid s where s = isqrt (n `div` 3) instance Arbitrary HexHexGrid where arbitrary = sized sizedHexHexGrid prop_HexHexGrid_tile_count_correct ∷ HexHexGrid → Property prop_HexHexGrid_tile_count_correct g = property $ (length . indices) g ≡ if s ≤ 0 then 0 else 3*s*(s-1) + 1 where s = size g prop_HexHexGrid_distance_in_bounds ∷ HexHexGrid → Int → Int → Property prop_HexHexGrid_distance_in_bounds g i j = nonNull g ==> distance g a b < 2*s where s = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by hexHexGrid is ever changed, this property -- may need to be changed too. It relies on the first and last elements being -- on opposite edges. prop_HexHexGrid_distance_edge_to_edge ∷ HexHexGrid → Property prop_HexHexGrid_distance_edge_to_edge g = s > 0 ==> distance g a b ≡ 2*s - 2 where ps = indices g a = head ps b = last ps s = size g prop_HexHexGrid_neighbour_count_in_bounds ∷ HexHexGrid → Int → Property prop_HexHexGrid_neighbour_count_in_bounds g i = nonNull g ==> if tileCount g ≡ 1 then length (neighbours g x) ≡ 0 else length (neighbours g x) `elem` [2,3,4,5,6] where x = g `pointAt` i prop_HexHexGrid_boundary_count_correct ∷ HexHexGrid → Property prop_HexHexGrid_boundary_count_correct g = property $ (length . boundary) g ≡ (f . size) g where f 0 = 0 f 1 = 1 f s = 6*(s-1) prop_HexHexGrid_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Property prop_HexHexGrid_boundary_tiles_have_fewer_neighbours g = property $ all (5>) . map (numNeighbours g) . boundary $ g -- -- Parallelogrammatical hexagonal grids -- -- We want the number of tiles in a test grid to be O(n) sizedParaHexGrid ∷ Int → Gen ParaHexGrid sizedParaHexGrid n = do r ← choose (0,n) let c = n `div` (r+1) return $ paraHexGrid r c instance Arbitrary ParaHexGrid where arbitrary = sized sizedParaHexGrid prop_ParaHexGrid_tile_count_correct ∷ ParaHexGrid → Property prop_ParaHexGrid_tile_count_correct g = property $ tileCount g ≡ r*c where (r, c) = size g prop_ParaHexGrid_distance_in_bounds ∷ ParaHexGrid → Int → Int → Property prop_ParaHexGrid_distance_in_bounds g i j = nonNull g ==> property $ distance g a b ≤ r+c-2 where (r, c) = size g a = g `pointAt` i b = g `pointAt` j -- If the ordering produced by paraHexGrid is ever changed, this property -- may need to be changed too. It relies on the first and last elements being -- at opposite corners on the longer diagonal. prop_ParaHexGrid_distance_corner_to_corner ∷ ParaHexGrid → Property prop_ParaHexGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> distance g a b ≡ r+c-2 where ps = indices g a = head ps b = last ps (r, c) = size g prop_ParaHexGrid_neighbour_count_in_bounds ∷ ParaHexGrid → Int → Property prop_ParaHexGrid_neighbour_count_in_bounds g i = nonNull g ==> f where x = g `pointAt` i 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,5,6] prop_ParaHexGrid_boundary_count_correct ∷ ParaHexGrid → Property prop_ParaHexGrid_boundary_count_correct g = property $ (length . boundary) g ≡ (cartesianBoundaryCount . size) g prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Property prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours g = property $ all (5>) . map (numNeighbours g) . boundary $ g test ∷ Test test = testGroup "Math.Geometry.GridQC" [ -- TriTriGrid tests testProperty "prop_TriTriGrid_tile_count_correct" prop_TriTriGrid_tile_count_correct, testProperty "prop_distance_reflexive - TriTriGrid" (prop_distance_reflexive ∷ TriTriGrid → Int → Property), testProperty "prop_distance_symmetric - TriTriGrid" (prop_distance_symmetric ∷ TriTriGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - TriTriGrid" (prop_minDistance_cw_distance ∷ TriTriGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - TriTriGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ TriTriGrid → Property), testProperty "prop_boundary_in_grid - TriTriGrid" (prop_boundary_in_grid ∷ TriTriGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - TriTriGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Int → Property), testProperty "prop_TriTriGrid_boundary_count_correct" prop_TriTriGrid_boundary_count_correct, testProperty "prop_TriTriGrid_boundary_tiles_have_fewer_neighbours" prop_TriTriGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - TriTriGrid" (prop_centres_equidistant_from_boundary ∷ TriTriGrid → Property), testProperty "prop_centres_farthest_from_boundary - TriTriGrid" (prop_centres_farthest_from_boundary ∷ TriTriGrid → Int → Property), testProperty "prop_TriTriGrid_distance_in_bounds" prop_TriTriGrid_distance_in_bounds, testProperty "prop_TriTriGrid_distance_edge_to_edge" prop_TriTriGrid_distance_edge_to_edge, testProperty "prop_TriTriGrid_neighbour_count_in_bounds" prop_TriTriGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - TriTriGrid" (prop_neighbours_cw_viewpoint ∷ TriTriGrid → Int → Property), testProperty "prop_edges_cw_neighbours - TriTriGrid" ( prop_edges_cw_neighbours ∷ TriTriGrid → Int → Property), testProperty "prop_edges_are_adjacent - TriTriGrid" ( prop_edges_are_adjacent ∷ TriTriGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - TriTriGrid" ( prop_adjacentTilesToward_moves_closer ∷ TriTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - TriTriGrid" ( prop_minimal_paths_have_min_length ∷ TriTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - TriTriGrid" ( prop_minimal_paths_are_valid ∷ TriTriGrid → Int → Int → Property), -- ParaTriGrid tests testProperty "prop_ParaTriGrid_tile_count_correct" prop_ParaTriGrid_tile_count_correct, testProperty "prop_distance_reflexive - ParaTriGrid" (prop_distance_reflexive ∷ ParaTriGrid → Int → Property), testProperty "prop_distance_symmetric - ParaTriGrid" (prop_distance_symmetric ∷ ParaTriGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - ParaTriGrid" (prop_minDistance_cw_distance ∷ ParaTriGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - ParaTriGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ ParaTriGrid → Property), testProperty "prop_boundary_in_grid - ParaTriGrid" (prop_boundary_in_grid ∷ ParaTriGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - ParaTriGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ ParaTriGrid → Int → Property), testProperty "prop_ParaTriGrid_boundary_count_correct" prop_ParaTriGrid_boundary_count_correct, testProperty "prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours" prop_ParaTriGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - ParaTriGrid" (prop_centres_equidistant_from_boundary ∷ ParaTriGrid → Property), testProperty "prop_centres_farthest_from_boundary - ParaTriGrid" (prop_centres_farthest_from_boundary ∷ ParaTriGrid → Int → Property), testProperty "prop_ParaTriGrid_distance_in_bounds" prop_ParaTriGrid_distance_in_bounds, testProperty "prop_ParaTriGrid_distance_corner_to_corner" prop_ParaTriGrid_distance_corner_to_corner, testProperty "prop_ParaTriGrid_neighbour_count_in_bounds" prop_ParaTriGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - ParaTriGrid" (prop_neighbours_cw_viewpoint ∷ ParaTriGrid → Int → Property), testProperty "prop_edges_cw_neighbours - ParaTriGrid" ( prop_edges_cw_neighbours ∷ ParaTriGrid → Int → Property), testProperty "prop_edges_are_adjacent - ParaTriGrid" ( prop_edges_are_adjacent ∷ ParaTriGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - ParaTriGrid" ( prop_adjacentTilesToward_moves_closer ∷ ParaTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - ParaTriGrid" ( prop_minimal_paths_have_min_length ∷ ParaTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - ParaTriGrid" ( prop_minimal_paths_are_valid ∷ ParaTriGrid → Int → Int → Property), -- RectTriGrid tests testProperty "prop_RectTriGrid_tile_count_correct" prop_RectTriGrid_tile_count_correct, testProperty "prop_distance_reflexive - RectTriGrid" (prop_distance_reflexive ∷ RectTriGrid → Int → Property), testProperty "prop_distance_symmetric - RectTriGrid" (prop_distance_symmetric ∷ RectTriGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - RectTriGrid" (prop_minDistance_cw_distance ∷ RectTriGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - RectTriGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ RectTriGrid → Property), testProperty "prop_boundary_in_grid - RectTriGrid" (prop_boundary_in_grid ∷ RectTriGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - RectTriGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ RectTriGrid → Int → Property), testProperty "prop_RectTriGrid_boundary_count_correct" prop_RectTriGrid_boundary_count_correct, testProperty "prop_RectTriGrid_boundary_tiles_have_fewer_neighbours" prop_RectTriGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - RectTriGrid" (prop_centres_equidistant_from_boundary ∷ RectTriGrid → Property), testProperty "prop_centres_farthest_from_boundary - RectTriGrid" (prop_centres_farthest_from_boundary ∷ RectTriGrid → Int → Property), testProperty "prop_RectTriGrid_distance_in_bounds" prop_RectTriGrid_distance_in_bounds, testProperty "prop_RectTriGrid_neighbour_count_in_bounds" prop_RectTriGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - RectTriGrid" (prop_neighbours_cw_viewpoint ∷ RectTriGrid → Int → Property), testProperty "prop_edges_cw_neighbours - RectTriGrid" ( prop_edges_cw_neighbours ∷ RectTriGrid → Int → Property), testProperty "prop_edges_are_adjacent - RectTriGrid" ( prop_edges_are_adjacent ∷ RectTriGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - RectTriGrid" ( prop_adjacentTilesToward_moves_closer ∷ RectTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - RectTriGrid" ( prop_minimal_paths_have_min_length ∷ RectTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - RectTriGrid" ( prop_minimal_paths_are_valid ∷ RectTriGrid → Int → Int → Property), -- TorTriGrid tests testProperty "prop_TorTriGrid_tile_count_correct" prop_TorTriGrid_tile_count_correct, testProperty "prop_distance_reflexive - TorTriGrid" (prop_distance_reflexive ∷ TorTriGrid → Int → Property), testProperty "prop_distance_symmetric - TorTriGrid" (prop_distance_symmetric ∷ TorTriGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - TorTriGrid" (prop_minDistance_cw_distance ∷ TorTriGrid → Int → [Int] → Property), testProperty "prop_TorTriGrid_distance_in_bounds" prop_TorTriGrid_distance_in_bounds, testProperty "prop_TorTriGrid_neighbour_count_in_bounds" prop_TorTriGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - TorTriGrid" (prop_neighbours_cw_viewpoint ∷ TorTriGrid → Int → Property), testProperty "prop_edges_cw_neighbours - TorTriGrid" ( prop_edges_cw_neighbours ∷ TorTriGrid → Int → Property), testProperty "prop_edges_are_adjacent - TorTriGrid" ( prop_edges_are_adjacent ∷ TorTriGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - TorTriGrid" ( prop_adjacentTilesToward_moves_closer ∷ TorTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - TorTriGrid" ( prop_minimal_paths_have_min_length ∷ TorTriGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - TorTriGrid" ( prop_minimal_paths_are_valid ∷ TorTriGrid → Int → Int → Property), -- RectSquareGrid tests testProperty "prop_RectSquareGrid_tile_count_correct" prop_RectSquareGrid_tile_count_correct, testProperty "prop_distance_reflexive - RectSquareGrid" (prop_distance_reflexive ∷ RectSquareGrid → Int → Property), testProperty "prop_distance_symmetric - RectSquareGrid" (prop_distance_symmetric ∷ RectSquareGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - RectSquareGrid" (prop_minDistance_cw_distance ∷ RectSquareGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - RectSquareGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ RectSquareGrid → Property), testProperty "prop_boundary_in_grid - RectSquareGrid" (prop_boundary_in_grid ∷ RectSquareGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - RectSquareGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ RectSquareGrid → Int → Property), testProperty "prop_RectSquareGrid_boundary_count_correct" prop_RectSquareGrid_boundary_count_correct, testProperty "prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours" prop_RectSquareGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - RectSquareGrid" (prop_centres_equidistant_from_boundary ∷ RectSquareGrid → Property), testProperty "prop_centres_farthest_from_boundary - RectSquareGrid" (prop_centres_farthest_from_boundary ∷ RectSquareGrid → Int → Property), testProperty "prop_RectSquareGrid_distance_in_bounds" prop_RectSquareGrid_distance_in_bounds, testProperty "prop_RectSquareGrid_distance_corner_to_corner" prop_RectSquareGrid_distance_corner_to_corner, testProperty "prop_RectSquareGrid_neighbour_count_in_bounds" prop_RectSquareGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - RectSquareGrid" (prop_neighbours_cw_viewpoint ∷ RectSquareGrid → Int → Property), testProperty "prop_edges_cw_neighbours - RectSquareGrid" ( prop_edges_cw_neighbours ∷ RectSquareGrid → Int → Property), testProperty "prop_edges_are_adjacent - RectSquareGrid" ( prop_edges_are_adjacent ∷ RectSquareGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - RectSquareGrid" ( prop_adjacentTilesToward_moves_closer ∷ RectSquareGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - RectSquareGrid" ( prop_minimal_paths_have_min_length ∷ RectSquareGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - RectSquareGrid" ( prop_minimal_paths_are_valid ∷ RectSquareGrid → Int → Int → Property), testProperty "prop_RectSquareGrid_num_min_paths_correct" prop_RectSquareGrid_num_min_paths_correct, -- TorSquareGrid tests testProperty "prop_TorSquareGrid_tile_count_correct" prop_TorSquareGrid_tile_count_correct, testProperty "prop_distance_reflexive - TorSquareGrid" (prop_distance_reflexive ∷ TorSquareGrid → Int → Property), testProperty "prop_distance_symmetric - TorSquareGrid" (prop_distance_symmetric ∷ TorSquareGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - TorSquareGrid" (prop_minDistance_cw_distance ∷ TorSquareGrid → Int → [Int] → Property), testProperty "prop_TorSquareGrid_distance_in_bounds" prop_TorSquareGrid_distance_in_bounds, testProperty "prop_TorSquareGrid_distance_corner_to_corner" prop_TorSquareGrid_distance_corner_to_corner, testProperty "prop_TorSquareGrid_neighbour_count_in_bounds" prop_TorSquareGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - TorSquareGrid" (prop_neighbours_cw_viewpoint ∷ TorSquareGrid → Int → Property), testProperty "prop_edges_cw_neighbours - TorSquareGrid" ( prop_edges_cw_neighbours ∷ TorSquareGrid → Int → Property), testProperty "prop_edges_are_adjacent - TorSquareGrid" ( prop_edges_are_adjacent ∷ TorSquareGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - TorSquareGrid" ( prop_adjacentTilesToward_moves_closer ∷ TorSquareGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - TorSquareGrid" ( prop_minimal_paths_have_min_length ∷ TorSquareGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - TorSquareGrid" ( prop_minimal_paths_are_valid ∷ TorSquareGrid → Int → Int → Property), -- HexHexGrid tests testProperty "prop_HexHexGrid_tile_count_correct" prop_HexHexGrid_tile_count_correct, testProperty "prop_distance_reflexive - HexHexGrid" (prop_distance_reflexive ∷ HexHexGrid → Int → Property), testProperty "prop_distance_symmetric - HexHexGrid" (prop_distance_symmetric ∷ HexHexGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - HexHexGrid" (prop_minDistance_cw_distance ∷ HexHexGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - HexHexGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ HexHexGrid → Property), testProperty "prop_boundary_in_grid - HexHexGrid" (prop_boundary_in_grid ∷ HexHexGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - HexHexGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ HexHexGrid → Int → Property), testProperty "prop_HexHexGrid_boundary_count_correct" prop_HexHexGrid_boundary_count_correct, testProperty "prop_HexHexGrid_boundary_tiles_have_fewer_neighbours" prop_HexHexGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - HexHexGrid" (prop_centres_equidistant_from_boundary ∷ HexHexGrid → Property), testProperty "prop_centres_farthest_from_boundary - HexHexGrid" (prop_centres_farthest_from_boundary ∷ HexHexGrid → Int → Property), testProperty "prop_HexHexGrid_distance_in_bounds" prop_HexHexGrid_distance_in_bounds, testProperty "prop_HexHexGrid_distance_edge_to_edge" prop_HexHexGrid_distance_edge_to_edge, testProperty "prop_HexHexGrid_neighbour_count_in_bounds" prop_HexHexGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - HexHexGrid" (prop_neighbours_cw_viewpoint ∷ HexHexGrid → Int → Property), testProperty "prop_edges_cw_neighbours - HexHexGrid" ( prop_edges_cw_neighbours ∷ HexHexGrid → Int → Property), testProperty "prop_edges_are_adjacent - HexHexGrid" ( prop_edges_are_adjacent ∷ HexHexGrid → Property), testProperty "prop_adjacentTilesToward_moves_closer - HexHexGrid" ( prop_adjacentTilesToward_moves_closer ∷ HexHexGrid → Int → Int → Property), testProperty "prop_minimal_paths_have_min_length - HexHexGrid" ( prop_minimal_paths_have_min_length ∷ HexHexGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - HexHexGrid" ( prop_minimal_paths_are_valid ∷ HexHexGrid → Int → Int → Property), -- ParaHexGrid tests testProperty "prop_ParaHexGrid_tile_count_correct" prop_ParaHexGrid_tile_count_correct, testProperty "prop_distance_reflexive - ParaHexGrid" (prop_distance_reflexive ∷ ParaHexGrid → Int → Property), testProperty "prop_distance_symmetric - ParaHexGrid" (prop_distance_symmetric ∷ ParaHexGrid → Int → Int → Property), testProperty "prop_minDistance_cw_distance - ParaHexGrid" (prop_minDistance_cw_distance ∷ ParaHexGrid → Int → [Int] → Property), testProperty "prop_grid_and_boundary_are_both_null_or_not - ParaHexGrid" (prop_grid_and_boundary_are_both_null_or_not ∷ ParaHexGrid → Property), testProperty "prop_boundary_in_grid - ParaHexGrid" (prop_boundary_in_grid ∷ ParaHexGrid → Property), testProperty "prop_boundary_tiles_have_fewer_neighbours - TriTriGrid" (prop_boundary_tiles_have_fewer_neighbours ∷ TriTriGrid → Int → Property), testProperty "prop_ParaHexGrid_boundary_count_correct" prop_ParaHexGrid_boundary_count_correct, testProperty "prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours" prop_ParaHexGrid_boundary_tiles_have_fewer_neighbours, testProperty "prop_centres_equidistant_from_boundary - ParaHexGrid" (prop_centres_equidistant_from_boundary ∷ ParaHexGrid → Property), testProperty "prop_centres_farthest_from_boundary - ParaHexGrid" (prop_centres_farthest_from_boundary ∷ ParaHexGrid → Int → Property), testProperty "prop_ParaHexGrid_distance_in_bounds" prop_ParaHexGrid_distance_in_bounds, testProperty "prop_ParaHexGrid_distance_corner_to_corner" prop_ParaHexGrid_distance_corner_to_corner, testProperty "prop_ParaHexGrid_neighbour_count_in_bounds" prop_ParaHexGrid_neighbour_count_in_bounds, testProperty "prop_neighbours_cw_viewpoint - ParaHexGrid" (prop_neighbours_cw_viewpoint ∷ ParaHexGrid → Int → Property), testProperty "prop_edges_cw_neighbours - ParaHexGrid" ( prop_edges_cw_neighbours ∷ ParaHexGrid → Int → Property), testProperty "prop_adjacentTilesToward_moves_closer - ParaHexGrid" ( prop_adjacentTilesToward_moves_closer ∷ ParaHexGrid → Int → Int → Property), testProperty "prop_edges_are_adjacent - ParaHexGrid" ( prop_edges_are_adjacent ∷ ParaHexGrid → Property), testProperty "prop_minimal_paths_have_min_length - ParaHexGrid" ( prop_minimal_paths_have_min_length ∷ ParaHexGrid → Int → Int → Property), testProperty "prop_minimal_paths_are_valid - ParaHexGrid" ( prop_minimal_paths_are_valid ∷ ParaHexGrid → Int → Int → Property) ]