This week I had pleasure of meeting Vagif Abilov on Tomas Petricek and I’s Advanced F# course at Skills Matter. Vagif mentioned a Ruby implementation of Conway’s Game of Life being squeezed into 140 characters for tweeting and how that might look in F#.
Here’s the 140 characters of Ruby:
life=->g,s{(0..s*s-1).map{|i|->n{n==3||(g[i]&&n==2)||nil}
[[g[i-s-1],g[i-s],g[i-s+1],g[i-1],g[i+1],g[i+s-1],g[i+s],g[i+s+1]]
.compact.count]}}
And 127 characters of F#:
let f s g = g|>List.mapi(fun i x->match Seq.sumBy(fun o->
g.[abs((i+o)%(s*s))])[-1-s;-s;1-s;-1;1;-1+s;s;1+s]with 3->1|2->x|_->0)
Like the Ruby version, the F# implementation above takes a shortcut when computing points outside of the grid.
This is what the function looks like with added white space, variable names and comments:
let generate size grid =
grid |> List.mapi (fun i value->
/// Neighbours count
let count =
let s = size
[-1-s;-s;1-s;
-1; 1;
-1+s;s; 1+s]
|> Seq.sumBy (fun o ->
let offset = abs((i + o) % grid.Length)
grid.[offset]
)
// Evaluate life
match value, count with
| _, 3 -> 1
| n, 2 -> n
| _, _ -> 0
)
The game grid can is expressed as a list:
let grid = [
0;0;0;0;0
0;0;1;0;0
0;0;1;1;0
0;0;1;0;0
0;0;0;0;0
]
Visualizing the grid on the console:
let show (size:int) (grid:int list) =
for y=0 to (grid.Length/size)-1 do
[0..size-1]
|> List.map (fun x -> grid.[y * size + x].ToString())
|> String.concat ""
|> printfn "%s"
Or watch it running in your browser: http://trelford.com/Life/Life.htm
(I used Pit to compile the F# code to JavaScript)
Life.fs (1.77 kb)