-- The Game of Life
-- (from John Launchbury)
start :: [[Int]]
start = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],
[0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0]]
-- Calculating the next generation
gen n board = map row (shift (copy n 0) board)
row (last,this,next)
= zipWith3 elt (shift 0 last) (shift 0 this) (shift 0 next)
elt (a,b,c) (d,e,f) (g,h,i)
| tot < 2 || tot > 3 = 0
| tot == 3 = 1
| otherwise = e
where
tot = a+b+c+d+f+g+h+i
shiftr x xs = [x] ++ init xs
shiftl x xs = tail xs ++ [x]
shift x xs = zip3 (shiftr x xs) xs (shiftl x xs)
copy 0 x = []
copy n x = x : copy (n-1) x
-- Displaying one generation
disp (gen,xss) =
gen ++ "\n\n" ++ (foldr (glue "\n") "" . map (concat . map star)) xss
star 0 = " "
star 1 = " o"
glue s xs ys = xs ++ s ++ ys
-- Test to see if we have reached a fixpoint
limit (x:y:xs) | x==y = [x]
| otherwise = x : limit (y:xs)
-- Generating and displaying a sequence of generations. Rather than
-- display all the generations, we just display the number of generations
-- it takes to reach a fixpoint, plus the last generations.
main =
putStr (last generations)
where
sz = 30
generations =
(map disp . zip (map show [0..]) . limit . iterate (gen sz))
(take sz (map (take sz . (++ (copy sz 0))) start ++ copy sz (copy sz 0)))
|