Conway's Game of Life with F# and Windows Forms



我正在尝试使用f#和winforms绘制一个16x16网格。如何在winforms上用f#couse将数组绘制为正方形?我真的不想要一个网格图像。

对于Conway的《人生游戏》,对于任何任务,最好将其分解为可管理的块:

  • 一种从游戏坐标投影到显示坐标(缩放(的机制
  • ";板;(2D阵列(,包含一些随机内容
  • 计算下一代的函数
  • 一个Windows窗体,用于承载所有内容并进行绘制,其中还包含
    • 用于在间隔后更新表单的计时器
    • 双缓冲代码(避免闪烁(
    • Paint方法绘制自动机的重写
    • Click方法的重写,以便您可以更改单元格
    • KeyDown方法的重写,因此关闭窗体

我们在这里使用18乘18的阵列,因为边缘最外面的细胞被认为是死的。或者,您可以在页边空白处换行。

open System.Windows.Forms
open System.Drawing
let xmax, ymax, scale = 18, 18, 20
let enscale x y = Point(x * scale, y * scale)
let descale (p : Point) = p.X / scale, p.Y / scale
let size = enscale xmax ymax

板(请注意,数组(是可变的:

let rnd = System.Random()
let board =
Array2D.init xmax ymax (fun i j ->
if rnd.NextDouble() < 0.9 then 0 else 1 )

我们可以在确定新状态后更改板,这就是为什么新状态将被计算为元组列表,表示数组的位置和新内容。

let nextGeneration() =
let loop2 x y f =
[ for x in 0..xmax - 1 do
for y in 0..ymax - 1 do
yield f x y ]
|> List.iter (fun (x, y, c) -> board.[x, y] <- c)
let chkbnds n i s =
if n + i < 0 || n + i > s - 1 then None
else Some(n + i)
loop2 xmax ymax (fun x y ->
[-1, 0; -1, -1; 0, -1; 1, -1; 1, 0; 1, 1; 0, 1; -1, 1]
|> List.fold (fun c (i, j) ->
match c, chkbnds x i xmax, chkbnds y j ymax with
| Some c, Some x, Some y -> Some(c + board.[x, y])
| _ -> None ) (Some 0)
|> function
| Some 3 when board.[x, y] = 0 -> 1
| Some 2 | Some 3 when board.[x, y] = 1 -> 1
| _ -> 0
|> fun c -> x, y, c )

位图(用于缓冲(,以及具有PaintClickKeyDown:覆盖的窗体

let bitmap = new Bitmap(size.X, size.Y)
type MyForm() as this =
inherit Form(ClientSize = Size size)
let timer = 
{ new Timer(Interval = 300) with
override me.OnTick _ =
nextGeneration()
this.Invalidate() }
do  this.SetStyle(ControlStyles.AllPaintingInWmPaint, true)
this.SetStyle(ControlStyles.UserPaint, true)
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true)
timer.Start()
override me.OnPaint e =
use g = Graphics.FromImage bitmap
g.FillRectangle(Brushes.White, Rectangle(Point.Empty, this.ClientSize))
for x in 0..xmax - 1 do
for y in 0..ymax - 1 do
if board.[x, y] = 1 then
g.FillRectangle(Brushes.Black, 
Rectangle(enscale x y, Size(enscale 1 1)) )
e.Graphics.DrawImage(bitmap, 0, 0)
override me.OnClick e =
let e = e :?> MouseEventArgs
if e.Button = MouseButtons.Right then timer.Start ()
else
timer.Stop()
let x, y = descale e.Location
board.[x, y] <- if board.[x, y] = 0 then 1 else 0
me.Invalidate()
override me.OnKeyDown _ =
me.Close()

最新更新