Skip to content

Commit 5a2f834

Browse files
committed
Fix game-of-life example inconsistencies; Fix ternary expression issues in void contexts and variable statements; Simplify HEAP_BASE handling
1 parent 4026c08 commit 5a2f834

19 files changed

Lines changed: 640 additions & 545 deletions

dist/asc.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/asc.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/game-of-life/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
node_modules/
1+
node_modules/

examples/game-of-life/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
Conway's Game of Life
22
=====================
33

4-
An [AssemblyScript](http://assemblyscript.org) example. Continuously updates the cellular automaton and visualizes its state on a canvas.
4+
An [AssemblyScript](http://assemblyscript.org) example. Continuously updates the cellular automaton and visualizes its state on a canvas. Compiles to ~450 bytes of optimized WASM, no strings attached.
55

66
Instructions
77
------------
88

9-
You have to install the 'opn' package to be able to run the `npm browser` command
9+
First, install the development dependencies:
1010

1111
```
1212
$> npm install
1313
```
1414

15-
To build [assembly/game-of-life.ts](./assembly/game-of-life.ts) to an untouched and an optimized `.wasm` including their respective `.wat` representations, run:
15+
Now, to build [assembly/game-of-life.ts](./assembly/game-of-life.ts) to an untouched and an optimized `.wasm` including their respective `.wat` representations, run:
1616

1717
```
1818
$> npm run build
1919
```
2020

21-
Afterwards, open [game-of-life.html](./game-of-life.html) in a browser (ideally one that allows `fetch`ing the `.wasm` from the local filesystem).
21+
Afterwards, run `node server` to start a <a href="http://localhost:9080">local server</a>. Should also automatically launch a browser.

examples/game-of-life/assembly/game-of-life.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,54 @@
1-
// A simplified version of the game of life as seen on http://dcode.io
1+
// The Game of Life, also known simply as Life, is a cellular automaton devised by the British
2+
// mathematician John Horton Conway in 1970.
3+
// see: https://en.wikipedia.org/wiki/Conway's_Game_of_Life
24

3-
var w: u32, // width
4-
h: u32, // height
5-
s: u32; // total size
5+
var w: i32, h: i32, s: i32;
66

7-
/** Initializes width and height. */
8-
export function init(w_: u32, h_: u32): void {
9-
w = w_;
10-
h = h_;
11-
s = w * h;
7+
/** Initializes width and height. Called once from JS. */
8+
export function init(width: i32, height: i32): void {
9+
w = width;
10+
h = height;
11+
s = width * height;
1212
}
1313

14-
/** Performs one step. */
14+
/** Performs one step. Called about 30 times a second from JS. */
1515
export function step(): void {
16-
var hm1 = h - 1,
17-
wm1 = w - 1;
18-
for (var y: u32 = 0; y < h; ++y) {
19-
var ym1 = select<u32>(hm1, y - 1, y == 0),
20-
yp1 = select<u32>(0, y + 1, y == hm1);
21-
for (var x: u32 = 0; x < w; ++x) {
22-
var xm1 = select<u32>(wm1, x - 1, x == 0),
23-
xp1 = select<u32>(0, x + 1, x == wm1);
24-
var n = (
16+
var hm1 = h - 1, // h - 1
17+
wm1 = w - 1; // w - 1
18+
19+
// The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square
20+
// "cells", each of which is in one of two possible states, alive or dead.
21+
for (let y = 0; y < h; ++y) {
22+
23+
let ym1 = y == 0 ? hm1 : y - 1, // y - 1
24+
yp1 = y == hm1 ? 0 : y + 1; // y + 1
25+
for (let x = 0; x < w; ++x) {
26+
let xm1 = x == 0 ? wm1 : x - 1, // x - 1
27+
xp1 = x == wm1 ? 0 : x + 1; // x + 1
28+
29+
// Every cell interacts with its eight neighbours, which are the cells that are horizontally,
30+
// vertically, or diagonally adjacent:
31+
let aliveNeighbors = (
2532
load<u8>(ym1 * w + xm1) + load<u8>(ym1 * w + x) + load<u8>(ym1 * w + xp1) +
2633
load<u8>(y * w + xm1) + load<u8>(y * w + xp1) +
2734
load<u8>(yp1 * w + xm1) + load<u8>(yp1 * w + x) + load<u8>(yp1 * w + xp1)
2835
);
29-
if (load<u8>(y * w + x)) {
30-
if (n < 2 || n > 3) {
31-
store<u8>(s + y * w + x, 0);
36+
37+
let alive = load<u8>(y * w + x);
38+
if (alive) {
39+
switch (aliveNeighbors) {
40+
// A live cell with fewer than 2 live neighbors dies, as if caused by underpopulation.
41+
// A live cell with more than 3 live neighbors dies, as if by overpopulation.
42+
default: { store<u8>(s + y * w + x, 0); break; }
43+
// A live cell with 2 or 3 live neighbors lives on to the next generation.
44+
case 2: case 3:
45+
}
46+
} else {
47+
switch (aliveNeighbors) {
48+
// A dead cell with exactly 3 live neighbors becomes a live cell, as if by reproduction.
49+
case 3: { store<u8>(s + y * w + x, 1); break; }
50+
default:
3251
}
33-
} else if (n == 3) {
34-
store<u8>(s + y * w + x, 1);
3552
}
3653
}
3754
}
Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,47 @@
1-
<canvas id="canvas" width="640" height="480"></canvas><script>
1+
<html>
2+
<head>
3+
<style>
4+
html, body { height: 100%; margin: 0; overflow: hidden; color: #111; background: #fff; font-family: sans-serif; }
5+
h1 { padding: 20px; font-size: 12pt; }
6+
a { color: #111; text-decoration: none; }
7+
a:hover { color: #0074C1; text-decoration: underline; }
8+
canvas { position: absolute; top: 60px; left: 20px; width: calc(100% - 40px); height: calc(100% - 80px); }
9+
</style>
10+
</head>
11+
<body>
12+
<h1>
13+
<a href="https://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway's Game Of Life</a> in
14+
<a href="http://assemblyscript.org">AssemblyScript</a>
15+
</h1>
16+
<canvas id="canvas"></canvas>
17+
<script>
218

3-
// Fetch the .wasm
4-
fetch("game-of-life.optimized.wasm").then(response => response.arrayBuffer()).then(binary => {
19+
// Set up the canvas with a 2D rendering context
20+
var cnv = document.getElementById("canvas");
21+
var ctx = cnv.getContext("2d");
22+
var bcr = cnv.getBoundingClientRect();
23+
cnv.width = bcr.width | 0;
24+
cnv.height = bcr.height | 0;
525

6-
// Instantiate the module
7-
var module = new WebAssembly.Module(binary);
8-
var instance = new WebAssembly.Instance(module, { env: { abort: function() {} } });
26+
// Compute the size of the universe (here: 2px per cell)
27+
var w = bcr.width >>> 1;
28+
var h = bcr.height >>> 1;
29+
var s = w * h; // memory required to store either input or output
30+
var S = s + s; // total memory required to store input and output
931

10-
// Set up the canvas with a 2D rendering context
11-
var cnv = document.getElementById("canvas");
12-
var ctx = cnv.getContext("2d");
13-
var w = cnv.width,
14-
h = cnv.height,
15-
s = w * h, // memory required to store either input or output
16-
S = s + s; // total memory required to store input and output
32+
// Compute the size of and instantiate the module's memory
33+
var nPages = ((S + 0xffff) & ~0xffff) >>> 16; // aligned up in 64k units
34+
var memory = new WebAssembly.Memory({ initial: nPages });
1735

18-
// Grow the (exported) memory if its size isn't sufficient
19-
var memory = instance.exports.memory;
20-
if (memory.buffer.byteLength < S)
21-
memory.grow(Math.ceil((S - memory.buffer.byteLength) / 65536));
36+
// Fetch and instantiate the module
37+
WebAssembly.instantiateStreaming(fetch("game-of-life.optimized.wasm"), {
38+
env: { memory: memory }
39+
})
40+
.then(module => {
41+
var exports = module.instance.exports;
2242

23-
// Initialize with width and height
24-
instance.exports.init(w, h);
43+
// Tell the module about the universe's width and height
44+
exports.init(w, h);
2545

2646
// Fill input at [0, s-1] with random live cells
2747
var mem = new Uint8Array(memory.buffer);
@@ -31,23 +51,26 @@
3151

3252
// Update about 30 times a second
3353
(function update() {
34-
setTimeout(update, 33);
35-
instance.exports.step();
36-
mem.set(mem.subarray(s, S), 0); // copy output -> input
54+
setTimeout(update, 30);
55+
exports.step();
56+
mem.copyWithin(0, s, S); // copy output at [s, S] to input at [0, s]
3757
})();
3858

39-
// Keep rendering the output at [s, 2*s-1]
59+
// Keep rendering the output at [s, S]
4060
(function render() {
4161
requestAnimationFrame(render);
42-
ctx.clearRect(0, 0, w, h);
62+
ctx.fillStyle = "rgba(238,238,238,0.67)";
63+
ctx.fillRect(0, 0, w << 1, h << 1);
4364
ctx.fillStyle = "#333";
4465
for (var y = 0; y < h; ++y)
4566
for (var x = 0; x < w; ++x)
4667
if (mem[s + y * w + x])
47-
ctx.fillRect(x, y, 1, 1);
68+
ctx.fillRect(x << 1, y << 1, 2, 2);
4869
})();
4970

5071
}).catch(err => {
5172
throw err;
5273
});
5374
</script>
75+
</body>
76+
</html>
453 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)