module Conway
    ( Index(..)
    , update
    )
where

import Data.List
import qualified Data.Vector.Sized as V
import Data.Map (Map)
import qualified Data.Map as M
import Data.Set (Set)
import qualified Data.Set as S

class Index i where
    neighbours :: i -> [i]
    addIndex :: i -> i -> i

counts :: Ord a => [a] -> Map a Int
counts = M.fromList . map (\xs -> (head xs, length xs)) . group . sort

neighbourCounts :: (Index i, Ord i) => Set i -> Map i Int
neighbourCounts = counts . concatMap neighbours . S.elems

update :: (Index i, Ord i) => (Int -> Bool) -> (Int -> Bool) -> Set i -> Set i
update create destroy old = M.keysSet $ M.filterWithKey shouldLive $ M.fromSet (flip (M.findWithDefault 0) nCounts) indices
    where nCounts = neighbourCounts old
          indices = S.union old $ M.keysSet nCounts
          shouldLive ix n = if S.notMember ix old then create n else not $ destroy n