Skip to content

Instantly share code, notes, and snippets.

@chribben
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chribben/2c3cef2b8ac4da2aef0e to your computer and use it in GitHub Desktop.
Save chribben/2c3cef2b8ac4da2aef0e to your computer and use it in GitHub Desktop.
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