Phillip Trelford's Array

POKE 36879,255

Fractal Zoom

A quick search for “F# Mandelbrot” gave an article written by Luke Hoban back in 2007, that draws a Fractal to the console.

Time for a makeover with a sprinkling of Active patterns, Reactive programming, Parallel execution and Silverlight.

Simply draw a rectangle onto the Fractal to zoom in:


“Complex” maths using F# PowerPack library and an Active Pattern:

open Microsoft.FSharp.Math

let maxIteration = 255
let modSquared (c : Complex) = 
    c.RealPart * c.RealPart + c.ImaginaryPart * c.ImaginaryPart
    
let (|Escaped|DidNotEscape|) c =
    let rec compute z iterations =
        if(modSquared z >= 4.0) 
            then Escaped iterations
        elif iterations = maxIteration
            then DidNotEscape
        else compute ((z * z) + c) (iterations + 1)
    compute c 0

Tomas Petricek’s original Reactive Rectangles sample to select the zoom area:

let rec waiting() = async {
  let! md = Async.AwaitObservable(main.MouseLeftButtonDown)
  let rc = new Canvas(Background = transparentGray)
  main.Children.Add(rc) 
  do! drawing(rc, md.GetPosition(main)) }

and drawing(rc:Canvas, pos) = async {
  let! evt = Async.AwaitObservable(main.MouseLeftButtonUp, main.MouseMove)
  match evt with
  | Choice1Of2(up) -> 
      rc.Background <- SolidColorBrush(colorSelect.CurrentColor)
      do! waiting() 
  | Choice2Of2(move) ->
      moveControl rc pos (move.GetPosition(main))
      do! drawing(rc, pos) }

do waiting() |> Async.StartImmediate

Parallel rendering over up to 4 cores using Async workflows:

do! [0..3] 
    |> List.map (fun y -> async {
        render points (y,(height/4),4) buffer
    })
    |> Async.Parallel

Resources:

Source: FractalZoom.zip (3.89 kb)

Silverlife

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)

Missile Command

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)