在 Sui 上开发一个简单的掷骰子游戏
如果你是初学者,强烈建议看下前几节内容:
入门 Sui Move 开发:2. 常用命令、编写并发布 Hello World 合约
入门 Sui Move 开发:3. Sui Move 语法和设计模式
入门 Sui Move 开发:4. Sui Move 中集合、对象、泛型、动态字段
入门 Sui Move 开发:5. 发布同质化代币 — NFT
本节学习目标完成一个掷骰子游戏的合约,游戏内容包含:初始化的时候合约创建者创建一个游戏,管理员向游戏奖池中存入奖金,管理员从游戏奖池中提取金额,用户玩游戏需要输入猜测的结果和押注金额。
实现上面的功能,会涉及到以下新内容的学习:
assert!
的使用,如果不符合预期则抛出错误并停止执行coin
模块:对币的拆分、合并处理,可以转移balance
模块: 游戏合约中对 token
的处理(使用之前发布的水龙头代币为游戏币)创建好合约之后,如果想添加其他合约的依赖需要添加一下配置
模块依赖:在模块中添加对其他模块的依赖
当前模块 Move.toml
添加:
[dependencies]
...
coin_greyhao = { local = "../coin_greyhao" } # 你需要依赖的模块的实际路径
被依赖模块(游戏币合约)需要在 Move.toml
中添加:
published-at = "合约发布得到的 packageId"
...
[dependencies]
// 使用 new_generator 创建 RandomGenerator 对象
// random 的值为 0x8 (系统预留的值)
let mut g = new_generator(random, ctx);
// 然后通过 RandomGenerator 的实例可以生成不同类型的 随机数
let win_num = generate_u8_in_range(&mut g, 1, 6);
Coin 是对 Balance 的包装;Balance 用来操作 Coin 的数量。
// 获取 in_coin 对象所包含的数量
coin::value(in_coin)
// 从 balance 中取出指定数量的 coin,用于转账
let coin = coin::take(&mut game.pool_amount, amount, ctx);
// 拆分指定数量的 coin,返回的是 balance 类型
let coin_balance = in_coin.balance_mut().split(拆分的数量)
// 合并两个 balance
game.pool_amount.join(coin_balance);
Token Coin Balance 关系和转换
以下是完整代码
/// 游戏:掷骰子,用户下注并猜测点数,如果猜中则获取同下注数量相同的奖励,如果猜错则下注金额归游戏池所有
module game_greyhao::game_greyhao;
use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin};
use sui::random::{Random, new_generator, generate_u8_in_range};
use coin_greyhao::greyhaofaucet::GREYHAOFAUCET;
const ErrorUserInsufficient: u64 = 0x101;
const ErrorGameInsufficient: u64 = 0x101;
public struct Game has key {
id: UID,
pool_amount: Balance<GREYHAOFAUCET>,
}
public struct Admin has key {
id: UID,
}
fun init(ctx: &mut TxContext) {
let game = Game {
id: object::new(ctx),
pool_amount: balance::zero()
};
transfer::share_object(game);
let admin = Admin { id: object::new(ctx) };
transfer::transfer(admin, ctx.sender());
}
public entry fun addCoinToGamePool(game: &mut Game, in_coin: &mut Coin<GREYHAOFAUCET>, amount: u64, _: &mut TxContext) {
// coin 的总金额
let value = coin::value(in_coin);
assert!(amount <= value, ErrorUserInsufficient);
// 拆分指定金额的 coin
let coin_balance = in_coin.balance_mut().split(amount);
// 添加到游戏奖池中
game.pool_amount.join(coin_balance);
}
public entry fun removeCoinFromGamePool(_: &Admin, game: &mut Game, amount: u64, ctx: &mut TxContext) {
// 池子里的余额是否大于要提取的数量
assert!(game.pool_amount.value() >= amount, ErrorGameInsufficient);
let coin = coin::take(&mut game.pool_amount, amount, ctx);
transfer::public_transfer(coin, ctx.sender());
}
entry fun play(game: &mut Game, random: &Random, guess_num: u8, in_coin: &mut Coin<GREYHAOFAUCET>, amount: u64, ctx: &mut TxContext) {
// 最大下注金额为奖池的 三分之一
assert!(game.pool_amount.value() >= (amount * 3), ErrorGameInsufficient);
// 用户余额数值是要大于下注金额
assert!(in_coin.balance().value() >= amount, ErrorUserInsufficient);
let mut g = new_generator(random, ctx);
let win_num = generate_u8_in_range(&mut g, 1, 6);
if(win_num == guess_num) {
// 从奖池中拿出同下注金额相同的数量作为奖励
let reward_coin = coin::take(&mut game.pool_amount, amount, ctx);
// 将奖励返回给玩家
in_coin.join(reward_coin);
} else {
// 下注金额放入池子里
Self::addCoinToGamePool(game, in_coin, amount, ctx);
}
}
使用命令行调用 play
方法传入 0x8
作为 Random
的值没问题,但是如果在浏览器中调用会一直报错。
以上就是本节的所有内容。
如果觉得本节内容对你有所帮助,可以点赞鼓励下。
如果你对文章中内容有任何疑问可以留言。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!