6 people like it.
    Like the snippet!
  
  Berzerk
  Zombie state machine code sample. 
Use arrow keys to move humanoid.
Robots activate when in range of humanoids. 
Try it out in the browser with TryFSharp.org.
  |   1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
 | #if INTERACTIVE
#else
namespace Berzerk
#endif
open System
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Media
open System.Windows.Media.Imaging
type Keys (control:Control) =
    let mutable keysDown = Set.empty
    do  control.KeyDown.Add (fun e -> keysDown <- keysDown.Add e.Key)
    do  control.KeyUp.Add (fun e -> keysDown <- keysDown.Remove e.Key)
    member keys.IsKeyDown key = keysDown.Contains key
[<AutoOpen>] 
module Imaging =
    let toInt (color:Color) = 
        (int color.A <<< 24) ||| 
        (int color.R <<< 16) ||| 
        (int color.G <<< 8)  ||| 
        (int color.B)
    let toBitmap color width (xs:int list) =
        let on = color |> toInt
        let off = Colors.Black |> toInt
        let toColor = function true -> on | false -> off
        let bitmap = WriteableBitmap(width, xs.Length)
        let pixels = bitmap.Pixels
        xs |> List.iteri (fun y xs ->
            for x = 0 to width-1 do
                let bit = 1 <<< (width - 1 - x) 
                pixels.[x+y*width] <- xs &&& bit = bit |> toColor
        )
        bitmap
    let toImage (bitmap:#BitmapSource) =
        let w = bitmap.GetValue(BitmapSource.PixelWidthProperty) :?> int
        let h = bitmap.GetValue(BitmapSource.PixelHeightProperty) :?> int
        Image(Source=bitmap,Stretch=Stretch.Fill,Width=float w,Height=float h) 
    let rotate xs =
        List.tail xs |> List.fold (fun ys xs ->
            List.zip xs ys
            |> List.map (fun (x,y) -> x::y)
        ) (List.head xs |> List.map (fun x -> [x]))
        |> List.map List.rev    
[<AutoOpen>]
module Game = 
    let rand = Random()
    let run rate update =
        let rate = TimeSpan.FromSeconds(rate)
        let lastUpdate = ref DateTime.Now
        let residual = ref (TimeSpan())
        CompositionTarget.Rendering.Subscribe (fun _ -> 
            let now = DateTime.Now
            residual := !residual + (now - !lastUpdate)
            while !residual > rate do
                update(); residual := !residual - rate
            lastUpdate := now
        )
    let move element (x,y) =
        Canvas.SetLeft(element, x)
        Canvas.SetTop(element, y)
[<AutoOpen>]
module Bits =
    let robot_bits = [ 
        0b00111100
        0b01100110
        0b11111111
        0b10111101
        0b10111101
        0b00111100
        0b00100100
        0b01100110
        ]
    let humanoid_bits = [
        [0b001100; 0b001100]
        [0b001100; 0b001100]
        [0b000000; 0b000000]
        [0b011111; 0b011111]
        [0b101100; 0b101100]
        [0b001100; 0b001100]
        [0b010010; 0b110100]
        [0b100010; 0b000100]
        ] 
type State = { mutable Image:Image; mutable X:float; mutable Y:float }
[<AutoOpen>]
module Robot =
    let random_pause state n = seq {
        let count = (rand.Next(10))
        for i = 1 to count do yield ()
    }
    let wait target state range = seq {
        let distance () = 
            let dx = (target.X - state.X)
            let dy = (target.Y - state.Y)
            sqrt(dx * dx + dy * dy) 
        while distance() > 50.0 do yield ()
    }
    let home target state n = seq {
        let dx = if target.X < state.X then -0.5 else 0.5
        let dy = if target.Y < state.Y then -0.5 else 0.5
        for i = 1 to n do          
            state.X <- state.X + dx
            state.Y <- state.Y + dy
            yield ()
        }
    let zombie target state = seq {
        yield! random_pause state 10
        while true do
            yield! wait target state 50.0
            yield! home target state 10
        }
type GameControl() as control =
    inherit UserControl(Width=200.0, Height=150.0,IsTabStop=true)
    let keys = Keys control
    let grid = Grid()
    let canvas = Canvas(Background = SolidColorBrush Colors.Black)
    do  grid.RenderTransform <- ScaleTransform(ScaleX=4.0,ScaleY=4.0)
    do  grid.Children.Add canvas
    do  control.Content <- grid
   
    let humanoids = 
        humanoid_bits |> rotate
        |> List.map (toBitmap Colors.Yellow 6 >> toImage)
    
    let humanoid = {Image=humanoids.[0]; X=control.Width/2.0; Y=control.Height/2.0}
    do  move humanoid.Image (humanoid.X,humanoid.Y)
    do  canvas.Children.Add humanoid.Image
    let robot = toBitmap Colors.Red 8 robot_bits
    let mutable robots = [
        for i = 1 to 5 do 
            let image = robot |> toImage
            let x = rand.Next(int control.Width - 8) |> float
            let y = rand.Next(int control.Height - 8) |> float
            move image (x,y)
            canvas.Children.Add(image)
            let state = { Image=image; X=x; Y=y }
            let machine = (zombie humanoid state)
            yield state, machine.GetEnumerator()
        ]
    let moveRobots () =
        robots <- robots |> List.filter (fun (state,machine) -> 
            let alive = machine.MoveNext()
            if alive then
                move state.Image (state.X, state.Y)
            alive
        )
    let update () =
        if keys.IsKeyDown Key.Up    then humanoid.Y <- humanoid.Y - 1.0
        if keys.IsKeyDown Key.Down  then humanoid.Y <- humanoid.Y + 1.0
        if keys.IsKeyDown Key.Left  then humanoid.X <- humanoid.X - 1.0
        if keys.IsKeyDown Key.Right then humanoid.X <- humanoid.X + 1.0
        move humanoid.Image (humanoid.X,humanoid.Y)       
        moveRobots ()
    let createMessage text =
        let t = TextBlock(Text=text, Foreground=SolidColorBrush Colors.White)
        t.HorizontalAlignment <- HorizontalAlignment.Center
        t.VerticalAlignment <- VerticalAlignment.Center
        t        
    let rec loop () = async {
        let t = createMessage "Click to Start"
        grid.Children.Add t
        do! control.MouseLeftButtonDown |> Async.AwaitEvent |> Async.Ignore
        grid.Children.Remove t |> ignore
        let _ = run (1.0/50.0) update
        do! Async.Sleep(-1)
        return! loop ()
        }
    do  loop () |> Async.StartImmediate
    let canvas = Canvas(Background = SolidColorBrush Colors.Black)
    do  canvas.RenderTransform <- ScaleTransform(ScaleX=4.0,ScaleY=4.0)
#if INTERACTIVE
open Microsoft.TryFSharp
App.Dispatch (fun() -> 
    App.Console.ClearCanvas()
    let canvas = App.Console.Canvas
    canvas.Background <- SolidColorBrush Colors.Black
    let control = GameControl()    
    control |> canvas.Children.Add
    App.Console.CanvasPosition <- CanvasPosition.Right
    control.Focus() |> ignore
)
#else
type App() as app = 
    inherit Application()
    let main = new GameControl()
    do app.Startup.Add(fun _ -> app.RootVisual <- GameControl())
#endif
 | 
namespace System
namespace System.Windows
namespace System.Media
Multiple items
type Keys =
  new : control:obj -> Keys
  member IsKeyDown : key:IComparable -> bool
Full name: Script.Keys
--------------------
new : control:obj -> Keys
val control : obj
namespace Microsoft.FSharp.Control
val mutable keysDown : Set<IComparable>
Multiple items
module Set
from Microsoft.FSharp.Collections
--------------------
type Set<'T (requires comparison)> =
  interface IComparable
  interface IEnumerable
  interface IEnumerable<'T>
  interface ICollection<'T>
  new : elements:seq<'T> -> Set<'T>
  member Add : value:'T -> Set<'T>
  member Contains : value:'T -> bool
  override Equals : obj -> bool
  member IsProperSubsetOf : otherSet:Set<'T> -> bool
  member IsProperSupersetOf : otherSet:Set<'T> -> bool
  ...
Full name: Microsoft.FSharp.Collections.Set<_>
--------------------
new : elements:seq<'T> -> Set<'T>
val empty<'T (requires comparison)> : Set<'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Set.empty
member Set.Add : value:'T -> Set<'T>
member Set.Remove : value:'T -> Set<'T>
val keys : Keys
member Keys.IsKeyDown : key:IComparable -> bool
Full name: Script.Keys.IsKeyDown
val key : IComparable
member Set.Contains : value:'T -> bool
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute
  new : path:string -> AutoOpenAttribute
  member Path : string
Full name: Microsoft.FSharp.Core.AutoOpenAttribute
--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
val toInt : color:'a -> int
Full name: Script.Imaging.toInt
val color : 'a
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val toBitmap : color:'a -> width:int -> xs:int list -> 'b
Full name: Script.Imaging.toBitmap
val width : int
val xs : int list
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val on : int
val off : int
val toColor : (bool -> int)
val bitmap : 'b
property List.Length: int
val pixels : obj
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val iteri : action:(int -> 'T -> unit) -> list:'T list -> unit
Full name: Microsoft.FSharp.Collections.List.iteri
val y : int
val xs : int
val x : int
val bit : int
val toImage : bitmap:'a -> 'b
Full name: Script.Imaging.toImage
val bitmap : 'a
val w : int
val h : int
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
val rotate : xs:'a list list -> 'a list list
Full name: Script.Imaging.rotate
val xs : 'a list list
val tail : list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.tail
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
Full name: Microsoft.FSharp.Collections.List.fold
val ys : 'a list list
val xs : 'a list
val zip : list1:'T1 list -> list2:'T2 list -> ('T1 * 'T2) list
Full name: Microsoft.FSharp.Collections.List.zip
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
val x : 'a
val y : 'a list
val head : list:'T list -> 'T
Full name: Microsoft.FSharp.Collections.List.head
val rev : list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.rev
val rand : Random
Full name: Script.Game.rand
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float
Full name: System.Random
--------------------
Random() : unit
Random(Seed: int) : unit
val run : rate:float -> update:'a -> 'b
Full name: Script.Game.run
val rate : float
val update : 'a
val rate : TimeSpan
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    member Minutes : int
    ...
  end
Full name: System.TimeSpan
--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
TimeSpan.FromSeconds(value: float) : TimeSpan
val lastUpdate : DateTime ref
Multiple items
val ref : value:'T -> 'T ref
Full name: Microsoft.FSharp.Core.Operators.ref
--------------------
type 'T ref = Ref<'T>
Full name: Microsoft.FSharp.Core.ref<_>
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end
Full name: System.DateTime
--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
property DateTime.Now: DateTime
val residual : TimeSpan ref
val move : element:'a -> x:'b * y:'c -> 'd
Full name: Script.Game.move
val element : 'a
val x : 'b
val y : 'c
val robot_bits : int list
Full name: Script.Bits.robot_bits
val humanoid_bits : int list list
Full name: Script.Bits.humanoid_bits
type State =
  {mutable Image: obj;
   mutable X: float;
   mutable Y: float;}
Full name: Script.State
State.Image: obj
State.X: float
State.Y: float
val random_pause : state:'a -> n:'b -> seq<unit>
Full name: Script.Robot.random_pause
val state : 'a
val n : 'b
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val count : int
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val i : int
val wait : target:State -> state:State -> range:'a -> seq<unit>
Full name: Script.Robot.wait
val target : State
val state : State
val range : 'a
val distance : (unit -> float)
val dx : float
val dy : float
val sqrt : value:'T -> 'U (requires member Sqrt)
Full name: Microsoft.FSharp.Core.Operators.sqrt
val home : target:State -> state:State -> n:int -> seq<unit>
Full name: Script.Robot.home
val n : int
val zombie : target:State -> state:State -> seq<unit>
Full name: Script.Robot.zombie
Multiple items
type GameControl =
  inherit obj
  new : unit -> GameControl
Full name: Script.GameControl
--------------------
new : unit -> GameControl
val control : GameControl
val filter : predicate:('T -> bool) -> list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.filter
namespace System.Text
val async : AsyncBuilder
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken
Full name: Microsoft.FSharp.Control.Async
--------------------
type Async<'T>
Full name: Microsoft.FSharp.Control.Async<_>
static member Async.AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member Async.Ignore : computation:Async<'T> -> Async<unit>
val ignore : value:'T -> unit
Full name: Microsoft.FSharp.Core.Operators.ignore
static member Async.Sleep : millisecondsDueTime:int -> Async<unit>
static member Async.StartImmediate : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
  
  
  More information