이번 장에서는 간단한 야구 게임을 만들어 보도록 하겠습니다.
야구 게임의 룰은 1~9로 이루어진 3자리 숫자를 맞추는 걸 목표로 합니다. 숫자를 제시하면 힌트를 줍니다.
규칙은 다음과 같습니다.
자릿수와 숫자가 모두 일치한다면 Strike
자릿수는 일치하지 않지만 숫자가 일치한다면 Ball
해당 규칙을 생각하여 스마트 컨트랙트를 작성하겠습니다.
https://github.com/DevToothCrew/eos_book_example/blob/master/baseball/baseball.hpp
#pragma once #include#include #include #include #include #include namespace eosio { using std::string; class baseball : public contract { public: account_name _owner; uint64_t num_table[504]; baseball(account_name self):contract(self){ // Init _owner _owner = self; // Init Number Table uint64_t temp = 0; for(uint64_t i=100 ; i < 1000; i++){ if( (i/10)%11 != 0 ){ if( i/100 != i%10 ){ if( (i%100)%11 != 0 ){ if( i%10 != 0 ){ if( (i%100)/10 != 0 ){ num_table[temp] = i; temp++; } } } } } } } //@abi action void start(account_name payer); //@abi action void throwball(account_name player,uint64_t value); void matchnum(uint64_t num, uint64_t array[]); void createnum(account_name player); private: //@abi table scores i64 struct score { account_name user; uint64_t num; uint64_t primary_key()const { return user; } }; typedef eosio::multi_index scores; }; }
// Init Number Table
uint64_t temp = 0;
for(uint64_t i=100 ; i < 1000; i++){
if( (i/10)%11 != 0 ){
if( i/100 != i%10 ){
if( (i%100)%11 != 0 ){
if( i%10 != 0 ){
if( (i%100)/10 != 0 ){
num_table[temp] = i;
temp++;
}
}
}
}
}
}
자리가 중복되지 않는 숫자 503개를 테이블에 저장합니다.
//@abi action
void start(account_name payer);
//@abi action
//@abi table scores i64
struct score {
account_name user;
uint64_t num;
uint64_t primary_key()const { return user; }
};
https://github.com/DevToothCrew/eos_book_example/blob/master/baseball/baseball.cpp
#include "baseball.hpp"
namespace eosio {
void baseball::start(account_name player)
{
print("Baseball game start!!!");
print("\n create goal number");
baseball::createnum(player);
}
void baseball::throwball(account_name player,uint64_t value )
{
scores goalnum(_self,player);
const auto& data = goalnum.get(player,"No Goal Num");
uint64_t num = data.num;
uint64_t strike = 0, ball = 0;
uint64_t goalarray[3];
uint64_t playervalue[3];
matchnum(num, goalarray);
matchnum(value, playervalue);
for(int i=0; i<3;i++)
{
for(int j=0; j<3; j++)
{
if(goalarray[i]==playervalue[j]&& i==j)
{
strike++;
}
if(goalarray[i]==playervalue[j]&& i!= j)
{
ball++;
}
}
}
if(strike==3)
{
print("Homerun!! You Win.\n");
}
else
{
print(" Strike : ", strike, " Ball : ", ball);
}
}
void baseball::createnum(account_name player)
{
checksum256 result;
uint64_t source = tapos_block_num() * tapos_block_prefix();
sha256((char *)&source, sizeof(source), &result);
uint64_t* p = reinterpret_cast(&result.hash);
uint64_t randNum = (*p % 504);
scores num(_self, player);
auto iter=num.find(player);
if(iter==num.end())
{
num.emplace(_self,[&](auto& s){
s.user = player;
s.num = num_table[randNum];
});
}
else{
num.modify(iter,_self,[&](auto& s){
s.num = num_table[randNum];
});
}
}
void baseball::matchnum(uint64_t num, uint64_t array[])
{
array[0] = num/100;
array[1] = num/10;
array[1] = array[1]%10;
array[2] = num%10;
}
}
EOSIO_ABI( eosio::baseball, (start)(throwball) )
작성한 cpp파일로 wasm파일을, hpp파일로 abi로 만들어 줍니다.
$ eosiocpp -o baseball.wasm baseball.cpp
$ eosiocpp -g baseball.abi baseball.hpp
< baseball.wasm, baseball.abi 파일 생성 화면 >
만들어진 wasm파일과 abi파일을 배포합니다.
< baseball 컨트랙트 배포 >
cleos push action 명령어로 Start 함수를 실행시켜 게임을 시작합니다.
< start 액션 실행 결과 >
throwball함수를 실행하여 숫자를 맞춰봅니다.
< throwball 액션 실행 결과 >
strike에 성공했다면 socres 테이블을 조회하여 결괏값이 맞는지 확인합니다.
< scores 테이블 정보 확인 >
SmartContract로 간단한 게임을 만들어 보았습니다. 위 게임을 통해 우리는 컨트랙트 내부에서만 사용하는 함수, 컨트랙트 생성자 초기화, 오류 텍스트를 띄우는 방법, 난수 를 생성하는 방법, 함수를 실행하여 결괏값을 얻는 방법을 익혔습니다. 퍼블릭 블록체인의 특징은 모두 다 보여진다 입니다. 결국 해당 게임은 간단한 테이블 조회를 통해 답을 쉽게 찾을 수 있습니다.