如何便捷转换二维数组为二维向量?优化Rust-Wasm生命游戏代码
优化Rust-WASM生命游戏中形状转坐标索引的易用性
嘿,很高兴看到你在折腾Rust-WASM版的生命游戏!把二维0/1形状数组转成Universe的坐标索引这个需求,确实是添加自定义“飞船”的关键一步。我来给你几个实用的优化思路,让这个过程更顺手、更灵活~
先假设你现有的代码大概是这样的(毕竟你提到已经能运行了):
const WIDTH: u32 = 64; const HEIGHT: u32 = 64; /// glider: [[0, 1, 0], [0, 0, 1], [1, 1, 1]] fn make_ship(shape: &[&[u8]]) -> Vec<u32> { let mut indices = Vec::new(); for (y, row) in shape.iter().enumerate() { for (x, &cell) in row.iter().enumerate() { if cell == 1 { let idx = (y as u32) * WIDTH + (x as u32); indices.push(idx); } } } indices }
下面是几个提升易用性的方向:
1. 让形状可以放在任意位置(添加起始坐标参数)
默认从左上角(0,0)放形状太局限了,给函数加个起始坐标参数,再加上边界检查避免越界,实用性瞬间拉满:
fn make_ship(shape: &[&[u8]], start_x: u32, start_y: u32) -> Vec<u32> { let mut indices = Vec::new(); for (y_offset, row) in shape.iter().enumerate() { let y = start_y + y_offset as u32; if y >= HEIGHT { break; // 超出宇宙高度,停止处理后续行 } for (x_offset, &cell) in row.iter().enumerate() { let x = start_x + x_offset as u32; if x >= WIDTH { break; // 超出当前行宽度,停止处理后续列 } if cell == 1 { let idx = y * WIDTH + x; indices.push(idx); } } } indices }
调用的时候直接指定位置就行:make_ship(&glider, 15, 20),把滑翔机放在宇宙的(15,20)位置。
2. 用宏简化形状定义
每次写&[&[0,1,0], &[0,0,1], &[1,1,1]]这种嵌套引用太繁琐,写个小宏让形状定义更清爽:
macro_rules! shape { ($($row:expr),*) => { &[$(&$row),*] }; }
之后定义滑翔机就可以写成:
let glider = shape![ [0, 1, 0], [0, 0, 1], [1, 1, 1] ];
不用再给每个子数组加&,看起来舒服多了。
3. 封装成Universe的方法(更贴合业务逻辑)
如果你的Universe是一个结构体,直接给它加个add_shape方法,省去手动处理索引再更新细胞的步骤:
struct Universe { width: u32, height: u32, cells: Vec<u8>, } impl Universe { fn add_shape(&mut self, shape: &[&[u8]], start_x: u32, start_y: u32) { for (y_offset, row) in shape.iter().enumerate() { let y = start_y + y_offset as u32; if y >= self.height { break; } for (x_offset, &cell) in row.iter().enumerate() { let x = start_x + x_offset as u32; if x >= self.width { break; } if cell == 1 { let idx = (y * self.width + x) as usize; self.cells[idx] = 1; } } } } }
调用时直接universe.add_shape(glider, 5, 5),一步到位把形状加到宇宙里,逻辑更连贯。
4. 加类型别名和文档注释(提升可读性)
给形状类型起个别名,再加上详细的文档注释,不管是自己维护还是别人看代码都更清晰:
/// 生命游戏中的自定义形状:二维u8数组,1代表存活细胞,0代表死亡细胞 type Shape = &[&[u8]]; /// 将自定义形状转换为Universe中的细胞索引向量 /// /// # 参数 /// * `shape` - 要转换的自定义形状 /// * `start_x` - 形状左上角的起始X坐标 /// * `start_y` - 形状左上角的起始Y坐标 /// /// # 返回值 /// 形状中所有存活细胞在Universe中的索引集合 fn shape_to_indices(shape: Shape, start_x: u32, start_y: u32) -> Vec<u32> { // 实现代码... }
这些优化点可以根据你的实际需求组合使用,之后添加新的“飞船”形状会轻松很多~
内容的提问来源于stack exchange,提问作者DjebbZ
相关产品推荐
相关产品推荐

