<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
之前學了幾遍,後來忘記了,通過製作該遊戲再複習複習。
cargo install cargo-generate
初始rust專案
使用wasm的專案模板:
cargo generate --git https://github.com/rustwasm/wasm-pack-template
mod utils; 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] extern { fn alert(s: &str); } #[wasm_bindgen] pub fn greet() { alert("Hello, wasm-game-of-life!"); }
npm init wasm-app www
{ "name": "create-wasm-app", "version": "0.1.0", "description": "create an app to consume rust-generated wasm packages", "main": "index.js", "bin": { "create-wasm-app": ".bin/create-wasm-app.js" }, "scripts": { "build": "webpack --config webpack.config.js", "start": "webpack-dev-server" },
import * as wasm from "hello-wasm-pack"; wasm.greet();
wasm-pack build
生成)"wasm-game-of-life": "file:../pkg"
import * as wasm from "wasm-game-of-life"; wasm.greet();
index(row, column, universe) = row * width(universe) + column
首先我們需要定義每個單元格:
#[wasm_bindgen] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Cell { Dead = 0, Alive = 1, }
列舉型別,0是死亡,1是存活,#[repr(u8)]
表示一個單元格1位元組。複習下:
長度 | 有符號 | 無符號 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
接下來定義宇宙:
#[wasm_bindgen] pub struct Universe { width: u32, height: u32, cells: Vec<Cell>, }
#[wasm_bindgen] 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; println!("{},{}-s-", neighbor_row, neighbor_col); let idx = self.get_index(neighbor_row, neighbor_col); count += self.cells[idx] as u8; } } count }
1,1
1,2
1,3
2,1
2,3
3,1
3,2
3,3
63,63
63,0-
63,1
0,63
0,1
1,63
1,0
1,1
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; }
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(()) } }
最後進行暴露初始化和渲染方法:
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() }
<pre id="game-of-life-canvas"></pre>
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); }; renderLoop();
pub fn width(&self) -> u32 { self.width } pub fn height(&self) -> u32 { self.height } pub fn cells(&self) -> *const Cell { self.cells.as_ptr() }
<canvas id="game-of-life-canvas"></canvas>
修改js:
import { Universe, Cell } from "wasm-game-of-life"; import { memory } from "wasm-game-of-life/wasm_game_of_life_bg"; const CELL_SIZE = 5; // px const GRID_COLOR = "#CCCCCC"; const DEAD_COLOR = "#FFFFFF"; const ALIVE_COLOR = "#000000"; const universe = Universe.new(); const width = universe.width(); const height = universe.height(); // Give the canvas room for all of our cells and a 1px border // around each of them. const canvas = document.getElementById("game-of-life-canvas"); canvas.height = (CELL_SIZE + 1) * height + 1; canvas.width = (CELL_SIZE + 1) * width + 1; const ctx = canvas.getContext("2d"); const drawGrid = () => { ctx.beginPath(); ctx.strokeStyle = GRID_COLOR; // Vertical lines. for (let i = 0; i <= width; i++) { ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0); ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1); } // Horizontal lines. for (let j = 0; j <= height; j++) { ctx.moveTo(0, j * (CELL_SIZE + 1) + 1); ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1); } ctx.stroke(); }; const getIndex = (row, column) => { return row * width + column; }; const drawCells = () => { const cellsPtr = universe.cells(); const cells = new Uint8Array(memory.buffer, cellsPtr, width * height); ctx.beginPath(); for (let row = 0; row < height; row++) { for (let col = 0; col < width; col++) { const idx = getIndex(row, col); ctx.fillStyle = cells[idx] === Cell.Dead ? DEAD_COLOR : ALIVE_COLOR; ctx.fillRect( col * (CELL_SIZE + 1) + 1, row * (CELL_SIZE + 1) + 1, CELL_SIZE, CELL_SIZE ); } } ctx.stroke(); }; const renderLoop = () => { universe.tick(); drawGrid(); drawCells(); requestAnimationFrame(renderLoop); }; renderLoop();
即可看見效果:
impl Universe { /// Get the dead and alive values of the entire universe. pub fn get_cells(&self) -> &[Cell] { &self.cells } /// Set cells to be alive in a universe by passing the row and column /// of each cell as an array. pub fn set_cells(&mut self, cells: &[(u32, u32)]) { for (row, col) in cells.iter().cloned() { let idx = self.get_index(row, col); self.cells[idx] = Cell::Alive; } } }
新增重置的方法:
/// Set the width of the universe. /// /// Resets all cells to the dead state. pub fn set_width(&mut self, width: u32) { self.width = width; self.cells = (0..width * self.height).map(|_i| Cell::Dead).collect(); } /// Set the height of the universe. /// /// Resets all cells to the dead state. pub fn set_height(&mut self, height: u32) { self.height = height; self.cells = (0..self.width * height).map(|_i| Cell::Dead).collect(); }
#![cfg(target_arch = "wasm32")] extern crate wasm_bindgen_test; use std::assert_eq; use wasm_bindgen_test::*; extern crate wasm_game_of_life; use wasm_game_of_life::Universe; wasm_bindgen_test_configure!(run_in_browser); #[cfg(test)] pub fn input_spaceship() -> Universe { let mut universe = Universe::new(); universe.set_width(6); universe.set_height(6); universe.set_cells(&[(1, 2), (2, 3), (3, 1), (3, 2), (3, 3)]); universe } #[cfg(test)] pub fn expected_spaceship() -> Universe { let mut universe = Universe::new(); universe.set_width(6); universe.set_height(6); universe.set_cells(&[(2, 1), (2, 3), (3, 2), (3, 3), (4, 2)]); universe } #[wasm_bindgen_test] pub fn test_tick() { // Let's create a smaller Universe with a small spaceship to test! let mut input_universe = input_spaceship(); // This is what our spaceship should look like // after one tick in our universe. let expected_universe = expected_spaceship(); // Call `tick` and then see if the cells in the `Universe`s are the same. input_universe.tick(); assert_eq!(&input_universe.get_cells(), &expected_universe.get_cells()); }
wasm-pack test --firefox --headless
即可執行測試結果。如果安裝瀏覽器失敗,可以使用谷歌,或者去掉無頭屬性,直接網頁上看測試結果。[dependencies.web-sys] version = "0.3" features = [ "console", ]
extern crate web_sys; // A macro to provide `println!(..)`-style syntax for `console.log` logging. macro_rules! log { ( $( $t:tt )* ) => { web_sys::console::log_1(&format!( $( $t )* ).into()); } }
format宏與其他幾個輸出區別在於其使用write,不輸出到標準輸出中:
format!: write formatted text to String print!: same as format! but the text is printed to the console (io::stdout). println!: same as print! but a newline is appended. eprint!: same as format! but the text is printed to the standard error (io::stderr). eprintln!: same as eprint!but a newline is appended.
然後就可以在需要的地方console了,比如neighbours那:
let live_neighbors = self.live_neighbor_count(row, col); log!( "cell[{}, {}] is initially {:?} and has {} live neighbors", row, col, cell, live_neighbors ); 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, }; log!(" it becomes {:?}", next_cell); next[idx] = next_cell;
開啟web,即可看見console的內容。
到此這篇關於使用Rust製作康威生命遊戲的文章就介紹到這了,更多相關Rust康威生命遊戲內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45