HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

Game of Life in Haskell

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
lifegamehaskell

Problem

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 (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  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  -1) && (x  -1)

ppr_peice Dead = "O"
ppr_peice Alive = "X"
ppr_peice Cat = "C"

Solution

Refactor's answer is excellent and captures most points. One thing in your code which sticks out is the overuse of if. E.g. consider

get_bounds xs = if null xs
    then (0, 0)
    else (length xs, length $ head xs)


I think

getBounds [] = (0,0)
getBounds xs = (length xs, length $ head xs)


is much clearer. Or this, which looks really strange:

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


You should write

make_population_transition from to condition image 
     | image origin == from && 
       (condition . population_count) image = replace image origin to 
     | otherwise = image

Code Snippets

get_bounds xs = if null xs
    then (0, 0)
    else (length xs, length $ head xs)
getBounds [] = (0,0)
getBounds xs = (length xs, length $ head xs)
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
make_population_transition from to condition image 
     | image origin == from && 
       (condition . population_count) image = replace image origin to 
     | otherwise = image

Context

StackExchange Code Review Q#1204, answer score: 11

Revisions (0)

No revisions yet.