1. 程式人生 > >EOS(六) - DAPP實踐之小遊戲

EOS(六) - DAPP實踐之小遊戲

    這DAPP主要是實現一個小遊戲的智慧合約的實現,是為了提供學習EOS智慧合約用。

1、編譯智慧合約,生成abi檔案
    eosiocpp -o mygame.wast mygame.cpp
    eosiocpp -g mygame.abi  mygame.cpp
2、部署智慧合約
    //建立3個使用者賬號
    cleos create account eosio banker  EOS6zzuh...  EOS6zzuh...
    cleos create account eosio player1 EOS6zzuh...  EOS6zzuh...
    cleos create account eosio player2 EOS6zzuh...  EOS6zzuh...
    //建立一個新遊戲
    cleos push action mygame.co creategame '["banker"]' -p banker
    //玩家開牌
    cleos push action mygame.co opencard '[6,1]' -p player1
    cleos push action mygame.co opencard '[6,2]' -p player2
    //查詢資料表
    cleos get table mygame.co mygame.co game
    超級節點部署智慧合約:
    cleos set contract eosio /hom/.../contracts/eosio.bios -p eosio
    建立一個智慧合約檔案
    eosiocpp -n mytest
3、前端呼叫智慧合約介面
import React from 'react'
import ReactDOM from 'react-dom'
import EOSJS from 'eosjs'

let contract_name = 'mygame.co'
let account_name = 'banker'

const EOSJS_CONFIG = {
    contractName: contract_name, //合約名字
    contractSender: account_name, //執行合約的賬號(需要與私鑰對應)
    clientConfig:{
        keyProvider:['5Jc...'], //賬號對應的私鑰
        httpEndpoint: 'http://172.0.0.1:8888' //EOS節點程式的http終端
    }
}

class LuckPoint extends React.Component {
    constructor(props){
        super(props)

        this._initGameData = this._initGameData.bind(this)

        this.gameprops = {
            gameIndex: -1,
            gameDataList: [];
            loading_test: '正在讀取資料...'
        }

        this.state = {
            gameStatus: false,
            winner: 0
        }
    }

    componentDidMount(){
        this._initGameData()
    }

    _initGameData(){
        console.log('_initGameData::......')
        this._updataGameData()
    }

    // cleos get tale luckpoint.co luckpoint.co game
    _updataGameData(){
        console.log('_updataGameData::......')

        this._showLoading(true, '正在讀取遊戲資料... ...')

        this.gameprops.gameIndex = -1
        this.gameprops.gameDataList = []

        //讀取遊戲資料
        let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
        eosjs.contract(contract_name)
            .then((contract)=>{
                console.log('_updataGameData::'+contract_name+'合約載入成功!')

                eosjs.getTableRows({"scope":contract_name, "code":contract_name, "table":"game","json":true})
                    .then(result => {
                        console.log('_updataGameData::讀取遊戲列表成功')

                        let rows = result.rows
                        let len = rows.length
                        for(let i=0; i<len; i++){

                        }
                    })
            }).catch((err)=>{
                console.log('_updataGameData::讀取遊戲列表失敗')
            })

    }

    // 呼叫智慧合約
    _createGame(){
        console.log('_createGame::建立遊戲...')

        this._showLoading(true, '正在建立遊戲... ...')

        let _sender = account_name
        let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
        eosjs.contract(EOSJS_CONFIG.contractName)
            .then((contract)=>{
                console.log('_createGame::載入合約成功')

                contract.creategame(_sender, {authorization: [_sender] })
                    .then((res)=>{
                        console.log('_createGame::遊戲建立成功')
                        this._updataGameData()
                    })
                    .catch((err)=>{
                        console.log('_createGame::遊戲建立失敗')
                    })
            })
    }

    //開牌
    _playerOpenCard(game_id, play_id){
        console.log('_playerOpenCard::遊戲ID'+game_id+', 玩家'+play_id+'開牌...')
        this._showLoading(true, '玩家'+play_id+ '正在開牌...')

        let _sender = account_name
        let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
        eosjs.contract(EOSJS_CONFIG.contractName)
            .then((contract)=>{
                console.log('_playerOpenCard::載入合約成功')

                contract.opencard(game_id, play_id, {authorization: [_sender]})
                    .then((res)=>{
                        console.log('_playerOpenCard::開牌成功')
                        this._updataGameData()
                    })
                    .catch((err)=>{
                        console.log('_playerOpenCard::開牌失敗')
                    })
            })
    }

}

4、智慧合約的實現

//mygame.hpp
#include <utility>
#include <vector>
#include <string>
#include <eosiolib/eosio.hpp>
#include <eosiolib/asset.hpp>

using eosio:asset;

class mygame: public eosio::contract {
public:
    mygame(account_name self)
    :eosio::contract(self), globals(_self, _self), games(_self, _self) {}

public:
    void creategame(const account_name _owner);
    void opencard(uint64_t _gameid, const uint32_t _player);

    //測試函式
    void sayhi(account_name receiver);
    void printrand(uint64_t _gameid);

private:
    void _checkgame(uint64_t _gameid);
    void _finishgame(uint64_t _gameid);
    uint32_t _getrandnum(uint64_t _gameid);

private:
    //@abi table global i64 全域性引用計數表
    struct global{
        uint64_t id = 0;
        uint64_t nextgameid = 0;

        uint64_t primary_key()const { return id; }
        EOSLIB_SERIALIZE(global, (id)(nextgameid) )
    };

    //建立一個多索引容器的遊戲引用計數,用於為新遊戲生成ID
    typedef eosio::multi_index<N(global), global> global_index;
    global_index globals;

    //@abi table game i64 遊戲表
    struct game {
        uint64_t id;        //遊戲ID
        uint32_t winner;    //勝出者,0還未決勝負,1玩家1勝出,2玩家2勝出
        uint32_t player1;   //玩家1點數
        uint32_t player2;   //玩家2點數
        time     creattime; //建立時間
        accunt_name owner;  //建立遊戲的賬號

        uint64_t primary_key()const { return id; } //設定資料主鍵
        EOSLIB_SERIALIZE(game, (id)(winner)(player1)(player2)(creattime)(owner) )
    };

    //建立一個多索引容器的遊戲列表
    typedef eosio::multi_index<N(game), game> game_index;
    game_index games;
};
///////////////////////////////////////////////////////////
//mygame.cpp

#include <mygame.hpp>

void mygame::creategame(const account_name _owner){
    //建立一個全域性引用計數器
    auto global_itl = globals.begin();
    if( global_itl == globals.end() ){
        global_itl = globals.emplace(_self, [&](auto& gitr){
            gitr.nextgameid = 0;
        });
    }

    //增加引用計數器
    globals.modify(global_itl, 0, [&](auto& gitr){
        gitr.nextgameid++;
    });

    //建立一個新遊戲物件
    auto game_itr = games.emplace(_self, [&](auto& new_game){
        new_game.id = global_itl->nextgameid;
        new_game.winner     = 0;
        new_game.player1    = 0;
        new_game.player2    = 0;
        new_game.createtime = now();
        new_game.owner      = _owner;
    });
}

void mygame::opencard(uint64_t _gameid, const uint32_t _player){
    eosio_assert(_player == 1 || _player == 2, "the player must is 1 or 2.");

    auto game_itr = games.find(_gameid);
    eosio_assert(game_itr != games.end(), "game not found");

    //修改遊戲狀態
    games.modify(game_itr, 0, [&](auto& gitr){
        if(_player == 1){
            gitr.player1 = 1;
        } else if(_player == 2){
            gitr.player2 = 1;
        }

        //檢查遊戲是否已經決出勝者
        _checkgame(_gameid);
    });
}

void mygame::sayhi(account_name receiver){
    eosio::print("hi~ luck point world!");
}

void mygame::printrand(uint64_t _gameid){
    eosio::print("printrand::%d",_getrandnum(_gameid));
}

void mygame::_checkgame(uint64_t _gameid){
    auto game_itr = games.find(_gameid);
    eosio_assert(game_itr != ggames.end(), "game not found");

    if(game_itr->player1 != 0 && game_itr->player2 !=0){
        games.modify(game_itr, 0, [&](auto& gitr){
            gitr.winner = _getrandnum(_gameid);
        });
    }
}

uint32_t mygame::_getrandnum(uint64_t _gameid){
    auto game_itr = games.find(_gameid);
    eosio_assert(game_itr != games.end(), "game id not found in games");

    //隨機數=遊戲建立時間,取餘2,再+1,保證是1、2中的任意一個
    return (((uint32_t)(game_itr->createtime))%2) + 1;
}

EOSIO_ABI( mygame, (creategame)(opencard)(sayhi)(printrand))