Showing
3 changed files
with
126 additions
and
8 deletions
1 | 1 | mod utils; |
2 | 2 | |
3 | +use std::fmt::{Display, Formatter, Result}; | |
3 | 4 | use wasm_bindgen::prelude::*; |
4 | 5 | |
5 | 6 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global |
... | ... | @@ -9,11 +10,105 @@ use wasm_bindgen::prelude::*; |
9 | 10 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; |
10 | 11 | |
11 | 12 | #[wasm_bindgen] |
12 | -extern { | |
13 | - fn alert(s: &str); | |
13 | +#[repr(u8)] | |
14 | +#[derive(Clone, Copy, Debug, PartialEq, Eq)] | |
15 | +pub enum Cell { | |
16 | + Dead = 0, | |
17 | + Alive = 1, | |
14 | 18 | } |
15 | 19 | |
16 | 20 | #[wasm_bindgen] |
17 | -pub fn greet(s :&str) { | |
18 | - alert(&format!("Hello, {}!", s)); | |
21 | +pub struct Universe { | |
22 | + width :u32, | |
23 | + height :u32, | |
24 | + cells :Vec<Cell>, | |
25 | +} | |
26 | + | |
27 | +#[wasm_bindgen] | |
28 | +impl Universe { | |
29 | + pub fn new() -> Universe { | |
30 | + let width = 64; | |
31 | + let height = 64; | |
32 | + | |
33 | + let init_cells = |i :u32| { | |
34 | + if i % 2 == 0 || i % 7 == 0 { Cell::Alive } else { Cell::Dead } | |
35 | + }; | |
36 | + | |
37 | + let cells = (0..width * height).map(init_cells).collect(); | |
38 | + | |
39 | + Universe { | |
40 | + width: width, | |
41 | + height: height, | |
42 | + cells: cells, | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + pub fn render(&self) -> String { | |
47 | + self.to_string() | |
48 | + } | |
49 | + | |
50 | + pub fn tick(&mut self) { | |
51 | + let mut next = self.cells.clone(); | |
52 | + | |
53 | + for row in 0..self.height { | |
54 | + for col in 0..self.width { | |
55 | + let idx = self.get_index(row, col); | |
56 | + let cell = self.cells[idx]; | |
57 | + let live_neighbors = self.live_neighbor_count(row, col); | |
58 | + | |
59 | + // Game of life rules.... | |
60 | + let next_cell = match (cell, live_neighbors) { | |
61 | + (Cell::Alive, 2) | | |
62 | + (Cell::Alive, 3) => Cell::Alive, | |
63 | + (Cell::Alive, _) => Cell::Dead, | |
64 | + ( Cell::Dead, 3) => Cell::Alive, | |
65 | + ( otherwise, _) => otherwise, | |
66 | + }; | |
67 | + | |
68 | + next[idx] = next_cell; | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + self.cells = next; | |
73 | + } | |
74 | + | |
75 | + fn get_index(&self, row :u32, col :u32) -> usize { | |
76 | + (row * self.width + col) as usize | |
77 | + } | |
78 | + | |
79 | + fn live_neighbor_count(&self, row :u32, col :u32) -> u8 { | |
80 | + let mut count = 0; | |
81 | + | |
82 | + for delta_row in [self.height - 1, 0, 1].iter().cloned() { | |
83 | + for delta_col in [self.width - 1, 0, 1].iter().cloned() { | |
84 | + if delta_row == 0 && delta_col == 0 { | |
85 | + continue; | |
86 | + } | |
87 | + | |
88 | + let neighbor_row = (row + delta_row) % self.height; | |
89 | + let neighbor_col = (col + delta_col) % self.width; | |
90 | + let idx = self.get_index(neighbor_row, neighbor_col); | |
91 | + count += self.cells[idx] as u8; | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + count | |
96 | + } | |
97 | +} | |
98 | + | |
99 | +impl Display for Universe { | |
100 | + fn fmt(&self, f :&mut Formatter) -> Result { | |
101 | + for line in self.cells.as_slice().chunks(self.width as usize) { | |
102 | + for &cell in line { | |
103 | + let symbol = match cell { | |
104 | + Cell::Dead => ' ', | |
105 | + Cell::Alive => '*', | |
106 | + }; | |
107 | + write!(f, "{}", symbol)?; | |
108 | + } | |
109 | + write!(f, "\n")?; | |
110 | + } | |
111 | + | |
112 | + Ok(()) | |
113 | + } | |
19 | 114 | } |
... | ... |
... | ... | @@ -2,10 +2,23 @@ |
2 | 2 | <html> |
3 | 3 | <head> |
4 | 4 | <meta charset="utf-8"> |
5 | - <title>Hello wasm-pack!</title> | |
5 | + <title>wasm-game-of-life!</title> | |
6 | + <style> | |
7 | + body { | |
8 | + position: absolute; | |
9 | + top: 0; | |
10 | + left: 0; | |
11 | + width: 100%; | |
12 | + height: 100%; | |
13 | + display: flex; | |
14 | + flex-direction: column; | |
15 | + align-items: center; | |
16 | + justify-content: center; | |
17 | + } | |
18 | + </style> | |
6 | 19 | </head> |
7 | 20 | <body> |
8 | - <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> | |
21 | + <pre id="game-of-life-canvas"></pre> | |
9 | 22 | <script src="./bootstrap.js"></script> |
10 | 23 | </body> |
11 | 24 | </html> |
... | ... |
1 | -import * as wasm from "wasm-game-of-life"; | |
1 | +import { Universe } from "wasm-game-of-life"; | |
2 | 2 | |
3 | -wasm.greet("It's all a game"); | |
3 | +const pre = document.getElementById("game-of-life-canvas"); | |
4 | +const universe = Universe.new(); | |
5 | + | |
6 | +const renderLoop = () => { | |
7 | + pre.textContent = universe.render(); | |
8 | + universe.tick(); | |
9 | + | |
10 | + requestAnimationFrame(renderLoop); | |
11 | +}; | |
12 | + | |
13 | +requestAnimationFrame(renderLoop); | |
... | ... |
Please
register
or
login
to post a comment