Inspired by a few inverse tree ascii art F# questions, I wanted to give it a shot in Haskell.
As seen in the linked questions, the resulting program reads an Int
from stdin (\$0 \leq n \leq 5\$), and displays a tree of dimensions 100 * 63, consisting of \$n\$ Y
-formed "trunks-and-branches" of which the three arms each have a height of \$16/2^{i-1}\$ (that is, the branch is \$16/2^{i-1}\$ high, and the branches are \$16/2^{i-1}\$ high). After each branch, the next Y
-formed iterations start at the tops of the last Y
s, until \$i\$ reaches \$n\$.
The Y
s are drawn in a 100 * 63 field of _
characters, and drawn with 1
characters. An example for \$n = 0\$ would be (halving all given dimensions to save space):
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
\$n = 1\$ would give:
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
__________________________________________________
________________1_______________1_________________
_________________1_____________1__________________
__________________1___________1___________________
___________________1_________1____________________
____________________1_______1_____________________
_____________________1_____1______________________
______________________1___1_______________________
_______________________1_1________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
And \$n = 4\$ would show:
__________________________________________________
_________1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1__________
__________1___1___1___1___1___1___1___1___________
__________1___1___1___1___1___1___1___1___________
___________1_1_____1_1_____1_1_____1_1____________
____________1_______1_______1_______1_____________
____________1_______1_______1_______1_____________
____________1_______1_______1_______1_____________
_____________1_____1_________1_____1______________
______________1___1___________1___1_______________
_______________1_1_____________1_1________________
________________1_______________1_________________
________________1_______________1_________________
________________1_______________1_________________
________________1_______________1_________________
________________1_______________1_________________
_________________1_____________1__________________
__________________1___________1___________________
___________________1_________1____________________
____________________1_______1_____________________
_____________________1_____1______________________
______________________1___1_______________________
_______________________1_1________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
________________________1_________________________
The code is not as clean as I'd like it to be, and I'm sure it's not idiomatic Haskell (I don't see any Arrow
s, Functor
s or more than two types), but I'd like to learn and improve my skills. Please have at it :)
module Main where
import Data.List (groupBy, sortOn)
data Point = Point Int Int
deriving Show
type Tree = [Point]
trunk :: Point -> Int -> Tree
trunk (Point x y) size = [Point x (y + d) | d <- [1..size]]
split :: Point -> [Point]
split (Point x y) = [Point (x + 1) (y + 1), Point (x - 1) (y + 1)]
branch :: Point -> Int -> Tree
branch start = branch' [start]
where branch' _ 0 = []
branch' [single] size = split single ++ branch' (split single) (size - 1)
branch' points size = widen points ++ branch' (widen points) (size - 1)
where widen [Point leftx lefty, Point rightx righty] = [Point (leftx + 1) (lefty + 1), Point (rightx - 1) (righty + 1)]
tree :: Point -> Int -> Int -> Tree
tree _ _ 0 = []
tree start size splits =
let trunks = trunk start size
branches = branch (last trunks) size
in
trunks ++ branches ++ concat [tree st (size `div` 2) (splits - 1) | st <- take 2 $ reverse branches]
formatTree :: Int -> Int -> Tree -> [String]
formatTree width height =
take height
. flip (++) (repeat (replicate width '_'))
. map (\points -> map (\x -> if x `elem` map (\(Point x _) -> x) points then '1' else '_') [1..width])
. groupBy (\(Point _ y1) (Point _ y2) -> y1 == y2)
. sortOn (\(Point _ y) -> y)
main :: IO ()
main = do
sizeStr <- getLine
let splits = read sizeStr
mapM_ putStrLn $ reverse $ formatTree 100 63 $ tree (Point 50 0) 16 splits
sortOn
? \$\endgroup\$Ord
, instead of anOrdering
. \$\endgroup\$