0votos

La tela de araña en F#

por josejuan hace 5 años

Atención a la clausura de "s.OnMoving.Add" que es curiosa.

Un problema fácil de resolver imperativamente... ¿y funcionalmente? (inmutabilidad y transparencia referencial). Aun así (el enfoque funcional), creo que puede ser un buen kata para practicar punteros y/o TAD's.

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
module SpiderWorld 
 
open System 
open System.Drawing 
open System.Windows.Forms 
open System.Threading 
 
let rnd = new Random() 
 
type Spider(arenaSize : int, blockSize : int) = 
  let moving = new Event<_>() 
  member self.OnMoving = moving.Publish 
  member self.Create = 
                async { 
                  let (x, y) = (ref (rnd.Next arenaSize), ref (rnd.Next arenaSize)) 
                  while true do 
                    let (dx, dy) = [|(0, 1); (0, -1); (1, 0); (-1, 0)|].[rnd.Next 4] 
                    for i = 0 to 9 do 
                      let delta c d = c * blockSize + int (0.1 * float (d * i * blockSize)) 
                      moving.Trigger (delta !x dx, delta !y dy) 
                      Thread.Sleep(rnd.Next(50, 100)) 
                    x := (arenaSize + !x + dx) % arenaSize 
                    y := (arenaSize + !y + dy) % arenaSize 
                } |> Async.Start 
 
type World(arenaSize : int, blockSize : int, spiders : int) = 
  let arenaL = arenaSize * blockSize 
  let arena = new Form(Text = "", Visible = true, TopMost = true, Width = arenaL, Height = arenaL) 
  let ispiders = [|0..(spiders - 1)|] 
  let spiderPos = Array.map (fun _ -> ref (0, 0)) ispiders 
  do for i in ispiders do 
       let s = new Spider(arenaSize, blockSize) 
       s.OnMoving.Add (fun p -> spiderPos.[i] := p; arena.Refresh()) 
       s.Create 
  do arena.Paint.Add ( fun e -> 
                         let g = e.Graphics 
                         g.Clear(Color.White) 
                         for pos in spiderPos do 
                           let (x, y) = !pos 
                           g.DrawRectangle(Pens.Black, x, y, 3, 3) 
  do Application.Run(arena) 
 
Async.Start( async { ignore (new World(3, 100, 5)) }) 
ignore (new World(30, 30, 10)) 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.