Alva

Alva

programmer
github
telegram
email

Let's Move - Learn to Move Sui (Part Four): Deploying a Game to the Chain

letsmove

Let's Move is a motivational program to learn the Move language.

Learning log (alva-lin)

Task 4 - Deploy a game on the blockchain (mainnet)#

Task

  • Complete the learning of blockchain gaming-related knowledge.

  • Complete the learning of random numbers.

  • Complete the learning of storing Coins in contracts.

  • Complete the deployment of the first game contract on the mainnet.

For this task, I chose a simple game: Rock Paper Scissors. It is played by a single player against the computer, which uses random numbers to generate its moves. The source of the random numbers is the global clock.

Code#

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),
        });
    }
}

Random Numbers#

The code uses the sui::clock::Clock as a source of random numbers.

We can find the corresponding source code clock.move, where there is a comment about Clock. It explains that Clock is a singleton shared object that provides time for Move invocations. The address of this object is 0x6 and can only be obtained by the entry function (through an immutable reference).

In Move, objects are addresses, which means that when we need to pass in a Clock, we can directly use its address 0x6 to pass the Clock object.

Pushing and Calling#

We skip the package publishing process and directly call the method.

# You can directly use the package I have already published
# export PACKAGE_ID=0xf968242b22a4f05b62847688c4071aa82c8c97c6a39f08b4b2f12cd7f662cdff
sui client call --gas-budget 7500000 --package $PACKAGE_ID --module rock_paper_scissors --function play --args 0 0x6

You can get the output, and since I directly write the game result to an event, you can see the result content clearly. By calling the method multiple times, you can see the change in computer_choice, and the result will be calculated correctly.

You can also use SuiScan to view the information of this transaction

# Transaction hash
Transaction Digest: 61QxmsdND2t9yCSGFYXPAGH3LRJH3gYb1TuggBpbuHFX

# Event content
╭──────────────────────────────────────────────────────────────────╮
│ 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  │                                 │
│  │   └─────────────────┴───────┘                                 │
│  └──                                                             │
╰──────────────────────────────────────────────────────────────────╯
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.