Skip to content

Instantly share code, notes, and snippets.

@sordina
Created July 1, 2011 11:57
Show Gist options
  • Save sordina/1058392 to your computer and use it in GitHub Desktop.
Save sordina/1058392 to your computer and use it in GitHub Desktop.
Dragon Curve ASCII Game
{-
Plotting the dragon curve
=========================
Console Version
http://en.wikipedia.org/wiki/Lindenmayer_system
-}
import System
import System.Random
import Control.Monad
import Control.Arrow
import Data.List
import Data.Maybe
import Data.Char
import qualified Data.Map as M
-- Should be 90 degrees, but just playing with it to see what happenes
angle = pi/2.2
data Direction = X | Y | F | P | N deriving (Show, Eq)
dims = (80,25)
-- Magic number: Itteration of the Lindenmayer transform
main = do
st_george <- readFile "/Users/lyndon/Documents/Reading/st_george.txt"
let
text = cycle $ stripper st_george
curve_length = length dragon_points
matcher = take curve_length text
dragon_points = normalise ((fromIntegral *** fromIntegral) dims) $ points $ dragon 12
putStrLn $ two_strippers matcher (cycle st_george)
render dims $ flip zip (map toLower text) $ dragon_points
render :: (Int, Int) -> [((Int,Int),Char)] -> IO ()
render (w,h) l =
forM_ [0..h] $ \y -> do
forM_ [0..w] $ \x -> putStr (fromMaybe ' ' (M.lookup (x,y) m) : [])
putStrLn ""
where m = M.fromList l
stripper = filter (not . flip elem ".\n\t ")
two_strippers [] _ = []
two_strippers w@(c:cs) (e:es)
| c == e = e : two_strippers cs es
| otherwise = e : two_strippers w es
normalise :: (Float,Float) -> [(Float,Float)] -> [(Int,Int)]
normalise (w,h) l = nub $ map ((\x -> round (x * w / maxx)) *** (\y -> round (y * h / maxy))) l'
where
minx = minimum $ map fst l
miny = minimum $ map snd l
l' = map (subtract minx *** subtract miny) l
maxx = maximum $ map fst l'
maxy = maximum $ map snd l'
points :: [Direction] -> [(Float,Float)]
points l = snd $ foldl' foo (0,[(0,0)]) l
where
foo :: (Float,[(Float,Float)]) -> Direction -> (Float,[(Float,Float)])
foo (a, xs) P = (a + angle, xs)
foo (a, xs) N = (a - angle, xs)
foo (a, xs@((x,y):_)) F = (a, (x + cos a, y + sin a):xs)
foo i _ = i
dragon :: Int -> [Direction]
dragon n = filter (`elem` [F,P,N]) (dragons !! n)
dragons = iterate (concatMap substitute) [F,X]
substitute X = [X,P,Y,F,P]
substitute Y = [N,F,X,N,Y]
substitute x = [x]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment