IT评测·应用市场-qidao123.com

标题: Rust + WebAssembly 实现康威生命游戏 [打印本页]

作者: 汕尾海湾    时间: 2025-3-18 11:41
标题: Rust + WebAssembly 实现康威生命游戏
1. 设计思绪

1.1 选择有限的世界

康威生命游戏的世界是 无穷二维网格,但由于 盘算机内存有限,我们可以选择三种有限宇宙方案:
环绕宇宙(Toroidal Universe)答应 滑翔机(Gliders) 无穷运行,不会被边界限定:

2. Rust 代码实现

2.1 定义 Cell 结构

  1. #[wasm_bindgen]
  2. #[repr(u8)]
  3. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  4. pub enum Cell {
  5.     Dead = 0,
  6.     Alive = 1,
  7. }
复制代码
说明

2.2 定义 Universe

  1. #[wasm_bindgen]
  2. pub struct Universe {
  3.     width: u32,
  4.     height: u32,
  5.     cells: Vec<Cell>,
  6. }
复制代码
说明

2.3 盘算网格索引

  1. impl Universe {
  2.     fn get_index(&self, row: u32, column: u32) -> usize {
  3.         (row * self.width + column) as usize
  4.     }
  5. }
复制代码

2.4 盘算活邻居数量

  1. impl Universe {
  2.     fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
  3.         let mut count = 0;
  4.         for delta_row in [self.height - 1, 0, 1].iter().cloned() {
  5.             for delta_col in [self.width - 1, 0, 1].iter().cloned() {
  6.                 if delta_row == 0 && delta_col == 0 {
  7.                     continue;
  8.                 }
  9.                 let neighbor_row = (row + delta_row) % self.height;
  10.                 let neighbor_col = (column + delta_col) % self.width;
  11.                 let idx = self.get_index(neighbor_row, neighbor_col);
  12.                 count += self.cells[idx] as u8;
  13.             }
  14.         }
  15.         count
  16.     }
  17. }
复制代码
说明

2.5 更新下一代状态

  1. #[wasm_bindgen]
  2. impl Universe {
  3.     pub fn tick(&mut self) {
  4.         let mut next = self.cells.clone();
  5.         for row in 0..self.height {
  6.             for col in 0..self.width {
  7.                 let idx = self.get_index(row, col);
  8.                 let cell = self.cells[idx];
  9.                 let live_neighbors = self.live_neighbor_count(row, col);
  10.                 let next_cell = match (cell, live_neighbors) {
  11.                     (Cell::Alive, x) if x < 2 => Cell::Dead,
  12.                     (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
  13.                     (Cell::Alive, x) if x > 3 => Cell::Dead,
  14.                     (Cell::Dead, 3) => Cell::Alive,
  15.                     (otherwise, _) => otherwise,
  16.                 };
  17.                 next[idx] = next_cell;
  18.             }
  19.         }
  20.         self.cells = next;
  21.     }
  22. }
复制代码
说明

2.6 初始化宇宙

  1. #[wasm_bindgen]
  2. impl Universe {
  3.     pub fn new() -> Universe {
  4.         let width = 64;
  5.         let height = 64;
  6.         let cells = (0..width * height)
  7.             .map(|i| if i % 2 == 0 || i % 7 == 0 { Cell::Alive } else { Cell::Dead })
  8.             .collect();
  9.         Universe {
  10.             width,
  11.             height,
  12.             cells,
  13.         }
  14.     }
  15.     pub fn render(&self) -> String {
  16.         self.to_string()
  17.     }
  18. }
复制代码

3. JavaScript 前端

在 wasm-game-of-life/www/index.js 编写 Canvas 渲染 代码。
3.1 JavaScript 初始化

  1. import { Universe, Cell, memory } from "wasm-game-of-life";
  2. const CELL_SIZE = 5;
  3. const GRID_COLOR = "#CCCCCC";
  4. const DEAD_COLOR = "#FFFFFF";
  5. const ALIVE_COLOR = "#000000";
  6. const universe = Universe.new();
  7. const width = universe.width();
  8. const height = universe.height();
复制代码
3.2 绘制网格

  1. const drawGrid = () => {
  2.   ctx.beginPath();
  3.   ctx.strokeStyle = GRID_COLOR;
  4.   for (let i = 0; i <= width; i++) {
  5.     ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
  6.     ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
  7.   }
  8.   for (let j = 0; j <= height; j++) {
  9.     ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
  10.     ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
  11.   }
  12.   ctx.stroke();
  13. };
复制代码
3.3 读取 WebAssembly 内存

  1. const drawCells = () => {
  2.   const cellsPtr = universe.cells();
  3.   const cells = new Uint8Array(memory.buffer, cellsPtr, width * height);
  4.   ctx.beginPath();
  5.   for (let row = 0; row < height; row++) {
  6.     for (let col = 0; col < width; col++) {
  7.       const idx = row * width + col;
  8.       ctx.fillStyle = cells[idx] === Cell.Dead ? DEAD_COLOR : ALIVE_COLOR;
  9.       ctx.fillRect(col * (CELL_SIZE + 1) + 1, row * (CELL_SIZE + 1) + 1, CELL_SIZE, CELL_SIZE);
  10.     }
  11.   }
  12.   ctx.stroke();
  13. };
复制代码
3.4 动画渲染

  1. const renderLoop = () => {
  2.   universe.tick();
  3.   drawGrid();
  4.   drawCells();
  5.   requestAnimationFrame(renderLoop);
  6. };
  7. drawGrid();
  8. drawCells();
  9. requestAnimationFrame(renderLoop);
复制代码
4.运行项目

  1. wasm-pack build
  2. cd www
  3. npm install
  4. npm run start
复制代码
打开 http://localhost:8080/,你会看到 动态演化的生命游戏!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4