keid-geometry-0.1.1.2: src/Geometry/Tile/Neighbors.hs
module Geometry.Tile.Neighbors
( Neighbors(..)
, nobody
, everyone
, bitsNW
, testBitsNW
, fromBitsNW
, toBitsNW
, directionsWith
, isCorner
, names
) where
import RIO
import Data.Bits
import Resource.Collection (Generic1, Generically1(..), enumerate)
nobody :: Neighbors Bool
nobody = pure False
everyone :: Neighbors Bool
everyone = pure True
data Neighbors a = Neighbors
{ northWest :: a
, north :: a
, northEast :: a
, east :: a
, southEast :: a
, south :: a
, southWest :: a
, west :: a
}
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable, Generic1)
deriving Applicative via Generically1 Neighbors
bitsNW :: Neighbors Int
bitsNW = fmap fst . enumerate $ pure ()
{-# INLINE testBitsNW #-}
testBitsNW :: Bits a => Neighbors (a -> Bool)
testBitsNW =
bitsNW <&> \i packed ->
testBit packed i
{-# INLINE fromBitsNW #-}
fromBitsNW :: Bits a => a -> Neighbors Bool
fromBitsNW packed =
testBitsNW <&> \test ->
test packed
{-# INLINE toBitsNW #-}
toBitsNW :: Neighbors Bool -> Int
toBitsNW = toBits bitsNW
{-# INLINE toBits #-}
toBits :: Neighbors Int -> Neighbors Bool -> Int
toBits bits = foldl' (flip (.|.)) zeroBits . liftA2 toBit bits
where
toBit i = bool zeroBits (bit i)
directionsWith :: (Num a) => (a -> a -> b) -> Neighbors b
directionsWith f = Neighbors
{ northWest = f (-1) (-1)
, north = f 0 (-1)
, northEast = f 1 (-1)
, east = f 1 0
, southEast = f 1 1
, south = f 0 1
, southWest = f (-1) 1
, west = f (-1) 0
}
isCorner :: Neighbors Bool
isCorner = Neighbors
{ northWest = True
, north = False
, northEast = True
, east = False
, southEast = True
, south = False
, southWest = True
, west = False
}
names :: IsString a => Neighbors a
names = Neighbors
{ northWest = "nw"
, north = "n"
, northEast = "ne"
, east = "e"
, southEast = "se"
, south = "s"
, southWest = "sw"
, west = "w"
}