-
Notifications
You must be signed in to change notification settings - Fork 211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add examples of correct code at major points throughout the docs #284
Comments
I was also stuck at this same point for a while. Including code that finally worked as a workaround for now: src/lib.rs: mod utils;
use std::fmt;
use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
Dead = 0,
Alive = 1,
}
#[wasm_bindgen]
pub struct Universe {
width: u32,
height: u32,
cells: Vec<Cell>,
}
impl fmt::Display for Universe {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for line in self.cells.as_slice().chunks(self.width as usize) {
for &cell in line {
let symbol = if cell == Cell::Dead { '◻' } else { '◼' };
write!(f, "{}", symbol)?;
}
write!(f, "\n")?;
}
Ok(())
}
}
impl Universe {
fn get_index(&self, row: u32, column: u32) -> usize {
(row * self.width + column) as usize
}
fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
let mut count = 0;
for delta_row in [self.height - 1, 0, 1].iter().cloned() {
for delta_col in [self.width - 1, 0, 1].iter().cloned() {
if delta_row == 0 && delta_col == 0 {
continue;
}
let neighbor_row = (row + delta_row) % self.height;
let neighbor_col = (column + delta_col) % self.width;
let idx = self.get_index(neighbor_row, neighbor_col);
count += self.cells[idx] as u8;
}
}
count
}
}
/// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
pub fn new() -> Universe {
let width = 64;
let height = 64;
let cells = (0..width * height)
.map(|i| {
if i % 2 == 0 || i % 7 == 0 {
Cell::Alive
} else {
Cell::Dead
}
})
.collect();
Universe {
width,
height,
cells,
}
}
pub fn render(&self) -> String {
self.to_string()
}
pub fn tick(&mut self) {
let mut next = self.cells.clone();
for row in 0..self.height {
for col in 0..self.width {
let idx = self.get_index(row, col);
let cell = self.cells[idx];
let live_neighbors = self.live_neighbor_count(row, col);
let next_cell = match (cell, live_neighbors) {
// Rule 1: Any live cell with fewer than two live neighbours
// dies, as if caused by underpopulation.
(Cell::Alive, x) if x < 2 => Cell::Dead,
// Rule 2: Any live cell with two or three live neighbours
// lives on to the next generation.
(Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
// Rule 3: Any live cell with more than three live
// neighbours dies, as if by overpopulation.
(Cell::Alive, x) if x > 3 => Cell::Dead,
// Rule 4: Any dead cell with exactly three live neighbours
// becomes a live cell, as if by reproduction.
(Cell::Dead, 3) => Cell::Alive,
// All other cells remain in the same state.
(otherwise, _) => otherwise,
};
next[idx] = next_cell;
}
}
self.cells = next;
}
// ...
} www/index.html: <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
<style>
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<pre id="game-of-life-canvas"></pre>
<script src="./bootstrap.js"></script>
</body>
</html> www/index.js: import { Universe } from "wasm-game-of-life";
const pre = document.getElementById("game-of-life-canvas");
const universe = Universe.new();
const renderLoop = () => {
pre.textContent = universe.render();
universe.tick();
requestAnimationFrame(renderLoop);
};
requestAnimationFrame(renderLoop); |
You probably made the same mistake I did and missed the code under
I came up with this because I didn't like the code duplication and, since async-await exists, I replaced the recursion with looping to make it clearer, then I realized that the (async function renderLoop() {
let lastTime;
while (true) {
// await new Promise((res) => setTimeout(res, 1000 / 60));
let time = await new Promise(requestAnimationFrame);
if (lastTime && time - lastTime < 1000 / 59) {
continue;
}
lastTime = time;
drawCells();
universe.tick();
}
})(); |
Where in the docs did you come across this?
I could not get past section 4.4 > Rendering with JavaScript
Describe what about it does not make sense
My code runs fine (without warnings or errors) but nothing renders in the browser. I have checked it against the docs multiple times, but without a clear example of what the code should look like at this point, it's very difficult to debug what's going on.
Why does it not make sense?
There is not a complete picture of what the code should be at this point in the docs.
How could we improve it?
Add clear examples of what the code should look like at major points in the book.
This idea is mentioned in other issues, like #169 and #210, but I'm creating a new issue because I think it is worth calling out on its own. I also think having working examples after each major step would help folks (beginners especially) debug their own code. Perhaps this would help reduce confusion around the
#[wasm-bindgen]
macro, implementingDisplay
or other issues I've seen where the user would likely be able to debug their code if they had something to compare it to. So, I think this would not only be beneficial to users but could perhaps reduce the number of simple questions asked of others.For me, https://github.com/rustwasm/wasm_game_of_life is too far along to be helpful for debugging section 4.4 > Rendering with JavaScript. I can get the linked example to work just fine, but I still can't tell what's wrong with my current code.
To be clear, I'm not suggesting that the examples be put in the docs themselves - likely a link to a repo would be best.
The text was updated successfully, but these errors were encountered: