Alva

Alva

programmer
github
telegram
email

讓我們移動 - 學 Move 得 Sui(四):完成一個遊戲的上鏈部署

letsmove

Let's Move 是一項學習 Move 語言的激勵計畫,鼓勵更多的人學習 Move 語言

學習日誌 (alva-lin)

任務 4 - 完成一個遊戲的上鏈部署 (mainnet)#

任務

  • 完成鏈遊相關知識的學習

  • 完成隨機數的學習

  • 完成如何存儲 Coin 在合約的學習

  • 完成第一個遊戲合約部署主網

本次任務,我選擇了簡單的遊戲:石頭剪刀布,由單個玩家進行遊玩,與之對抗的電腦,使用隨機數來生成操作。隨機數的來源,使用全局時鐘

代碼#

module new_gaming::rock_paper_scissors {
    use std::string::{Self, String};
    use sui::clock::{Self, Clock};
    use sui::event;

    const EInvalidNumber: u64 = 1;

    struct GamingResultEvent has copy, drop {
        is_win: bool,
        your_choice: String,
        computer_choice: String,
        result: String,
    }

    fun get_random_choice(clock: &Clock) : u8 {
        ((clock::timestamp_ms(clock) % 3) as u8)
    }

    fun map_choice_to_string(choice: u8) : String {
        if (choice == 0) {
            string::utf8(b"rock")
        } else if (choice == 1) {
            string::utf8(b"paper")
        } else if (choice == 2) {
            string::utf8(b"scissors")
        } else {
            string::utf8(b"Invalid")
        }
    }

    public fun play(choice: u8, clock: &Clock) {
        assert!(choice < 3, EInvalidNumber);

        let computer_choice = get_random_choice(clock);
        let (result, is_win) = if (
            (choice == 0 && computer_choice == 1)
            || (choice == 1 && computer_choice == 2)
            || (choice == 2 && computer_choice == 0)
        ) {
            (string::utf8(b"Win"), true)
        } else if (choice == computer_choice) {
            (string::utf8(b"Draw"), false)
        } else {
            (string::utf8(b"Lose"), false)
        };

        event::emit(GamingResultEvent {
            result,
            is_win,
            your_choice: map_choice_to_string(choice),
            computer_choice: map_choice_to_string(computer_choice),
        });
    }
}

隨機數#

代碼中使用了 sui::clock::Clock 時鐘,來作為隨機數。

我們可以找到對應的源碼 clock.move,其中關於 Clock 有一段註釋。解釋了 Clock 是一個單例共享對象,為 Move 的調用提供時間。該對象的地址為 0x6,只能由入口函數獨取(通過不可變引用訪問)

Move 中,對象即地址,也就是說我們在需要傳入 Clock 時,直接使用它的地址 0x6,就可以傳入 Clock 對象。

推送和調用#

我們跳過包的發布流程,直接調用方法

# 你可以直接使用我已經發布好的包
# export PACKAGE_ID=0xf968242b22a4f05b62847688c4071aa82c8c97c6a39f08b4b2f12cd7f662cdff
sui client call --gas-budget 7500000 --package $PACKAGE_ID --module rock_paper_scissors --function play --args 0 0x6

可以得到輸出,因為我直接將遊戲結果寫到事件中,所以可以清晰看出結果內容,多次調用方法,可以看到 computer_choice 的變化,同時 result 也會正確計算。

也可以直接使用 SuiScan 來查看本次交易的信息

# 交易 hash
Transaction Digest: 61QxmsdND2t9yCSGFYXPAGH3LRJH3gYb1TuggBpbuHFX

# 事件內容
╭──────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                         │
├──────────────────────────────────────────────────────────────────┤
│  ┌──                                                             │
│  │ EventID: 61QxmsdND2t9yCSGFYXPAGH3LRJH3gYb1TuggBpbuHFX:0
│  │ PackageID: 0xf968242b2XXXXXXXXXXX662cdff                      │
│  │ Transaction Module: rock_paper_scissors                       │
│  │ Sender: 0xb31fcf5cXXXXXXXXa6965c57f48                         │
│  │ EventType: 0xf9682....2cdff::rock_.._ssors::GamingResultEvent │
│  │ ParsedJSON:                                                   │
│  │   ┌─────────────────┬───────┐                                 │
│  │   │ computer_choice │ rock  │                                 │
│  │   ├─────────────────┼───────┤                                 │
│  │   │ is_win          │ false │                                 │
│  │   ├─────────────────┼───────┤                                 │
│  │   │ result          │ Draw  │                                 │
│  │   ├─────────────────┼───────┤                                 │
│  │   │ your_choice     │ rock  │                                 │
│  │   └─────────────────┴───────┘                                 │
│  └──                                                             │
╰──────────────────────────────────────────────────────────────────╯
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。