2019-09-29 16:54:52 +02:00
|
|
|
|
{-# LANGUAGE ViewPatterns #-}
|
2019-09-28 19:20:57 +02:00
|
|
|
|
{-# LANGUAGE RoleAnnotations #-}
|
2019-09-02 19:56:25 +02:00
|
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
2019-08-31 19:17:27 +02:00
|
|
|
|
{-# LANGUAGE DeriveTraversable #-}
|
|
|
|
|
{-# LANGUAGE DeriveFoldable #-}
|
|
|
|
|
{-# LANGUAGE DeriveFunctor #-}
|
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
-- | Common data types for Xanthous
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
module Xanthous.Data
|
2019-09-29 16:54:52 +02:00
|
|
|
|
( -- *
|
|
|
|
|
Position(..)
|
2019-08-31 19:17:27 +02:00
|
|
|
|
, x
|
|
|
|
|
, y
|
|
|
|
|
|
|
|
|
|
, Positioned(..)
|
2019-09-15 19:00:28 +02:00
|
|
|
|
, _Positioned
|
2019-08-31 19:17:27 +02:00
|
|
|
|
, position
|
|
|
|
|
, positioned
|
|
|
|
|
, loc
|
2019-09-15 19:00:28 +02:00
|
|
|
|
, _Position
|
2019-09-13 21:24:05 +02:00
|
|
|
|
, positionFromPair
|
2019-09-29 16:54:52 +02:00
|
|
|
|
, addPositions
|
|
|
|
|
, diffPositions
|
|
|
|
|
, stepTowards
|
|
|
|
|
, isUnit
|
2019-08-31 19:17:27 +02:00
|
|
|
|
|
2019-09-07 20:49:59 +02:00
|
|
|
|
-- *
|
|
|
|
|
, Dimensions'(..)
|
|
|
|
|
, Dimensions
|
|
|
|
|
, HasWidth(..)
|
|
|
|
|
, HasHeight(..)
|
|
|
|
|
|
2019-08-31 19:17:27 +02:00
|
|
|
|
-- *
|
|
|
|
|
, Direction(..)
|
|
|
|
|
, opposite
|
|
|
|
|
, move
|
|
|
|
|
, asPosition
|
2019-09-29 16:54:52 +02:00
|
|
|
|
, directionOf
|
2019-09-02 19:56:25 +02:00
|
|
|
|
|
|
|
|
|
-- *
|
2019-09-10 02:54:33 +02:00
|
|
|
|
, Neighbors(..)
|
|
|
|
|
, edges
|
|
|
|
|
, neighborDirections
|
|
|
|
|
, neighborPositions
|
2019-08-31 19:17:27 +02:00
|
|
|
|
) where
|
|
|
|
|
--------------------------------------------------------------------------------
|
2019-09-02 19:56:25 +02:00
|
|
|
|
import Xanthous.Prelude hiding (Left, Down, Right)
|
|
|
|
|
import Test.QuickCheck (Arbitrary, CoArbitrary, Function)
|
|
|
|
|
import Test.QuickCheck.Arbitrary.Generic
|
|
|
|
|
import Data.Group
|
2019-09-10 02:54:33 +02:00
|
|
|
|
import Brick (Location(Location), Edges(..))
|
2019-08-31 19:17:27 +02:00
|
|
|
|
--------------------------------------------------------------------------------
|
2019-09-02 19:56:25 +02:00
|
|
|
|
import Xanthous.Util (EqEqProp(..), EqProp)
|
|
|
|
|
import Xanthous.Orphans ()
|
2019-09-29 16:54:52 +02:00
|
|
|
|
import Xanthous.Util.Graphics
|
2019-08-31 19:17:27 +02:00
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
data Position where
|
|
|
|
|
Position :: { _x :: Int
|
|
|
|
|
, _y :: Int
|
|
|
|
|
} -> Position
|
|
|
|
|
deriving stock (Show, Eq, Generic, Ord)
|
|
|
|
|
deriving anyclass (Hashable, CoArbitrary, Function)
|
|
|
|
|
deriving EqProp via EqEqProp Position
|
|
|
|
|
makeLenses ''Position
|
|
|
|
|
|
|
|
|
|
instance Arbitrary Position where
|
|
|
|
|
arbitrary = genericArbitrary
|
|
|
|
|
shrink = genericShrink
|
|
|
|
|
|
|
|
|
|
instance Semigroup Position where
|
|
|
|
|
(Position x₁ y₁) <> (Position x₂ y₂) = Position (x₁ + x₂) (y₁ + y₂)
|
|
|
|
|
|
|
|
|
|
instance Monoid Position where
|
|
|
|
|
mempty = Position 0 0
|
|
|
|
|
|
|
|
|
|
instance Group Position where
|
|
|
|
|
invert (Position px py) = Position (-px) (-py)
|
|
|
|
|
|
|
|
|
|
data Positioned a where
|
|
|
|
|
Positioned :: Position -> a -> Positioned a
|
|
|
|
|
deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable, Generic)
|
|
|
|
|
deriving anyclass (CoArbitrary, Function)
|
2019-09-28 19:20:57 +02:00
|
|
|
|
type role Positioned representational
|
2019-08-31 19:17:27 +02:00
|
|
|
|
|
2019-09-15 19:00:28 +02:00
|
|
|
|
_Positioned :: Iso (Position, a) (Position, b) (Positioned a) (Positioned b)
|
|
|
|
|
_Positioned = iso hither yon
|
|
|
|
|
where
|
|
|
|
|
hither (pos, a) = Positioned pos a
|
|
|
|
|
yon (Positioned pos b) = (pos, b)
|
|
|
|
|
|
2019-08-31 19:17:27 +02:00
|
|
|
|
instance Arbitrary a => Arbitrary (Positioned a) where
|
|
|
|
|
arbitrary = Positioned <$> arbitrary <*> arbitrary
|
|
|
|
|
|
|
|
|
|
position :: Lens' (Positioned a) Position
|
|
|
|
|
position = lens
|
|
|
|
|
(\(Positioned pos _) -> pos)
|
|
|
|
|
(\(Positioned _ a) pos -> Positioned pos a)
|
|
|
|
|
|
|
|
|
|
positioned :: Lens (Positioned a) (Positioned b) a b
|
|
|
|
|
positioned = lens
|
|
|
|
|
(\(Positioned _ x') -> x')
|
|
|
|
|
(\(Positioned pos _) x' -> Positioned pos x')
|
|
|
|
|
|
|
|
|
|
loc :: Iso' Position Location
|
|
|
|
|
loc = iso hither yon
|
|
|
|
|
where
|
|
|
|
|
hither (Position px py) = Location (px, py)
|
|
|
|
|
yon (Location (lx, ly)) = Position lx ly
|
|
|
|
|
|
2019-09-15 19:00:28 +02:00
|
|
|
|
_Position :: Iso' Position (Int, Int)
|
|
|
|
|
_Position = iso hither yon
|
|
|
|
|
where
|
|
|
|
|
hither (Position px py) = (px, py)
|
|
|
|
|
yon (lx, ly) = Position lx ly
|
|
|
|
|
|
2019-09-13 21:24:05 +02:00
|
|
|
|
positionFromPair :: (Integral i, Integral j) => (i, j) -> Position
|
|
|
|
|
positionFromPair (i, j) = Position (fromIntegral i) (fromIntegral j)
|
|
|
|
|
|
2019-09-29 16:54:52 +02:00
|
|
|
|
-- | Add two positions
|
|
|
|
|
--
|
|
|
|
|
-- Operation for the additive group on positions
|
|
|
|
|
addPositions :: Position -> Position -> Position
|
|
|
|
|
addPositions = (<>)
|
|
|
|
|
|
|
|
|
|
-- | Subtract two positions.
|
|
|
|
|
--
|
|
|
|
|
-- diffPositions pos₁ pos₂ = pos₁ `addPositions` (invert pos₂)
|
|
|
|
|
diffPositions :: Position -> Position -> Position
|
|
|
|
|
diffPositions (Position x₁ y₁) (Position x₂ y₂) = Position (x₁ - x₂) (y₁ - y₂)
|
|
|
|
|
|
|
|
|
|
-- | Is this position a unit position? or: When taken as a difference, does this
|
|
|
|
|
-- position represent a step of one tile?
|
|
|
|
|
--
|
|
|
|
|
-- ∀ dir :: Direction. isUnit ('asPosition' dir)
|
|
|
|
|
isUnit :: Position -> Bool
|
|
|
|
|
isUnit (Position px py) = abs px == 1 || abs py == 1
|
|
|
|
|
|
2019-08-31 19:17:27 +02:00
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2019-09-07 20:49:59 +02:00
|
|
|
|
data Dimensions' a = Dimensions
|
|
|
|
|
{ _width :: a
|
|
|
|
|
, _height :: a
|
|
|
|
|
}
|
|
|
|
|
deriving stock (Show, Eq, Functor, Generic)
|
|
|
|
|
deriving anyclass (CoArbitrary, Function)
|
|
|
|
|
makeFieldsNoPrefix ''Dimensions'
|
|
|
|
|
|
|
|
|
|
instance Arbitrary a => Arbitrary (Dimensions' a) where
|
|
|
|
|
arbitrary = Dimensions <$> arbitrary <*> arbitrary
|
|
|
|
|
|
|
|
|
|
type Dimensions = Dimensions' Word
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2019-08-31 19:17:27 +02:00
|
|
|
|
data Direction where
|
|
|
|
|
Up :: Direction
|
|
|
|
|
Down :: Direction
|
|
|
|
|
Left :: Direction
|
|
|
|
|
Right :: Direction
|
|
|
|
|
UpLeft :: Direction
|
|
|
|
|
UpRight :: Direction
|
|
|
|
|
DownLeft :: Direction
|
|
|
|
|
DownRight :: Direction
|
2019-09-20 19:14:55 +02:00
|
|
|
|
Here :: Direction
|
2019-08-31 19:17:27 +02:00
|
|
|
|
deriving stock (Show, Eq, Generic)
|
|
|
|
|
|
|
|
|
|
instance Arbitrary Direction where
|
|
|
|
|
arbitrary = genericArbitrary
|
|
|
|
|
shrink = genericShrink
|
|
|
|
|
|
|
|
|
|
opposite :: Direction -> Direction
|
|
|
|
|
opposite Up = Down
|
|
|
|
|
opposite Down = Up
|
|
|
|
|
opposite Left = Right
|
|
|
|
|
opposite Right = Left
|
|
|
|
|
opposite UpLeft = DownRight
|
|
|
|
|
opposite UpRight = DownLeft
|
|
|
|
|
opposite DownLeft = UpRight
|
|
|
|
|
opposite DownRight = UpLeft
|
2019-09-20 19:14:55 +02:00
|
|
|
|
opposite Here = Here
|
2019-08-31 19:17:27 +02:00
|
|
|
|
|
|
|
|
|
move :: Direction -> Position -> Position
|
|
|
|
|
move Up = y -~ 1
|
|
|
|
|
move Down = y +~ 1
|
|
|
|
|
move Left = x -~ 1
|
|
|
|
|
move Right = x +~ 1
|
|
|
|
|
move UpLeft = move Up . move Left
|
|
|
|
|
move UpRight = move Up . move Right
|
|
|
|
|
move DownLeft = move Down . move Left
|
|
|
|
|
move DownRight = move Down . move Right
|
2019-09-20 19:14:55 +02:00
|
|
|
|
move Here = id
|
2019-08-31 19:17:27 +02:00
|
|
|
|
|
|
|
|
|
asPosition :: Direction -> Position
|
|
|
|
|
asPosition dir = move dir mempty
|
2019-09-02 19:56:25 +02:00
|
|
|
|
|
2019-09-29 16:54:52 +02:00
|
|
|
|
-- | Returns the direction that a given position is from a given source position
|
|
|
|
|
directionOf
|
|
|
|
|
:: Position -- ^ Source
|
|
|
|
|
-> Position -- ^ Target
|
|
|
|
|
-> Direction
|
|
|
|
|
directionOf (Position x₁ y₁) (Position x₂ y₂) =
|
|
|
|
|
case (x₁ `compare` x₂, y₁ `compare` y₂) of
|
|
|
|
|
(EQ, EQ) -> Here
|
|
|
|
|
(EQ, LT) -> Down
|
|
|
|
|
(EQ, GT) -> Up
|
|
|
|
|
(LT, EQ) -> Right
|
|
|
|
|
(GT, EQ) -> Left
|
|
|
|
|
|
|
|
|
|
(LT, LT) -> DownRight
|
|
|
|
|
(GT, LT) -> DownLeft
|
|
|
|
|
|
|
|
|
|
(LT, GT) -> UpRight
|
|
|
|
|
(GT, GT) -> UpLeft
|
|
|
|
|
|
|
|
|
|
-- | Take one (potentially diagonal) step towards the given position
|
|
|
|
|
--
|
|
|
|
|
-- ∀ src tgt. isUnit (src `diffPositions` (src `stepTowards tgt`))
|
|
|
|
|
stepTowards
|
|
|
|
|
:: Position -- ^ Source
|
|
|
|
|
-> Position -- ^ Target
|
|
|
|
|
-> Position
|
|
|
|
|
stepTowards (view _Position -> p₁) (view _Position -> p₂)
|
|
|
|
|
| p₁ == p₂ = _Position # p₁
|
|
|
|
|
| otherwise =
|
|
|
|
|
let (_:p:_) = line p₁ p₂
|
|
|
|
|
in _Position # p
|
|
|
|
|
|
2019-09-02 19:56:25 +02:00
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2019-09-10 02:54:33 +02:00
|
|
|
|
data Neighbors a = Neighbors
|
|
|
|
|
{ _topLeft
|
|
|
|
|
, _top
|
|
|
|
|
, _topRight
|
|
|
|
|
, _left
|
|
|
|
|
, _right
|
|
|
|
|
, _bottomLeft
|
|
|
|
|
, _bottom
|
|
|
|
|
, _bottomRight :: a
|
2019-09-02 19:56:25 +02:00
|
|
|
|
}
|
2019-09-10 02:54:33 +02:00
|
|
|
|
deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable, Generic)
|
2019-09-02 19:56:25 +02:00
|
|
|
|
deriving anyclass (NFData)
|
2019-09-10 02:54:33 +02:00
|
|
|
|
makeLenses ''Neighbors
|
|
|
|
|
|
|
|
|
|
instance Applicative Neighbors where
|
|
|
|
|
pure α = Neighbors
|
|
|
|
|
{ _topLeft = α
|
|
|
|
|
, _top = α
|
|
|
|
|
, _topRight = α
|
|
|
|
|
, _left = α
|
|
|
|
|
, _right = α
|
|
|
|
|
, _bottomLeft = α
|
|
|
|
|
, _bottom = α
|
|
|
|
|
, _bottomRight = α
|
|
|
|
|
}
|
|
|
|
|
nf <*> nx = Neighbors
|
|
|
|
|
{ _topLeft = nf ^. topLeft $ nx ^. topLeft
|
|
|
|
|
, _top = nf ^. top $ nx ^. top
|
|
|
|
|
, _topRight = nf ^. topRight $ nx ^. topRight
|
|
|
|
|
, _left = nf ^. left $ nx ^. left
|
|
|
|
|
, _right = nf ^. right $ nx ^. right
|
|
|
|
|
, _bottomLeft = nf ^. bottomLeft $ nx ^. bottomLeft
|
|
|
|
|
, _bottom = nf ^. bottom $ nx ^. bottom
|
|
|
|
|
, _bottomRight = nf ^. bottomRight $ nx ^. bottomRight
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edges :: Neighbors a -> Edges a
|
|
|
|
|
edges neighs = Edges
|
|
|
|
|
{ eTop = neighs ^. top
|
|
|
|
|
, eBottom = neighs ^. bottom
|
|
|
|
|
, eLeft = neighs ^. left
|
|
|
|
|
, eRight = neighs ^. right
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
neighborDirections :: Neighbors Direction
|
|
|
|
|
neighborDirections = Neighbors
|
|
|
|
|
{ _topLeft = UpLeft
|
|
|
|
|
, _top = Up
|
|
|
|
|
, _topRight = UpRight
|
|
|
|
|
, _left = Left
|
|
|
|
|
, _right = Right
|
|
|
|
|
, _bottomLeft = DownLeft
|
|
|
|
|
, _bottom = Down
|
|
|
|
|
, _bottomRight = DownRight
|
|
|
|
|
}
|
2019-09-02 19:56:25 +02:00
|
|
|
|
|
2019-09-10 02:54:33 +02:00
|
|
|
|
neighborPositions :: Position -> Neighbors Position
|
|
|
|
|
neighborPositions pos = (`move` pos) <$> neighborDirections
|
2019-09-29 16:54:52 +02:00
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|