一:猜数设计
让我们来设计一个简单的猜数程序,用户猜测一个数字并传入函数,判断与程序随机而成的数字是否相同,如果相同就给予一定奖励。
这里的奖励可以是链上流通的货币或是其它有价值的虚拟物品,不过作为一篇适合 S u i M o v e \mathit {Sui\ Move} Sui Move 初学者的简单用例,直接牵扯到高昂物品似乎有所不妥,所以这里的奖励就用一个整型的 p r i z e \mathit {prize} prize 来表示,将含有奖金的 o b j e c t \mathit {object} object 发送给猜中数字的玩家,以此来作为激励手段。
同时,我们还可以用 E v e n t s \mathit {Events} Events 来记录链上发生的重大事件。在这个例子里,重大事件无疑就是 W i n n e r \mathit {Winner} Winner 了,我们可以用事件来记录胜者玩家的地址,为了让数据有一定的分析价值,还可以记录到这一次猜中数之前的所有玩家的尝试总数。
那么,根据分析,我们可以用三个 s t r u c t \mathit {struct} struct 来存储这些信息。
struct Count has key {
id: UID,
total: u64,
}
struct Prize has key {
id: UID,
prize: u8,
}
struct GuessEvent has copy, drop {
total_count: u64,
final_winner: address,
}
- C o u n t \mathit {Count} Count 会作为一个共享对象,让所有玩家都可以访问并修改,其中的 t o t a l \mathit {total} total 将存储一共的尝试猜数的次数,直到猜中时清零重置。
- P r i z e \mathit {Prize} Prize 直到被猜中数时才会被创建,同时被发送给此次交易的发起者,也就是猜中数字的玩家,其中的 p r i z e \mathit {prize} prize 可以简单设定为猜中的数等值的金额,由于猜数的范围不能太大,不妨就以 [ 0 , 10 ] [\text 0,\ \text {10}] [0, 10] 这个闭区间为前置条件。
- G u e s s E v e n t \mathit {GuessEvent} GuessEvent 是定义的一个事件,我们只关心事件当中的值,同时让它在作用域结束时自我消亡,所以设定了 c o p y , d r o p \mathit {copy},\ \mathit {drop} copy, drop 这两个能力。
触发事件时只需要使用sui::event::emit(<ObjectEvent>);
而交易产生的事件详情可以在 S u i e x p l o r e r \mathit {Sui\ explorer} Sui explorer 中的 E v e n t s \mathit {Events} Events 标签页查看。
根据上述分析,我们可以很轻松地编写三个函数。
fun init(ctx: &mut TxContext) {
let count = Count {
id: object::new(ctx),
total: 0,
};
transfer::share_object(count);
}
fun send_prize(count: u64, prize: u8, ctx: &mut TxContext) {
transfer::transfer(Prize {
id: object::new(ctx),
prize,
}, tx_context::sender(ctx));
event::emit(GuessEvent {
total_count: count,
final_winner: tx_context::sender(ctx),
});
}
public entry fun guess_between_zero_and_hundred(count: &mut Count, number: u8, clock: &Clock, ctx: &mut TxContext) {
let des_number = ((clock::timestamp_ms(clock) % 11) as u8);
if (number == des_number) {
send_prize(count.total, number, ctx);
count.total = 0;
} else {
count.total = count.total + 1;
}
}
- i n i t \mathit {init} init 函数只会在发布时被调用一次,用来创建 C o u n t \mathit {Count} Count 并将其共享再好不过。
- s e n d _ p r i z e \mathit {send\_prize} send_prize 函数是在数字被猜中时调用的,作用是将奖励 P r i z e \mathit {Prize} Prize 发送给中奖者,同时触发一个事件。
- e n t r y \mathit {entry} entry 函数是指在交易过程中能够被直接调用的,它不应该有返回值,因为即使有也没什么作用,入口函数被不被 p u b l i c \mathit {public} public 修饰的区别在于能否被其它模块调用,以及合约升级时能否被更改等。
g u e s s _ b e t w e e n _ z e r o _ a n d _ h