module Game.LambdaHack.PointXY
( X, Y, PointXY(..), fromTo, sortPointXY, blaXY
) where
import qualified Data.List as L
import Game.LambdaHack.Utils.Assert
type X = Int
type Y = Int
newtype PointXY = PointXY (X, Y)
deriving (Eq, Ord)
instance Show PointXY where
show (PointXY (x, y)) = show (x, y)
fromTo :: PointXY -> PointXY -> [PointXY]
fromTo (PointXY (x0, y0)) (PointXY (x1, y1)) =
let result
| x0 == x1 = L.map (\ y -> PointXY (x0, y)) (fromTo1 y0 y1)
| y0 == y1 = L.map (\ x -> PointXY (x, y0)) (fromTo1 x0 x1)
| otherwise = assert `failure` ((x0, y0), (x1, y1))
in result
fromTo1 :: Int -> Int -> [Int]
fromTo1 x0 x1
| x0 <= x1 = [x0..x1]
| otherwise = [x0,x01..x1]
sortPointXY :: (PointXY, PointXY) -> (PointXY, PointXY)
sortPointXY (a, b) | a <= b = (a, b)
| otherwise = (b, a)
balancedWord :: Int -> Int -> Int -> [Int]
balancedWord p q eps | eps + p < q = 0 : balancedWord p q (eps + p)
balancedWord p q eps = 1 : balancedWord p q (eps + p q)
blaXY :: Int -> PointXY -> PointXY -> [PointXY]
blaXY eps (PointXY (x0, y0)) (PointXY (x1, y1)) =
let (dx, dy) = (x1 x0, y1 y0)
xyStep b (x, y) = (x + signum dx, y + signum dy * b)
yxStep b (x, y) = (x + signum dx * b, y + signum dy)
(p, q, step) | abs dx > abs dy = (abs dy, abs dx, xyStep)
| otherwise = (abs dx, abs dy, yxStep)
bw = balancedWord p q (eps `mod` (max 1 q))
walk w xy = xy : walk (tail w) (step (head w) xy)
in L.map PointXY $ walk bw (x0, y0)