Outputting Pascal's triangle

173 views Asked by At
import Data.List (intercalate)
import Control.Concurrent (threadDelay)
import System.IO

-- I love how amazingly concise Haskell code can be.  This same program in C, C++ or Java
-- would be at least twice as long.


pascal :: Int -> Int -> Int
pascal row col | col >= 0 && col <= row =
                 if row == 0 || col == 0 || row == col
                 then 1
                 else pascal (row - 1) (col - 1) + pascal (row - 1) col
pascal _ _ = 0


pascalsTriangle :: Int -> [[Int]]
pascalsTriangle rows =
  [[pascal row col | col <- [0..row]] | row <- [0..rows]]


main :: IO ()
main = do
  putStrLn "" 
  putStr "Starting at row #0, how many rows of Pascal's Triangle do you want to print out? "
  hFlush stdout
  numRows <- (\s -> read s :: Int) <$> getLine
  let triangle = pascalsTriangle numRows
      triangleOfStrings = map (intercalate ", ") $ map (map show) triangle
      lengthOfLastDiv2 = div ((length . last) triangleOfStrings) 2 
  putStrLn ""
  mapM_ (\s -> let spaces = [' ' | x <- [1 .. lengthOfLastDiv2 - div (length s) 2]]
                   in (putStrLn $ spaces ++ s) >> threadDelay 200000) triangleOfStrings
  putStrLn ""

My little program above finds the values of Pascal's Triangle. But if you compile it and use it you'll see that the "triangle" looks more like a Christmas tree than a triangle! Ouch!

I'm just taking half the length of the last line and subtracting from that half the length of each preceding line, and creating that many blank spaces to add to the beginning of each string. It ALMOST works, but I'm looking for an equilateral triangle type of effect, but to me it resembles a sloping Christmas tree! Is there a better way to do this. What am I missing besides some programming talent?! Thanks for the help. THIS IS NOT A HOMEWORK ASSIGNMENT. I'm just doing this for fun and recreation. I appreciate the help.

Best. Douglas Lewit.

1

There are 1 answers

0
comingstorm On

Here's a straightforward implementation:

space n = replicate n ' '

pad n s | n < length s = take n s
pad n s = space (n - length s) ++ s

triangle = iterate (\ xs -> zipWith (+) (xs ++ [0]) (0:xs)) [1]

rowPrint n hw xs  = space (n * hw) ++ concatMap (pad (2*hw) . show) xs

triRows n hw = [rowPrint (n-i) hw row | (i,row) <- zip [1..n] triangle]

main = do
  s <- getLine
  mapM_ putStrLn (triRows (read s) 2)

Note that triangle is an infinite Pascal's triangle, generated by the recurrence relation. Also, hw stands for "half-width": half the width allocated for printing a number, and pad is a strict left-pad that truncates the output rather than disrupt the formatting.