import Control.Arrow import Data.Foldable import Data.List import Data.Tree import System.Environment type Point = (Int,Int) type Angle = Double data Hilbert = A | B | M | P | F deriving (Show, Eq) step = 10 rule :: Hilbert -> [Hilbert] rule A = [P, B, F, M, A, F, A, M, F, B, P] rule B = [M, A, F, P, B, F, B, P, F, A, M] rule x = [x] axiom = Node A [] hilbert :: [Tree Hilbert] hilbert = iterate go axiom where go (Node c []) = Node c ((`Node` []) <$> rule c) go (Node c xs) = Node c (go <$> xs) move :: Hilbert -> Point -> Angle -> (Point, Angle) move P p theta = (p, theta + (pi / 2)) move M p theta = (p, theta - (pi / 2)) move F (x,y) theta = ((round $ fromIntegral x + step * cos theta, round $ fromIntegral y + step * sin theta), theta) move _ p theta = (p, theta) curve n = map fst $ scanr (uncurry . move) ((100, 100), 0) $ leaves $ hilbert !! n svg :: [Point] -> String svg ps = " " width=" <> quote width <> " height=" <> quote height <> " viewBox=" <> quote (unwords ["0", "0", width, height]) <> ">" <> " " stroke-width=\"2\" stroke=\"#79a8ff\" fill=\"transparent\" style=\"fill:none;stroke-linejoin:round\"/>" <> "" where width = show $ succ $ maximum $ fst <$> ps height = show $ succ $ maximum $ snd <$> ps quote s = "\"" <> s <> "\"" path = ps >>= (uncurry (:) . second singleton) main = do (n:_) <- getArgs putStrLn $ svg $ curve (read n) leaves :: Tree a -> [a] leaves (Node a []) = [a] leaves (Node a xs) = xs >>= leaves