module GameOfLife where

import Array2D

height = 20
width  = 80

newtype World = World (Array2D Bool)

instance Show World where
  show (World world)
    = unlines ((map.map) (\p -> if world?p then '*' else ' ')
                 [ [ (n,m) | m <- [1..width] ] | n <- [1..height] ])

newWorld :: [(Int,Int)] -> World
newWorld = 
  World . foldr (\p w -> w#p:=True) (emptyWithValue False) . filter inside
 where
  inside (n,m) = 1 <= n && n <= height && 1 <= m && m <= width

nextGeneration :: World -> World
nextGeneration (World world)
  = World $ foldr (\p w -> w#p:~alive p) world
              [ (n,m) | n <- [1..height], m <- [1..width] ]
 where
  alive (n,m) b
    = (length.filter id.map (world?))
        [ (x,y) | x <- [n-1..n+1], y <- [m-1..m+1], (x,y) /= (n,m) ]
      `elem` 3:if b then [2] else []

life :: World -> IO ()
life world = do
  putStr "\ESC[1;2J\ESC[1;1H"
  print world
  s <- getLine
  if s == "q" then return () else life (nextGeneration world)

test1 = life (newWorld [(3,3),(4,3),(5,3),(6,4),(7,4),(8,4)])
test2 n = life (newWorld [ p | x <- [1..height], y <- [x,x+n..n*x]
                             , p <- [(x,y),(x,y)] ])
test3 = life (newWorld [ (x,y+x`mod`2) | x <- [1..height]
                                       , y <- [1,3..width] ])
