{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedLists #-}
module Data.Grid.Examples.Conway where

import Data.Grid
import Data.Foldable
import Data.List

rule :: Grid '[3, 3] Bool -> Bool
rule g = (currentCellAlive && livingNeighbours == 2) || livingNeighbours == 3
 where
  currentCellAlive = g `index` Coord [1, 1] -- Get the center cell
  livingNeighbours =
    (if currentCellAlive then subtract 1 else id) . length . filter id $ toList
      g

step :: (Dimensions dims) => Grid dims Bool -> Grid dims Bool
step = autoConvolute wrapWindow rule

glider :: [Coord '[10, 10]]
glider = Coord <$> [[0, 1], [1, 2], [2, 0], [2, 1], [2, 2]]

start :: Grid '[10, 10] Bool
start = tabulate (`elem` glider)

simulate :: Int -> Grid '[10, 10] Bool
simulate = (iterate step start !!)

showBool :: Bool -> Char
showBool True  = '#'
showBool False = '.'

showGrid :: (Dimensions '[x, y]) => Grid '[x, y] Bool -> String
showGrid = intercalate "\n" . toNestedLists . fmap showBool