diff options
author | Joris | 2020-01-28 09:55:58 +0100 |
---|---|---|
committer | Joris | 2020-01-29 10:12:31 +0100 |
commit | 1b6a7e0d00703e3da2e1620b5a2b2cba027161de (patch) | |
tree | 5143f784e1529d3b6c04116c84f09c426bb257b0 | |
parent | 197b6fa7aa810147d63209408c3a378ec552d0f4 (diff) |
Implement game of life
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | .gitlab-ci.yml | 10 | ||||
-rw-r--r-- | Cargo.lock | 235 | ||||
-rw-r--r-- | Cargo.toml | 27 | ||||
-rw-r--r-- | LICENSE | 0 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rwxr-xr-x | deploy | 16 | ||||
l--------- | public/game_of_life.js | 1 | ||||
l--------- | public/game_of_life_bg.wasm | 1 | ||||
-rw-r--r-- | public/index.html | 28 | ||||
-rw-r--r-- | shell.nix | 17 | ||||
-rw-r--r-- | src/canvas.rs | 64 | ||||
-rw-r--r-- | src/console.rs | 5 | ||||
-rw-r--r-- | src/game.rs | 31 | ||||
-rw-r--r-- | src/game_loop.rs | 31 | ||||
-rw-r--r-- | src/lib.rs | 26 | ||||
-rw-r--r-- | src/state.rs | 72 | ||||
-rwxr-xr-x | watch | 13 |
18 files changed, 603 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34aa146 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target/ +pkg/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..a872f80 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,10 @@ +image: alpine:latest +pages: + stage: deploy + script: + - echo 'Nothing to do...' + artifacts: + paths: + - public + only: + - pages diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1c06bd8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,235 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "anyhow" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bumpalo" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "game_of_life" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "js-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "web-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "weedle" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +"checksum bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7889c7c36282151f6bf465be4700359318aef36baa951462382eae49e9577cf9" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c" +"checksum wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "11cdb95816290b525b32587d76419facd99662a07e59d3cdb560488a819d9a45" +"checksum wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" +"checksum wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" +"checksum wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" +"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d" +"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b" +"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..aa18d6f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "game_of_life" +version = "0.1.0" +authors = ["Joris"] +edition = "2018" +description = '' +repository = '' +license = 'LICENSE' + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-bindgen = "0.2.58" +js-sys = "0.3.35" +console_error_panic_hook = "0.1.6" + +[dependencies.web-sys] +version = "0.3.35" +features = [ + 'CanvasRenderingContext2d', + 'Document', + 'Element', + 'HtmlCanvasElement', + 'Window', + 'console', +] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e9517c3 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Game of life + +The code is written in Rust and is compiled to WebAssembly. +[wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) is used to interact +with JavaScript. + +See [the wikipedia page](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) +to get more information about game of life. + +## Live + +[https://guyonvarch.gitlab.io/game-of-life](https://guyonvarch.gitlab.io/game-of-life) + +## Getting started + +```bash +nix-shell --run ./watch +``` + +## Deploy + +```bash +nix-shell --run ./deploy +``` @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -e +git branch -D pages +git checkout -b pages +rm -f public/game_of_life.js +rm -f public/game_of_life_bg.wasm +rm -f public/game_of_life_bg.wasm.gz +wasm-pack build --release --target web +mv pkg/game_of_life.js public +wasm-opt -O -o public/game_of_life_bg.wasm pkg/game_of_life_bg.wasm +gzip -9 --keep public/game_of_life_bg.wasm +git add . +git commit -m "Deploy pages" +git push --force origin pages +git checkout master +git branch -D pages diff --git a/public/game_of_life.js b/public/game_of_life.js new file mode 120000 index 0000000..998a5ea --- /dev/null +++ b/public/game_of_life.js @@ -0,0 +1 @@ +../pkg/game_of_life.js
\ No newline at end of file diff --git a/public/game_of_life_bg.wasm b/public/game_of_life_bg.wasm new file mode 120000 index 0000000..fe3f9b8 --- /dev/null +++ b/public/game_of_life_bg.wasm @@ -0,0 +1 @@ +../pkg/game_of_life_bg.wasm
\ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..ed2639f --- /dev/null +++ b/public/index.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/> + <style> + body { + margin: 0; + width: 100%; + height: 100%; + background-color: #333333; + display: flex; + align-items: center; + justify-content: center; + } + </style> + </head> + <body> + <canvas id="canvas" height="800" width="800" /> + <script type="module"> + import init from './game_of_life.js'; + + async function run() { + await init(); + } + + run(); + </script> + </body> +</html> diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..45261c8 --- /dev/null +++ b/shell.nix @@ -0,0 +1,17 @@ +with import <nixpkgs> {}; + +let unstable = import ( + fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz + ) {}; +in + +mkShell { + buildInputs = [ + entr + gzip + python3 + rustup + unstable.binaryen + wasm-pack + ]; +} diff --git a/src/canvas.rs b/src/canvas.rs new file mode 100644 index 0000000..38aef4d --- /dev/null +++ b/src/canvas.rs @@ -0,0 +1,64 @@ +use wasm_bindgen::prelude::JsValue; +use wasm_bindgen::JsCast; +use web_sys::CanvasRenderingContext2d; + +pub struct Canvas { + context: CanvasRenderingContext2d, + width: u32, + height: u32, + scaled_width: u32, + scaled_height: u32, +} + +impl Canvas { + pub fn new(attr_id: &str, width: u32, height: u32) -> Canvas { + let document = web_sys::window().unwrap().document().unwrap(); + let canvas = document.get_element_by_id(attr_id).unwrap(); + let canvas: web_sys::HtmlCanvasElement = canvas + .dyn_into::<web_sys::HtmlCanvasElement>() + .unwrap(); + + let context = canvas + .get_context("2d") + .unwrap() + .unwrap() + .dyn_into::<web_sys::CanvasRenderingContext2d>() + .unwrap(); + + let scaled_width = canvas.width() / width; + let scaled_height = canvas.height() / height; + + Canvas { + context, + width, + height, + scaled_width, + scaled_height, + } + } + + pub fn clear(&self) { + self.context.set_fill_style(&JsValue::from_str("white")); + + self.context.fill_rect( + f64::from(0), + f64::from(0), + f64::from(self.width * self.scaled_width), + f64::from(self.height * self.scaled_height) + ); + } + + pub fn draw(&self, x: u32, y: u32, color: &str) { + assert!(x < self.width); + assert!(y < self.height); + + self.context.set_fill_style(&JsValue::from_str(color)); + + self.context.fill_rect( + f64::from(x * self.scaled_width), + f64::from(y * self.scaled_height), + f64::from(self.scaled_width), + f64::from(self.scaled_height) + ); + } +} diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..4efbd80 --- /dev/null +++ b/src/console.rs @@ -0,0 +1,5 @@ +use wasm_bindgen::prelude::JsValue; + +pub fn log(str: &str) { + web_sys::console::log_1(&JsValue::from_str(str)); +} diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..4b527d2 --- /dev/null +++ b/src/game.rs @@ -0,0 +1,31 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use crate::canvas::Canvas; +use crate::state::State; + +pub struct Game { + canvas: Canvas, + state: Rc<RefCell<State>>, +} + +impl Game { + pub fn new(canvas_id: &str, width: u32, height: u32) -> Game { + let canvas = Canvas::new(canvas_id, width, height); + let state = Rc::new(RefCell::new(State::new(width, height))); + + Game { + canvas, + state, + } + } + + pub fn update(&self) { + let next_state = self.state.borrow().next(); + *self.state.borrow_mut() = next_state; + } + + pub fn render(&self) { + self.state.borrow().draw(&self.canvas); + } +} diff --git a/src/game_loop.rs b/src/game_loop.rs new file mode 100644 index 0000000..34dd477 --- /dev/null +++ b/src/game_loop.rs @@ -0,0 +1,31 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use wasm_bindgen::prelude::Closure; +use wasm_bindgen::JsCast; + +use crate::game::Game; + +pub fn run(game: Game, update_period: i32) { + game.render(); + + let f = Rc::new(RefCell::new(None)); + let g = f.clone(); + + *g.borrow_mut() = Some(Closure::wrap(Box::new(move |_| { + + game.update(); + game.render(); + + set_timeout(f.borrow().as_ref().unwrap(), update_period); + + }) as Box<dyn FnMut(i32)>)); + + set_timeout(g.borrow().as_ref().unwrap(), update_period); +} + +fn set_timeout(f: &Closure<dyn FnMut(i32)>, timeout: i32) { + web_sys::window().unwrap() + .set_timeout_with_callback_and_timeout_and_arguments_0(f.as_ref().unchecked_ref(), timeout) + .unwrap(); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f7fa24c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,26 @@ +use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; + +mod canvas; +mod state; +mod game; +mod game_loop; + +use game::Game; + +#[wasm_bindgen(start)] +pub fn main() -> Result<(), JsValue> { + set_panic_hook(); + game_loop::run(Game::new("canvas", 100, 100), 100); + Ok(()) +} + +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..5d13902 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,72 @@ +use crate::canvas::Canvas; + +#[derive(Debug, Clone)] +pub struct State { + width: u32, + height: u32, + cells: Vec::<bool>, +} + +impl State { + pub fn new(width: u32, height: u32) -> State { + let cells = (0..width * height) + .map(|_| js_sys::Math::random() < 0.5) + .collect(); + + State { + width, + height, + cells, + } + } + + pub fn neighbor_count(&self, x: u32, y: u32) -> u32 { + let mut count = 0; + for delta_x in [self.height - 1, 0, 1].iter().clone() { + for delta_y in [self.width - 1, 0, 1].iter().clone() { + let neighbor_x = (x + delta_x) % self.width; + let neighbor_y = (y + delta_y) % self.height; + + if (*delta_x, *delta_y) != (0, 0) && self.is_on(neighbor_x, neighbor_y) { + count += 1; + } + } + } + count + } + + pub fn next(&self) -> State { + let cells = (0..self.width * self.height) + .map(|i| { + let x = i % self.width; + let y = i / self.width; + let neighbor_count = self.neighbor_count(x, y); + neighbor_count == 3 || self.is_on(x, y) && neighbor_count == 2 + }) + .collect(); + + State { + width: self.width, + height: self.height, + cells, + } + } + + fn is_on(&self, x: u32, y: u32) -> bool { + let inside_x = (x + self.width) % self.width; + let inside_y = (y + self.height) % self.height; + self.cells[(inside_x + inside_y * self.width) as usize] + } + + pub fn draw(&self, canvas: &Canvas) { + canvas.clear(); + + for y in 0..self.height { + for x in 0..self.width { + if self.is_on(x, y) { + canvas.draw(x, y, "green"); + } + } + } + } +} @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +python -m http.server --directory public 8000 & + +trap "fuser -k 8000/tcp" EXIT + +CMD="clear && wasm-pack build --target web" + +while true; do + + find src | entr -d -s "$CMD" + +done |