A simple opening/closing spiral going upwards

This commit is contained in:
Felix Van der Jeugt 2020-07-16 17:44:40 +02:00
parent b8fef3fd76
commit 9f0cbfcecc
No known key found for this signature in database
GPG Key ID: 58B209295023754D

78
Main.hs
View File

@ -12,7 +12,8 @@ type Length = Int -- ^ The length of an line segment
type X = Int type X = Int
type Y = Int type Y = Int
type Z = Int type Z = Int
type Point = (X, Y, Z) type Point2D = (X, Y)
type Point3D = (X, Y, Z)
area :: Int -> Int area :: Int -> Int
area a = a * a area a = a * a
@ -20,68 +21,53 @@ area a = a * a
cube :: Int -> Int cube :: Int -> Int
cube a = a * a * a cube a = a * a * a
layer :: Cell -> Layer
layer c = integerCubeRoot c `div` 2
ring :: Cell -> Ring ring :: Cell -> Ring
ring o = integerSquareRoot o `div` 2 ring o = integerSquareRoot o `div` 2
edge :: Layer -> Length edge :: Layer -> Length
edge l = 2 * l + 2 edge l = 2 * l + 2
-- | Offset of a cell within its layer atZ :: Z -> Point2D -> Point3D
lOffset :: Cell -> Cell atZ z (x, y) = (x, y, z)
lOffset c = c - cube (edge $ layer c - 1)
-- | Offset of a cell in a layer within its spiral ring reflectY :: Point2D -> Point2D
rOffset :: Cell -> Cell reflectY (x, y) = (x, -y - 1)
rOffset o = o - area (edge $ ring o - 1)
location :: Cell -> Point reflectX :: Point2D -> Point2D
location c | o < a = locationOnTop (e `div` 2 - 1) o reflectX (x, y) = (-x - 1, y)
| o < a + (e - 2) * (e - 1) * 4 = locationAround c
| otherwise = locationOnBottom ((-e) `div` 2) c (o - a - (e - 2) * (e - 1) * 4)
where o = lOffset c -- ^ offset within the current layer
l = layer c -- ^ the current layer
e = edge l -- ^ the length of the edge of the current layer
a = area e -- ^ the area of a side of the current layer
locationOnTop :: Z -> Cell -> Point rotate :: Length -> Point2D -> Point2D
locationOnTop z o | o == 0 = (0, 0, z) rotate l (x, y) = (-y - 1, -x - 1)
| ro < e - 1 = (r, ro - r, z) -- 64
| ro < 2 * e - 2 = (3 * r - ro, r, z) location :: Length -> Cell -> Point3D
| ro < 3 * e - 3 = (0 - r - 1, 5 * r - ro + 1, z) location l c = atZ h $ case h `mod` 4 of
| otherwise = (ro - 7 * r - 3, 0 - r - 1, z) 0 -> growingSpiral l o
1 -> rotate l $ shrinkingSpiral l o
2 -> reflectX . reflectY $ growingSpiral l o
3 -> reflectX . reflectY . rotate l $ shrinkingSpiral l o
where h = c `div` area l
o = c - h * area l
z = h - l `div` 2 - 1
growingSpiral :: Length -> Cell -> Point2D
growingSpiral l o | o == 0 = (0, 0)
| ro < e - 1 = (r, ro - r) -- 64
| ro < 2 * e - 2 = (3 * r - ro, r)
| ro < 3 * e - 3 = (0 - r - 1, 5 * r - ro + 1)
| otherwise = (ro - 7 * r - 3, 0 - r - 1)
where r = ring o -- ^ the current spiral ring where r = ring o -- ^ the current spiral ring
ro = rOffset o -- ^ offset within this ring ro = o - area (edge $ r - 1) -- ^ offset within this ring
e = edge r -- ^ edge of the this ring e = edge r -- ^ edge of the this ring
locationAround :: Cell -> Point shrinkingSpiral :: Length -> Cell -> Point2D
locationAround c | o <= r = (l - r + o, 0 - l - 1, l - r - 1) shrinkingSpiral l o = growingSpiral l (area l - o - 1)
| o <= r + e - 1 = (l, 0 - l - 1 + o - r, l - r - 1)
| o <= r + 2 * e - 2 = (l - o + r + e - 1, l, l - r - 1)
| o <= r + 3 * e - 3 = (0 - l - 1, l - o + r + 2 * e - 2, l - r - 1)
| otherwise = (0 - l - 1 + o - r - 3 * e + 3, 0 - l - 1, l - r - 1)
where l = layer c
e = edge l
s = lOffset c - area e -- ^ offset since starting the sides of the cude
r = s `div` (4 * e - 4) -- ^ revolutions since starting on the side
o = s - (4 * e - 4) * r -- ^ offset within this revolution
locationOnBottom :: Z -> Cell -> Cell -> Point
locationOnBottom z c b | False = (r, r, z)
| otherwise = (3, -3, z)
where l = layer c
r = integerSquareRoot (area (edge l) - b - 1) `div` 2 -- ^ the current spiral ring
asMatrix :: Length -> [[[Cell]]] asMatrix :: Length -> [[[Cell]]]
asMatrix e = foldl (\c (i, x, y, z) -> replace c z $ replace (c!!z) y $ replace (c!!z!!y) x i) asMatrix e = foldl (\c (i, x, y, z) -> replace c z $ replace (c!!z) y $ replace (c!!z!!y) x i)
(replicate e $ replicate e $ replicate e (-1)) (replicate e $ replicate e $ replicate e (-1))
[ (i, x + div e 2, y + div e 2, z + div e 2) [ (i, x + div e 2, y + div e 2, z)
| i <- [0..cube e - 1] | i <- [0..cube e - 1]
, let (x, y, z) = location i , let (x, y, z) = location e i
-- , x + div e 2 >= 0, y + div e 2 >= 0, z + div e 2 >= 0
-- , x < div e 2, y < div e 2, z < div e 2
] ]
where replace :: [a] -> Int -> a -> [a] where replace :: [a] -> Int -> a -> [a]
replace l i e = take i l ++ [e] ++ drop (i+1) l replace l i e = take i l ++ [e] ++ drop (i+1) l