Skip to content

Commit b170bc9

Browse files
committed
add testing and debugging
1 parent d6cbdc9 commit b170bc9

File tree

6 files changed

+131
-34
lines changed

6 files changed

+131
-34
lines changed

05-game-of-life/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ wee_alloc = { version = "0.4.5", optional = true }
3333
[dev-dependencies]
3434
wasm-bindgen-test = "0.3.13"
3535

36+
[dependencies.web-sys]
37+
version = "0.3"
38+
features = [
39+
"console",
40+
]
41+
3642
[profile.release]
3743
# Tell `rustc` to optimize for small code size.
3844
opt-level = "s"

05-game-of-life/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ A zero-player game to learn how to use Rust, WebAssembly, and JavaScript togethe
1212
- serving locally with webpack.
1313
- implementing the Game of Life with Rust.
1414
- rendering to canvas directly from memory with JavaScript.
15+
- testing the tick function and debugging.
1516

16-
Based on [The Rust and WebAssembly Book](https://rustwasm.github.io/docs/book/) by The Rust and WebAssembly Working Group (2021).
17+
Based on [The Rust and WebAssembly Book](https://rustwasm.github.io/docs/book/) by The Rust and WebAssembly Working Group (2021).

05-game-of-life/src/lib.rs

+49
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ mod utils;
33
use std::fmt;
44
use wasm_bindgen::prelude::*;
55
extern crate js_sys;
6+
extern crate web_sys;
7+
8+
// A macro to provide `println!(..)`-style syntax for `console.log` logging.
9+
macro_rules! log {
10+
($( $t:tt)* ) => {
11+
web_sys::console::log_1(&format!( $( $t )*).into());
12+
};
13+
}
614

715
#[wasm_bindgen]
816
#[repr(u8)]
@@ -39,6 +47,19 @@ impl Universe {
3947
}
4048
count
4149
}
50+
51+
/// Get the dead and alive values of the entire universe.
52+
pub fn get_cells(&self) -> &[Cell] {
53+
&self.cells
54+
}
55+
/// Set cells to be alive in a universe by passing the row and column
56+
/// of each cell as an array.
57+
pub fn set_cells(&mut self, cells: &[(u32, u32)]) {
58+
for (row, col) in cells.iter().cloned() {
59+
let idx = self.get_index(row, col);
60+
self.cells[idx] = Cell::Alive;
61+
}
62+
}
4263
}
4364

4465
/// Public methods, exported to JavaScript.
@@ -53,6 +74,14 @@ impl Universe {
5374
let cell = self.cells[idx];
5475
let live_neighbors = self.live_neighbor_count(row, col);
5576

77+
log!(
78+
"cell[{}, {}] is initially {:?} and has {} live neighbors",
79+
row,
80+
col,
81+
cell,
82+
live_neighbors
83+
);
84+
5685
let next_cell = match (cell, live_neighbors) {
5786
// Rule 1: Any live cell with fewer than two live neighbours
5887
// dies, as if caused by underpopulation.
@@ -69,13 +98,17 @@ impl Universe {
6998
// All other cells remain in the same state.
7099
(otherwise, _) => otherwise,
71100
};
101+
102+
log!("it becomes {:?}", next_cell);
103+
72104
next[idx] = next_cell;
73105
}
74106
}
75107
self.cells = next;
76108
}
77109

78110
pub fn new() -> Universe {
111+
utils::set_panic_hook();
79112
let width = 64;
80113
let height = 64;
81114

@@ -111,6 +144,22 @@ impl Universe {
111144
pub fn cells(&self) -> *const Cell {
112145
self.cells.as_ptr()
113146
}
147+
148+
/// Set the width of the universe.
149+
///
150+
/// Resets all cells to the dead state.
151+
pub fn set_width(&mut self, width: u32) {
152+
self.width = width;
153+
self.cells = (0..width * self.height).map(|_i| Cell::Dead).collect();
154+
}
155+
156+
/// Set the height of the universe.
157+
///
158+
/// Resets all cells to the dead state.
159+
pub fn set_height(&mut self, height: u32) {
160+
self.height = height;
161+
self.cells = (0..self.width * height).map(|_i| Cell::Dead).collect();
162+
}
114163
}
115164

116165
impl fmt::Display for Universe {

05-game-of-life/tests/web.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,47 @@
11
//! Test suite for the Web and headless browsers.
2+
// wasm-pack test --chrome --headless
23

34
#![cfg(target_arch = "wasm32")]
45

56
extern crate wasm_bindgen_test;
67
use wasm_bindgen_test::*;
78

9+
extern crate game_of_life;
10+
use game_of_life::Universe;
11+
812
wasm_bindgen_test_configure!(run_in_browser);
913

1014
#[wasm_bindgen_test]
1115
fn pass() {
1216
assert_eq!(1 + 1, 2);
1317
}
18+
19+
#[cfg(test)]
20+
pub fn input_spaceship() -> Universe {
21+
let mut universe = Universe::new();
22+
universe.set_width(6);
23+
universe.set_height(6);
24+
universe.set_cells(&[(1, 2), (2, 3), (3, 1), (3, 2), (3, 3)]);
25+
universe
26+
}
27+
28+
#[cfg(test)]
29+
pub fn expected_spaceship() -> Universe {
30+
let mut universe = Universe::new();
31+
universe.set_width(6);
32+
universe.set_height(6);
33+
universe.set_cells(&[(2, 1), (2, 3), (3, 2), (3, 3), (4, 2)]); // expected position after 1 tick
34+
universe
35+
}
36+
37+
#[wasm_bindgen_test]
38+
pub fn test_tick() {
39+
// Let's create a smaller Universe with a small spaceship to test!
40+
let mut input_universe = input_spaceship();
41+
// This is what our spaceship should look like
42+
let expected_universe = expected_spaceship();
43+
// after one tick in our universe.
44+
// Call `tick` and then see if the cells in the `Universe`s are the same.
45+
input_universe.tick();
46+
assert_eq!(&input_universe.get_cells(), &expected_universe.get_cells());
47+
}

05-game-of-life/www/index.js

+39-33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { memory } from 'game-of-life/game_of_life_bg';
1+
import { memory } from "game-of-life/game_of_life_bg";
22
import { Universe, Cell } from "game-of-life";
33

44
// const pre = document.getElementById("game-of-life-canvas");
@@ -7,7 +7,7 @@ import { Universe, Cell } from "game-of-life";
77
// const renderLoop = () => {
88
// pre.textContent = universe.render();
99
// universe.tick();
10-
10+
1111
// requestAnimationFrame(renderLoop);
1212
// };
1313

@@ -29,50 +29,56 @@ const canvas = document.getElementById("game-of-life-canvas");
2929
canvas.height = (CELL_SIZE + 1) * height + 1;
3030
canvas.width = (CELL_SIZE + 1) * width + 1;
3131

32-
const ctx = canvas.getContext('2d');
32+
const ctx = canvas.getContext("2d");
3333

3434
const renderLoop = () => {
35-
universe.tick();
36-
drawGrid();
37-
drawCells();
38-
requestAnimationFrame(renderLoop);
39-
}
35+
debugger;
36+
universe.tick();
37+
drawGrid();
38+
drawCells();
39+
requestAnimationFrame(renderLoop);
40+
};
4041

4142
const drawGrid = () => {
42-
ctx.beginPath();
43-
ctx.strokeStyle = GRID_COLOR;
43+
ctx.beginPath();
44+
ctx.strokeStyle = GRID_COLOR;
4445

45-
// Vertical lines
46-
for (let i = 0; i <= width; i++) {
46+
// Vertical lines
47+
for (let i = 0; i <= width; i++) {
4748
ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
4849
ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
49-
}
50+
}
5051

51-
// Horizontal lines
52-
for (let j = 0; j <= height; j++) {
53-
ctx.moveTo(0, j* (CELL_SIZE + 1) + 1);
54-
ctx.lineTo((CELL_SIZE + 1) * width + 1, j* (CELL_SIZE + 1) + 1);
55-
}
56-
}
52+
// Horizontal lines
53+
for (let j = 0; j <= height; j++) {
54+
ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
55+
ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
56+
}
57+
};
5758

5859
const getIndex = (row, column) => {
59-
return row * width + column;
60-
}
60+
return row * width + column;
61+
};
6162

6263
const drawCells = () => {
63-
const cellsPtr = universe.cells();
64-
const cells = new Uint8Array(memory.buffer, cellsPtr, width * height);
65-
ctx.beginPath();
66-
for (let row = 0; row < height; row ++) {
67-
for (let col = 0; col < width; col++) {
68-
const idx = getIndex(row, col);
69-
ctx.fillStyle = cells[idx] === Cell.Dead ? DEAD_COLOR : ALIVE_COLOR;
70-
ctx.fillRect(col * (CELL_SIZE + 1) + 1, row * (CELL_SIZE + 1) + 1, CELL_SIZE, CELL_SIZE);
71-
}
64+
const cellsPtr = universe.cells();
65+
const cells = new Uint8Array(memory.buffer, cellsPtr, width * height);
66+
ctx.beginPath();
67+
for (let row = 0; row < height; row++) {
68+
for (let col = 0; col < width; col++) {
69+
const idx = getIndex(row, col);
70+
ctx.fillStyle = cells[idx] === Cell.Dead ? DEAD_COLOR : ALIVE_COLOR;
71+
ctx.fillRect(
72+
col * (CELL_SIZE + 1) + 1,
73+
row * (CELL_SIZE + 1) + 1,
74+
CELL_SIZE,
75+
CELL_SIZE
76+
);
7277
}
73-
ctx.stroke();
74-
}
78+
}
79+
ctx.stroke();
80+
};
7581

7682
drawGrid();
7783
drawCells();
78-
requestAnimationFrame(renderLoop);
84+
requestAnimationFrame(renderLoop);

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,6 @@ A zero-player game to learn how to use Rust, WebAssembly, and JavaScript togethe
103103
- serving locally with webpack.
104104
- implementing the Game of Life with Rust.
105105
- rendering to canvas directly from memory with JavaScript.
106+
- testing the tick function and debugging.
106107

107108
Based on [The Rust and WebAssembly Book](https://rustwasm.github.io/docs/book/) by The Rust and WebAssembly Working Group (2021).

0 commit comments

Comments
 (0)