F# 康威生命循环修正游戏

F# 康威生命循环修正游戏,f#,F#,大家好,我现在正在做一个项目,用f#创建康威生活游戏。 我的问题是,我想让游戏在一个循环中运行,当我按下开始按钮时,它会不断地改变矩阵,直到我按下停止按钮为止 为了解释我的代码,我可以说我们在循环函数中开始,然后等待,直到我按下一个按钮,然后按下按钮将给出我所采取的操作类型,例如,如果我按下开始按钮,我将获得开始操作,然后在匹配中,我将调用此操作所需的函数,即启动按钮功能 我现在遇到的问题是,当我启动startbutton函数时,它会按应有的方式循环,但我在显示中没有得到任何更改。当我调试这段代

大家好,我现在正在做一个项目,用f#创建康威生活游戏。 我的问题是,我想让游戏在一个循环中运行,当我按下开始按钮时,它会不断地改变矩阵,直到我按下停止按钮为止

为了解释我的代码,我可以说我们在
循环
函数中开始,然后等待,直到我按下一个按钮,然后按下按钮将给出我所采取的操作类型,例如,如果我按下开始按钮,我将获得开始操作,然后在匹配中,我将调用此操作所需的函数,即
启动按钮
功能

我现在遇到的问题是,当我启动
startbutton
函数时,它会按应有的方式循环,但我在显示中没有得到任何更改。当我调试这段代码时,我的理解是,我正在更改我发送的列表,而不是主列表,这就是为什么我没有在屏幕上看到任何东西,这可能是错误的,也可能不是主要问题,但我没有找到我看到的行为的任何其他原因。所以我正在考虑改变我现在的结构,但是我找不到一个好的方法使它工作,因为现在即使它在正确的列表上循环,我也会被困在
startbutton
功能上,这意味着我的其他按钮不能像stop按钮那样工作

总之,我想要的是能够让游戏运行并且永远不会停止,直到我按下停止按钮,然后游戏应该停止,或者如果我启动游戏并按下下一步按钮而不是开始按钮,
startbutton
中发生的循环应该循环一次,这相当于游戏中的一步或一次生命循环

那么,你知道我应该如何解决这个问题,或者如何改进我现有的结构,或者你有一个不需要改变结构的解决方案吗

下面的代码是我现在所拥有的,你可以用这些代码来看看游戏在GUI中是如何工作的,也许这会给你一些解决问题的方法

open System.Windows.Forms
open System.Drawing


module Gui = 

let form = new Form(Width = 528, Height = 572)
let matrixlabel = Array2D.init 16 16 (fun y x -> (new Label(Width = 32, Height = 32, BackColor = Color.White, 
                                                            BorderStyle = BorderStyle.FixedSingle, Left = 32*x, Top = 32*y)))
let lblList = matrixlabel |> Seq.cast<Label> |> Seq.fold (fun l n -> n :: l) []
let btnAdd0 = new Button(Text="Start", Top = 513, Height = 20, Width = 40)
let btnAdd1 = new Button(Text="Stop", Top = 513, Height = 20, Width = 40, Left = 40)
let btnAdd2 = new Button(Text="Next", Top = 513, Height = 20, Width = 40, Left = 80)
let btnAdd3 = new Button(Text="Steps", Top = 513, Height = 20, Width = 40, Left = 120)
let btnlist = [btnAdd0; btnAdd1; btnAdd2; btnAdd3;]
let text = new TextBox(Text="", Top = 513, Left = 160);


for y in 0 .. 15 do
    for x in 0 .. 15 do
        form.Controls.AddRange [| matrixlabel.[y,x] |]

for i in btnlist do 
    form.Controls.AddRange [| i |]

form.Controls.AddRange [| text |]
open System.Windows.Forms
开放系统.绘图
模块Gui=
让形状=新形状(宽度=528,高度=572)
让matrixlabel=Array2D.init 16(有趣的y x->)(新标签(宽度=32,高度=32,背景色=Color.White,
BorderStyle=BorderStyle.FixedSingle,左=32*x,上=32*y)))
让lblList=matrixlabel |>Seq.cast |>Seq.fold(fun l n->n::l)[]
让btnAdd0=新按钮(Text=“开始”,顶部=513,高度=20,宽度=40)
让btnAdd1=新按钮(Text=“Stop”,顶部=513,高度=20,宽度=40,左侧=40)
让btnAdd2=新建按钮(Text=“Next”,顶部=513,高度=20,宽度=40,左侧=80)
让btnAdd3=新建按钮(Text=“Steps”,顶部=513,高度=20,宽度=40,左侧=120)
设btnlist=[btnAdd0;btnAdd1;btnAdd2;btnAdd3;]
让text=newtextbox(text=”“,Top=513,Left=160);
对于0中的y。。15做
对于0中的x。。15做
form.Controls.AddRange[|矩阵标签[y,x]|]
因为我在btnlist做什么
form.Controls.AddRange[|i |]
form.Controls.AddRange[| text |]

开放系统
打开System.Windows.Forms
开放图形用户界面
开放系统.绘图
打开FSharpx.Control.Observable
类型操作=
|开始
|停止
|下一个
|整数步
|点的Pnt
主模块=
//确保createSearchList中的所有单元格都在我们拥有的矩阵中
设inRange(s:int)(a:int)yx=
匹配
|当s=-1->false时为0
|15当s=1->false时
|->将x与
|当a=-1->false时为0
|15当a=1->false时
|_uu->true
//创建一个小列表,包含我们想要检查的细胞的所有邻居,直到下一代它是否存活
让createSearchList y x(列表:标签[,])=
[因为我在-1..1做
对于j in-1..1 do
如果((i y|j x)和&(i 0|j 0))和&(in范围(i)(j)y x)=真)
然后收益率(列表[y+i,x+j])]
//数一数活着的邻居的数量
让rec chek(列表:标签列表)计数器=
匹配列表
|head::tail when head.BackColor=Color.Black->chek tail(计数器+1)
|head::tail when head.BackColor=Color.White->chek tail计数器
|[]->计数器
//创建一个新的列表,描述下一代主列表的外观
让我们检查标签(标签:标签[,])=
标签
|>Array2D.mapi(fun e r u->match u with
|u.BackColor=Color.Black->将chek(createSearchList e r标签)0与
|当x<2 | | x>3->新标签(宽度=u.宽度,高度=u.高度,背景色=颜色.白色,
BorderStyle=u.BorderStyle,Left=u.Left,Top=u.Top)
|当x=2 | | x=3->新标签(宽度=u.宽度,高度=u.高度,背景色=颜色.黑色,
BorderStyle=u.BorderStyle,Left=u.Left,Top=u.Top)
|新标签(宽度=u.宽度,高度=u.高度,背景色=颜色.黑色,
BorderStyle=u.BorderStyle,Left=u.Left,Top=u.Top)
|u.BackColor=Color.White->将chek(createSearchList e r标签)0与
open System
open System.Windows.Forms
open Gui
open System.Drawing
open FSharpx.Control.Observable

type Action = 
| Start 
| Stop 
| Next 
| Steps of int
| Pnt of Point

module Main =
// making sure that all the cells in the createSearchList is inside the matrix we have
let inRange (s : int) (a : int) y x  = 
    match y with 
    | 0 when s = -1 -> false
    | 15 when s = 1 -> false
    | _ -> match x with 
           | 0 when a = -1 -> false
           | 15 when a = 1 -> false
           | _ -> true

// create a small list contaning all the neighbors of the cell we want to check if it will live or not until the next gen
let createSearchList y x (list : Label [,]) =
    [for i in -1..1 do 
     for j in -1..1 do 
     if (((i <> y || j <> x) && (i <> 0 || j <> 0)) && (inRange (i) (j) y x) = true) 
     then yield (list.[y+i, x+j])] 

// count the amount of living neighbors
let rec chek (list : Label List) counter = 
    match list with 
    | head::tail when head.BackColor = Color.Black -> chek tail (counter+1)
    | head::tail when head.BackColor = Color.White -> chek tail counter
    | [] -> counter
        

// create a new list contating how our main list should look like in the next generation 
let checkLabel (labels:Label [,]) = 
    labels
    |> Array2D.mapi (fun e r u -> match u with 
                                  | u when u.BackColor = Color.Black -> match chek (createSearchList e r labels) 0 with 
                                                                        | x when x < 2 || x > 3 -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.White, 
                                                                                                                BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                                                   
                                                                        | x when x = 2 || x = 3 -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.Black, 
                                                                                                                BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                                                   
                                                                        | _ -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.Black, 
                                                                                            BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                               
                                  | u when u.BackColor = Color.White -> match chek (createSearchList e r labels) 0 with 
                                                                        | x when x < 2 || x > 3 -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.White, 
                                                                                                                BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                                                                
                                                                        | x when x = 3 -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.Black, 
                                                                                                        BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                                          
                                                                        | _ -> new Label(Width = u.Width, Height = u.Height, BackColor = Color.White, 
                                                                                            BorderStyle = u.BorderStyle, Left = u.Left, Top = u.Top)
                                                                               
                                  )

// changing the color of each cell in the main list to match the list we created for the next gen 
let changeLabel (labels : Label [,]) (l : Label [,]) =
    labels
    |> Array2D.mapi (fun e r u -> match u with 
                                  | u when u.BackColor = Color.Black -> l.[e,r].BackColor <- Color.Black
                                  | u when u.BackColor = Color.White -> l.[e,r].BackColor <- Color.White
                    )

let eventType action =
    let timer = Timers.Timer(1000.)
    match action with 
    Start -> timer.Start()
             timer.Elapsed
        
                      
//loops and every generation (loop) is 1 sec
let rec startbutton (l : Label [,]) (steps : int) (start : bool) (action) = async{
    let event = Async.AwaitEvent (eventType action) |> Async.Ignore
    Async.RunSynchronously event

    let labels = checkLabel l 
    changeLabel labels l 
    
    return! startbutton labels (steps) start action
}


// the main loop that controlls every button click 
let rec loop (l : Label [,]) (runType : IObservable<Action>) = async{
    let! action = Async.AwaitObservable(runType)

    match action with 
    | Pnt(location) -> let indexX = location.X/32
                       let indexY = location.Y/32
                       if l.[indexY, indexX].BackColor = Color.Black then 
                           l.[indexY, indexX].BackColor <- Color.White
                       else 
                           l.[indexY, indexX].BackColor <- Color.Black
                       return! loop l runType
    | Stop -> return! loop l runType
    | Start -> return! startbutton (l) (0) (true) (action)
    | _ -> return! loop l runType
}

module GuiInterface = 
    //Here we define what we will be observing (clicks)
    let check (element : string) = 
        match element with 
        | x when x = "Start" -> Start
        | x when x = "Stop" -> Stop
        | x when x = "Next" -> Next
        | x when x = "Steps" -> Steps((text.Text |> int))

    let rec lblClick (list : Label List) = 
       match list with 
       | [x] ->  (Observable.map (fun _-> Pnt(x.Location)) (x.Click))
       | head::tail -> Observable.merge (Observable.map (fun _-> Pnt(head.Location)) (head.Click)) (lblClick (tail))
       | [] -> failwith "empty"

    let rec btnClick (listbtn : Button List) (listlbl : Label List) = 
       match listbtn with 
       | [x] -> Observable.merge (Observable.map (fun _-> (check (x.Text))) (x.Click)) (lblClick (listlbl))
       | head::tail -> Observable.merge (Observable.map (fun _-> (check (head.Text))) (head.Click)) (btnClick (tail) (listlbl)) 
       | [] -> failwith "empty"


Async.StartImmediate (loop (matrixlabel) (GuiInterface.btnClick (btnlist) (lblList))); 
Application.Run(form)