随机生成城堡序列号

我们在之前的课程中已经学习了整数和运算。现在,让我们应用这些知识来生成城堡的序列号。

正如在课程开始时讨论的那样,城堡序列号对城堡的视觉呈现和游戏数据有重大影响。它是关键的,并且在建造城堡时随机分配。

sources 文件夹中创建一个新的模块 move_castle::utils。在这个模块中,包含一个名为 generate_castle_serial_number 的函数。

// sources/utils.move

module move_castle::utils {

    public(package) fun generate_castle_serial_number(size: u64, id: &UID): u64 {
    
    }
}

让我们重新审视序列号的设计:

Logo

第一个数字是“size”,它是用户输入的参数,我们需要生成一个5位整数。所选算法包括从城堡的 UID 哈希值中获取一个5位整数值(使用取模操作)。

// 对城堡的 UID 进行哈希。
let hash = hash::sha2_256(object::uid_to_bytes(id));

生成的哈希是一个长度为32的 vector<u8>,将其转换为 u64 整数:

let result_num: u64 = 0;
// 将哈希向量转换为 u64。
while (vector::length(&hash) > 0) {
    let element = vector::remove(&mut hash, 0);
    result_num = ((result_num << 8) | (element as u64));
};

执行取模操作以仅保留整数的最后5位数字:

// 保留最后5位数字。
result_num = result_num % 100000u64;

最后,将“size”数字连接并返回完整的序列号。整个函数应如下所示:

/// 生成城堡的序列号。
public(package) fun generate_castle_serial_number(size: u64, id: &UID): u64 {
    // 对城堡的 UID 进行哈希。
    //let mut hash = hash::sha2_256(object::uid_to_bytes(id));
    //原教程使用hash::sha2_256但以淘汰,更新至keccak256
    let mut hash = hash::keccak256(&object::uid_to_bytes(id));

    let mut result_num: u64 = 0;
    // 将哈希向量转换为 u64。
    while (vector::length(&hash) > 0) {
        let element = vector::remove(&mut hash, 0);
        result_num = ((result_num << 8) | (element as u64));
    };

    // 保留最后5位数字。
    result_num = result_num % 100000u64;

    // 连接 size 数字。
    size * 100000u64 + result_num
}

添加一些测试并运行它:

// utils_tests.move

#[test_only]
module move_castle::utils_tests {
    use sui::test_scenario::Self;
    use move_castle::utils;
    use std::debug::print;

    #[test]
    fun serial_number_test() {
        let sender = @0xABC;

        let scenario_val = test_scenario::begin(sender);
        let scenario = &mut scenario_val;
        {
            let ctx = test_scenario::ctx(scenario);
            let uid = object::new(ctx);
            let result = utils::generate_castle_serial_number(0, &mut uid);
            print(&result);
            assert!(result >= 0, 0);
            assert!(result < 100000, 0);
            object::delete(uid);
        };

        test_scenario::end(scenario_val);
    }
}