You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何便捷转换二维数组为二维向量?优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:47:01