Skip to content

Instantly share code, notes, and snippets.

@woxtu
Last active April 3, 2017 17:42
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 woxtu/610b88dd09a3856bcb77899314e16039 to your computer and use it in GitHub Desktop.
Save woxtu/610b88dd09a3856bcb77899314e16039 to your computer and use it in GitHub Desktop.
Conway's Game of Life in Facebook/Reason
{
"name": "lifegame",
"sources": [
"./"
]
}
<!DOCTYPE html>
<meta charset="utf-8">
<title>Conway's Game of Life</title>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script src="dist/main.js"></script>
module Element = {
type t;
};
module Context = {
type t;
external setFillStyle : t => string => unit = "fillStyle" [@@bs.set];
external fillRect : int => int => int => int => unit = "" [@@bs.send.pipe: t];
};
module Canvas = {
type t = Element.t;
external width : t => int = "" [@@bs.get];
external height : t => int = "" [@@bs.get];
external getContext : string => Context.t = "" [@@bs.send.pipe: t];
};
module Document = {
external getElementById : string => option Element.t = "document.getElementById" [@@bs.val] [@@bs.return null_to_opt];
};
module Window = {
external requestAnimationFrame : (unit => unit) => unit = "" [@@bs.val];
};
module Array = {
include Array;
let filter = Js.Array.filter;
};
type cell = Dead | Alive;
let size = 2;
let foregroundColor = "#F36";
let backgroundColor = "#000";
let clear canvas context => {
Context.setFillStyle context backgroundColor;
context |> Context.fillRect 0 0 (canvas |> Canvas.width) (canvas |> Canvas.height);
};
let draw grid context => {
Context.setFillStyle context foregroundColor;
grid |> Array.iteri @@ fun x cells =>
cells |> Array.iteri @@ fun y cell => switch cell {
| Alive => context |> Context.fillRect (x * size) (y * size) size size
| _ => ()
}
};
let rows grid => Array.length grid;
let columns grid => switch (Array.length grid) {
| length when 0 < length => Array.length @@ Array.get grid 0
| _ => -1
};
let index min max n => switch n {
| n when n < min => max
| n when max < n => min
| n => n
};
let neighbours x y grid =>
[|(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)|]
|> Array.map @@ fun (a, b) => {
let m = index 0 (rows grid - 1) (x + a);
let n = index 0 (columns grid - 1) (y + b);
Array.get (Array.get grid m) n
};
let next grid =>
grid |> Array.mapi @@ fun x cells =>
cells |> Array.mapi @@ fun y cell =>
switch (neighbours x y grid |> Array.filter ((==) Alive) |> Array.length) {
| 3 => Alive
| 2 => cell
| _ => Dead
};
let rec run canvas grid => {
let context = canvas |> Canvas.getContext "2d";
context |> clear canvas;
context |> draw grid;
Window.requestAnimationFrame @@ fun () => run canvas @@ next grid
};
let () = {
let canvas = switch (Document.getElementById "canvas") {
| None => failwith "Cannot find the canvas"
| Some canvas => canvas
};
let rows = (canvas |> Canvas.width) / size;
let columns = (canvas |> Canvas.height) / size;
Random.self_init ();
let grid =
Array.make_matrix rows columns () |> Array.map @@ fun cells =>
cells |> Array.map @@ fun _ => if (Random.bool ()) { Alive } else { Dead };
run canvas grid
};
{
"name": "lifegame",
"version": "0.1.0",
"private": true,
"license": "MIT",
"scripts": {
"build": "webpack",
"watch": "webpack -w",
"serve": "http-server",
"develop": "npm-run-all -p watch serve"
},
"devDependencies": {
"bs-loader": "^1.1.0",
"bs-platform": "^1.5.2",
"http-server": "^0.9.0",
"npm-run-all": "^4.0.2",
"webpack": "^2.2.1"
}
}
const path = require('path');
module.exports = {
entry: {
main: './main.re',
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{ test: /\.(re|ml)$/, use: 'bs-loader' },
],
},
resolve: {
extensions: ['.re', '.ml', '.js'],
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment