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:
|
#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 pause state n = seq {
for i = 1 to n do yield state
}
let wait target state = 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 state
}
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 state
}
let zombie target state = seq {
yield! pause state (rand.Next(10))
while true do
yield! wait target state
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 }
yield (zombie humanoid state).GetEnumerator()
]
let moveRobots () =
robots <- robots |> List.filter (fun machine ->
let alive = machine.MoveNext()
if alive then
let state = machine.Current
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
)
#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 pause : state:'a -> n:int -> seq<'a>
Full name: Script.Robot.pause
val state : 'a
val n : int
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 i : int
val wait : target:State -> state:State -> seq<State>
Full name: Script.Robot.wait
val target : State
val state : State
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<State>
Full name: Script.Robot.home
val zombie : target:State -> state:State -> seq<State>
Full name: Script.Robot.zombie
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
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