diff --git a/donut-hs.cabal b/donut-hs.cabal index 9a86d0e..f8967f5 100644 --- a/donut-hs.cabal +++ b/donut-hs.cabal @@ -10,6 +10,7 @@ build-type: Simple executable donut-hs main-is: Main.hs other-modules: Data.Vector - build-depends: base >=4.14 && <4.15 + build-depends: base >=4.14 && <4.15, + terminal-size hs-source-dirs: src default-language: Haskell2010 diff --git a/src/Data/Vector.hs b/src/Data/Vector.hs index 437b215..4b755d1 100644 --- a/src/Data/Vector.hs +++ b/src/Data/Vector.hs @@ -1,13 +1,16 @@ module Data.Vector -( Vector(Vector) ) where +( Vector(..) ) where data Vector a = Vector a a a deriving (Show, Eq) instance (Num a) => Num (Vector a) where (Vector x1 y1 z1) + (Vector x2 y2 z2) = Vector (x1+x2) (y1+y2) (z1+z2) - (*) = undefined + (Vector x1 y1 z1) * (Vector x2 y2 z2) = Vector (x1*x2) (y1*y2) (z1*z2) abs = undefined signum = undefined fromInteger = undefined negate = undefined + +instance Functor Vector where + fmap f (Vector x y z) = Vector (f x) (f y) (f z) diff --git a/src/Main.hs b/src/Main.hs index b4c3ff3..096b673 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -1,22 +1,67 @@ module Main where import Data.Vector +import System.Console.Terminal.Size -_r :: Float -_r = 1.0 -_R :: Float -_R = 2.0 +type ScreenPos = (Int, Int) -drawCircle :: Vector Float -> [Vector Float] -drawCircle center = map ((+) center . vradius) [0,0.1..2*pi] - where +type Grid = [[Char]] + +k :: Float +k = 1 + +-- | A torus is essentially a circle cloned around a central point; +-- we thus define r as being the radius of the center, +r :: Float +r = 5 +-- and r' a being the distance between the center of the +-- circle and the central point of the torus. +r' :: Float +r' = 25 + +-- | Generates every point of a circle of radius r and +-- center c. +generateCircle :: Vector Float -> [Vector Float] +generateCircle c = map ((+) c . vradius) [0.0,0.05..2*pi] + where + -- | Generates a vector corresponding to the + -- radius, rotated by the given angle theta. + -- It is centered at point (0,0,0); we need to add that + -- vector the vector c. vradius :: Float -> Vector Float - vradius theta = Vector (_r * cos theta) (_r * sin theta) 0 + vradius theta = Vector (r * cos theta) (r * sin theta) 0 + +-- | Projects a vector to a point on the screen +project :: Vector Float -> ScreenPos +project v@(Vector _ _ z) = pair . fmap (round . (* (k/z))) $ v + where pair (Vector x y _) = (x, y) -render :: [[Char]] -render = ["hello", "world"] +-- | Creates our final render made out of char, +-- based on screen coordinates that must get rendered. +renderScreenCoordinates :: [ScreenPos] -> Grid +renderScreenCoordinates coordinates = + map (concatMap (\cell -> if mustRender cell then ".." else " ")) gridCoordinates + where + gridCoordinates :: [[ScreenPos]] + gridCoordinates = [ + [ (x, y) | x <- take 40 [0..] ] + | y <- take 24 [0..] ] + + mustRender :: ScreenPos -> Bool + mustRender pos = pos `elem` coordinates + +-- | Starts the rendering process. +render :: Window Int -> [[Char]] +render win@(Window w h) = coordinates + where + coordinates = renderScreenCoordinates $ map project $ generateCircle (Vector r' 5 1) main :: IO () main = do - let screen = unlines render + window <- size + window <- case window of + Just a -> return a + Nothing -> return $ Window 80 24 + + let screen = unlines $ render window putStr screen