Back in February Jon Harrop published an implementation of John Conway’s Game of Life in 32 lines of F# using WPF. I’ve managed to increase Jon’s example to a massive 50 lines but at the same time get it running in Silverlight. If you have Silverlight 4 installed you can click in the box below to kick start life.
Jon’s original code for calculating life:
module Game =
let count (a: _ [,]) x y =
let m, n = a.GetLength 0, a.GetLength 1
let mutable c = 0
for x in x-1..x+1 do
for y in y-1..y+1 do
if x>=0 && x<m && y>=0 && y<n && a.[x, y] then
c <- c + 1
if a.[x, y] then c-1 else c
let rule (a: _ [,]) x y =
match a.[x, y], count a x y with
| true, (2 | 3) | false, 3 -> true
| _ -> false
The Silverlight Control, containing a WriteableBitmap updated from an F# Async Workflow:
type GameControl(n) as control =
inherit System.Windows.Controls.UserControl()
let game =
let rand = System.Random()
Array2D.init n n (fun _ _ -> rand.Next 2 = 0) |> ref
let update _ = Game.rule !game |> Array2D.init n n
let bitmap = System.Windows.Media.Imaging.WriteableBitmap(n,n)
do control.Content <- System.Windows.Controls.Image(Source=bitmap)
let render () =
let pixels = bitmap.Pixels
let black, white = 0xff000000, 0xffffffff
for x in 0..n-1 do
for y in 0..n-1 do
pixels.[x+y*n] <-
if (!game).[x, y] then white else black
do for i = 1 to 3 do game:= update() done; render ()
do async {
use handle = new System.Threading.AutoResetEvent(false)
do! control.MouseLeftButtonUp |> Async.AwaitEvent |> Async.Ignore
do! Async.SwitchToThreadPool ()
while true do
game := update ()
bitmap.Dispatcher.BeginInvoke(fun _ ->
render()
bitmap.Invalidate()
handle.Set() |> ignore
) |> ignore
do! Async.AwaitWaitHandle handle |> Async.Ignore
handle.Reset() |> ignore
} |> Async.StartImmediate
Application startup:
type App() as app =
inherit System.Windows.Application()
do app.Startup.Add(fun _ -> app.RootVisual <- GameControl(256))
Resources:
Source code: GameOfLife.zip (2.38 kb)
Just for fun, a clone of the 1980s arcade game Missile Command written in F# and deployed in Silverlight.
A language feature I have repeatedly found useful for games is state machines as sequences using yield. The following is used to define the path of explosions:
static member Path radius = seq {
for i in [50..2..100] do
yield radius * ((float i / 100.0) ** 3.0)
for i in [100..-1..0] do
yield radius * ((float i / 100.0) ** 3.0)
}
References:
MissileCommand.zip (4.65 kb)
The Gunning Fog Index is an estimate of readability based on:
- the number words per sentences
- the number of complex words
The index estimates the years of formal education needed to understand the text on a first reading. Texts for a wide audience generally need a fog index less than 12.
If you have Silverlight 4 installed you, paste your text below to get a score:
The Gunning Fog Index formula along with some samples can be found on Wikipedia. The paste window gives results that are quite close to the values given in the samples, but this is an approximation.
The paste box was written in F# using the freely available Visual Studio 2010 Shell. If you are interested in the implementation some code snippets follow.
Compute approximate fog index:
let toFogIndex text =
let sentences = getSentences text
let words = sentences |> Array.collect getWords
let complexWords =
words
|> Array.filter (fun word -> word.Length>3)
|> Array.map removeSuffixes
|> Array.filter (fun word -> countSyllables word >= 3)
0.4 * ((float words.Length/float sentences.Length) +
(100.0 * float complexWords.Length/float words.Length))
React to text pasted into window; computing new Fog index in the background then updating the display on the UI thread:
do pasteText.TextChanged
|> Observable.map (fun _ -> pasteText.Text)
|> Observable.onThreadPool
|> Observable.map toFogIndex
|> Observable.onDispatcher
|> Observable.subscribe (fun index ->
label.Text <- sprintf "Fog Index %0.2f" index
)
|> remember
References:
FogIndexSource.zip (5.71 kb)