Untitled

 avatar
unknown
fsharp
5 months ago
3.1 kB
9
Indexable
#r "nuget:DIKU.Canvas"
open Canvas
open Color
open System
open Asteroids.Vectors
open Asteroids.RandomGenerator
open Asteroids.Asteroids


let width = 400
let height = 400
let center = (200.0, 200.0)
let speed = 5.0

// Moth type definition
type Moth(pos: Vec, hdng: float) =
    member val pos = pos with get, set
    member val heading = hdng with get, set
    member this.draw =
        let x, y = this.pos
        filledEllipse yellow 5.0 5.0 |> translate x y

// Random heading change (between -10 and 10 degrees)
let randomHeadingChange () : float = GetRandomRange (-10.0) 10.0 * Math.PI / 180.0

// Wrap the moth's position if it goes off screen (cyclic movement)
let wrap (v: Vec) : Vec =
    let x, y = v
    let x' = if x < 0.0 then float width + x elif x >  float width then x - float width else x
    let y' = if y < 0.0 then float height + y elif y > float height then y - float height else y
    (x', y')

// Move a moth in the direction of its heading
let move (pos: Vec) (heading: float) : Vec =
    let dx = cos(heading) * speed
    let dy = sin(heading) * speed
    add pos (dx, dy) |> wrap



// Adjust the moth's heading to point towards the light (lamp position)
let adjustHeadingToLight (pos: Vec) (target: Vec) : float =
    let dx, dy = sub target pos
    ang (dx, dy)

// Define the state of the simulation
type State = { lamp: bool; moths: Moth list }

// Initial moths with random positions and random headings
let initialMoths = 
    [ Moth((5.0, 7.0), GetRandomRange 0.0 360.0)
      Moth((100.0, 100.0), GetRandomRange 0.0 360.0)
      Moth((50.0, 50.0), GetRandomRange 0.0 360.0)
      Moth((100.0, 50.0), GetRandomRange 0.0 360.0)
      Moth((50.0, 100.0), GetRandomRange 0.0 360.0) ]

// Draw function to render the simulation
let draw (state: State) =
    let lamplight = 
        if state.lamp then
            filledEllipse white 10.0 10.0 |> translate 200.0 200.0
        else 
            filledEllipse blue 10.0 10.0 |> translate 200.0 200.0
    let mothDrawings = state.moths |> List.map (fun m -> m.draw)
    make (List.fold onto lamplight mothDrawings)

// React function to handle key press and timer events
let react (state: State) (ev: Event) : State option =
    match ev with
    | Key ' ' -> { state with lamp = not state.lamp }  // Toggle the lamp when spacebar is pressed
    | TimerTick ->
        let target = (200.0, 200.0)
        let updatedMoths =
            state.moths
            |> List.map (fun m -> 
                // If the lamp is on, adjust the heading to the light
                if state.lamp then 
                    m.heading <- adjustHeadingToLight m.pos target
                else 
                    m.heading <- m.heading + randomHeadingChange() // Randomly change heading when lamp is off
                m.pos <- move m.pos m.heading
                m)
        { state with moths = updatedMoths }
    | _ -> state
    |> Some

// Initial state with lamp off and the initial list of moths
let initialstate = { lamp = false; moths = initialMoths }

// Start the simulation
let interval = Some 100
interact "moth sim" width height interval draw react initialstate
Editor is loading...
Leave a Comment