Last active
August 29, 2015 14:05
-
-
Save chribben/2c3cef2b8ac4da2aef0e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
open System.Windows.Forms | |
open System.Drawing | |
//************Number of cells and dimensions************ | |
let cellSide = 10 | |
let noOfCellsInOneDir = 16 | |
let side = cellSide * noOfCellsInOneDir | |
let totNoOfCells = pown noOfCellsInOneDir 2 | |
//***********Helper functions******************** | |
let mapMatrix matrix = (List.map >> List.map) matrix | |
let combine list1 list2 = List.collect (fun x -> List.map (fun y -> (x,y)) list1) list2 | |
//*************MODEL******************* | |
type State = Alive | Dead | |
type Cell = {state: State; coords: (int*int)} | |
type Game = {board: Cell list list} | |
with member this.flatten = | |
List.collect (fun row -> row) this.board | |
//***************INIT****************** | |
let rnd = new Random() | |
let game = {board = List.init noOfCellsInOneDir | |
(fun i -> List.init noOfCellsInOneDir | |
(fun j -> {coords = (i,j); state = (if rnd.Next() % 2 = 0 then Dead else Alive)}))} | |
//*************UPDATE (run to calculcate next generations of cells)****************** | |
let getCell game (x,y) = game.board.[x].[y] | |
let getNeighbours game cell = | |
let (x,y) = cell.coords | |
let norm coordinate = (coordinate + noOfCellsInOneDir)%noOfCellsInOneDir //Adjust neighbours for cells on first and last row/column | |
combine [norm(x-1);x;norm(x+1)] [norm(y-1);y;norm(y+1)] |> List.map (fun coord -> getCell game coord) |> | |
List.filter (fun c -> c.coords <> (x,y)) | |
let noOfLiveNeighbours game cell = getNeighbours game cell |> List.sumBy (fun cell -> if cell.state = Alive then 1 else 0) | |
let updateCell game cell = match noOfLiveNeighbours game cell with | |
| 3 when cell.state = Dead -> {cell with state = Alive} | |
| 2 | 3 -> cell | |
| n when n < 2 || n > 3 -> {cell with state = Dead} | |
let updateGame game = {game with board = mapMatrix (fun cell -> updateCell game cell) game.board} | |
//*************VIEW************ | |
let form = new Form() | |
let keypressEventHandler (sender:Object) (e:KeyPressEventArgs -> unit) = () | |
form.ClientSize <- new Size(side, side) | |
form.FormBorderStyle <- FormBorderStyle.FixedSingle; | |
form.MaximizeBox <- false; | |
form.MinimizeBox <- false; | |
form.Show() |> ignore | |
let graphics = form.CreateGraphics() | |
graphics.Clear(Color.White) | |
let tupleToPoint (x,y) = new Point(cellSide*x,cellSide*y) | |
let black = new SolidBrush(Color.Black) | |
let white = new SolidBrush(Color.White) | |
let toRect cell = new Rectangle(tupleToPoint cell.coords, new Size(cellSide,cellSide)) | |
let toRectsArray cells = cells |> List.map (fun cell -> toRect cell) |> List.toArray | |
let rec updateBoard (game:Game) = async{ | |
let aliveCells = game.flatten |> List.filter (fun cell -> cell.state = Alive) | |
if List.length aliveCells = 0 then | |
Async.Sleep 0 |> ignore | |
else | |
let (aliveCells, deadCells) = game.board |> List.collect (fun r -> r ) |> List.partition (fun cell -> cell.state = Alive) | |
graphics.FillRectangles(black, aliveCells |> toRectsArray) | |
graphics.FillRectangles(white, deadCells |> toRectsArray) | |
do! Async.Sleep 1000 | |
do! updateBoard (updateGame game) | |
} | |
Async.StartImmediate(updateBoard game) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment