I wondering what people think of this game of life. I don't think it is working properly, but I am interesting in what people think of the general design.
module GameOfLife where import Data.List --Our types type Coord = (Int, Int) origin = (0, 0) --Think of an image more like an infinite manifold type DiscreteImage a = (Coord -> a) --Cat is our "out of bounds" data GamePiece = Alive | Dead | Cat deriving(Show, Eq) type GameBoard = DiscreteImage GamePiece type TransitionRule = (GameBoard -> GamePiece) under_population = make_population_transition Alive Dead (<2) overcrowding = make_population_transition Alive Dead (>3) birth = make_population_transition Dead Alive (==3) --Order is not important. Only one transition applies per peice, --the others operate like id transition_rule :: TransitionRule transition_rule image = foldl (\image f -> f image) image [ under_population, overcrowding, birth ] origin --return a new gameboard that applies the transition rule to every --spot on the gameboard step :: TransitionRule -> GameBoard -> GameBoard step trans gb = trans . offset gb --apply the tranisition rule n number of times simulate :: Int -> TransitionRule -> GameBoard -> GameBoard simulate count trans gb = foldl apply_step gb steps where steps = replicate count (step trans) apply_step gb s = s gb --translate the image offset :: DiscreteImage a -> Coord -> Coord -> a offset image (offsetX, offsetY) (x, y) = image (offsetX + x, offsetY + y) --make a square of coords square_coords :: Int -> [Coord] square_coords radius = [(x, y) | x <- diameter_list, y <- diameter_list] where diameter_list = [(negate radius) .. radius] --return a neighborhood with the center missing punctured_neighborhood :: Int -> DiscreteImage a -> [a] punctured_neighborhood size image = map image $ filter (not . (==origin)) $ square_coords size --a little test main = do let (width, height) = get_bounds test_list let board1 = simulate 1 transition_rule test_board putStr $ unlines [ unwords [ ppr_peice $ board1 (x, y) | x <- [0..(width -1)]] | y <- [0..(height - 1)]] test_list = [ [Alive, Dead, Alive, Dead], [Alive, Dead, Dead, Alive], [Dead, Alive, Dead, Alive], [Dead, Alive, Alive, Alive] ] test_board = image_from_lists test_list Cat --helpers population_count = length . filter is_Alive . punctured_neighborhood 1 --does nothing if the origin peice /= from, otherwise test for replacement make_population_transition from to condition image | image origin == from = if (condition . population_count) image then replace image origin to else image make_population_transition from to test image | otherwise = image replace image coord_to_replace value coord = if coord_to_replace == coord then value else image coord bi f g h x = f x `h` g x is_Alive Alive = True is_Alive _ = False from_Bool True = Alive from_Bool False = Dead image_from_lists xs default_value coord@(x, y) = if is_in_bounds1 coord then (xs !! x) !! y else default_value where bounds = get_bounds xs is_in_bounds1 = is_in_bounds bounds get_bounds xs = if null xs then (0, 0) else (length xs, length $ head xs) is_in_bounds (xb, yb) (x, y) = (y < yb && y > -1) && (x < xb && x > -1) ppr_peice Dead = "O" ppr_peice Alive = "X" ppr_peice Cat = "C"