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

Conway's Game of Life in F#

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

Problem

Since I'm learning F# along with functional programming, I managed to implement the rules for Conway's Game of Life. I'm not sure if I can improve some of its parts, though. For example, the neighbours function does an ugly range testing, but I can't think of anything simpler.

module Game

open System

type Cell =
    | Alive
    | Dead

let amount_neighbours (board: Cell[,]) (pos: int * int) =
    let range (n: int) (limit: int) = 
        let min = if n  (limit - 2) then (limit - 1) else n + 1
        [min .. max]

    let x_range = range (fst pos) (Array2D.length1 board)
    let y_range = range (snd pos) (Array2D.length2 board)

    List.sum [for x in x_range ->
        List.sum [for y in y_range -> if board.[x, y] = Alive && (x, y) <> pos then 1 else 0]]

let lifecycle (board: Cell[,]) = 
    Array2D.init (Array2D.length1 board) (Array2D.length2 board) (fun i j ->
        let neighbours = amount_neighbours board (i, j)
        match neighbours with
            | 2 -> board.[i, j]
            | 3 -> Alive
            | _ -> Dead)

let rec process_game (board: Cell[,]) (n: int) =
    match n with
        | x when x > 0 -> 
            printfn "Iteration"
            printfn "%A" board
            process_game (lifecycle board) (n - 1)
        | _ -> 0

[]
let main args =
    let board = Array2D.init 5 5 (fun i j -> if i = 2 && j > 0 && j < 4 then Alive else Dead)
    ignore (process_game board 4)
    0

Solution

I thought it would make sense if you created a function alive, which would take care of bounds checking for you. And also simplify the the final expression by using a single sequence expression instead of two like you do.

But I'm not sure it's actually much better than your version:

let amount_neighbours (board: Cell[,]) (pos: int * int) =
    let alive board pos = 
        let (x, y) = pos
        if x = Array2D.length1 board ||
           y = Array2D.length2 board then
            false
        else
            board.[x, y] = Alive

    let vicinity x = seq { x - 1 .. x + 1 }

    seq {
        for x in vicinity (fst pos) do
        for y in vicinity (snd pos) do
        if (x, y) <> pos && alive board (x, y) then
            yield true
    } |> Seq.length

Code Snippets

let amount_neighbours (board: Cell[,]) (pos: int * int) =
    let alive board pos = 
        let (x, y) = pos
        if x < 0 || x >= Array2D.length1 board ||
           y < 0 || y >= Array2D.length2 board then
            false
        else
            board.[x, y] = Alive

    let vicinity x = seq { x - 1 .. x + 1 }

    seq {
        for x in vicinity (fst pos) do
        for y in vicinity (snd pos) do
        if (x, y) <> pos && alive board (x, y) then
            yield true
    } |> Seq.length

Context

StackExchange Code Review Q#17723, answer score: 3

Revisions (0)

No revisions yet.