Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

................................. #19

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y wget sudo curl
RUN wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb
RUN apt-get update && sudo apt install -y ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb
RUN wget https://github.com/EOSIO/eos/releases/download/v2.0.5/eosio_2.0.5-1-ubuntu-18.04_amd64.deb
RUN apt-get update && sudo apt install -y ./eosio_2.0.5-1-ubuntu-18.04_amd64.deb
87 changes: 47 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
# Elemental Battles Tutorial Lessons

The Elemental Battles Tutorial is divided into easy to follow lessons that take you through the process of creating your own fully-functional blockchain-based dApp.

Each lesson will introduce new concepts and showcase how to include them in the existing code. Additionally, we will display explanations and source code side-by-side to make following the tutorial easy.

## About this repository

This repository contains the source code used in each of the tutorial lesson. Each lesson's code are stored in a branch. You can find all the lesson branches from the list below.

## Changelog
- v1.1.12
- Updated eos to v2.0.5
- Updated README, added Contributing, CopyrightNotice and ImportantNotice files
- v1.1.11
- Moved 'contracts' folder to root
- v1.1.10
- Removed EOSIO_DISPATCH from smart contracts
- v1.1.9
- Updated deploy_contract script to work with new abi behaviour in eosio cdt 1.6.3
- v1.1.8
- eos 2.0.0, eosjs 20.0.3, react 16.12.0, react-dom 16.12.0, react-redux 7.1.3, react scripts 3.3.0, redux 4.0.5
- v1.1.7
- eosio cdt 1.6.3 and change deprecated eosiolib header
- v1.1.6
- eos 1.8.6
- v1.1.5
- Update sample.cpp to make it deployable and compatible with new eos / cdt releases
- v1.1.4
- react 16.11.0, react-dom 16.11.0, react-modal 3.11.1, react-redux 7.1.1, react-scripts 3.2.0, redux 4.0.4, npm-run-all 4.1.5
- v1.1.3
- eos 1.8.1
- v1.1.2
- eos 1.8.0
- v1.1.1
- eos 1.7.3, eosio.cdt 1.6.1, eosjs 20.0.0
- v1.1.0
- Introduce eosio.cdt, use eosio-cpp instead of eosiocpp for the compiler
- Use own docker image which is built using the binary instead of downloading from docker hub as the eosio/eos-dev in docker hub is deprecated
- eos 1.6.0, eosio.cdt 1.5.0, eosjs 20.0.0-beta3
# Elemental Battles Tutorial Lesson 8

- *Account*: `player1`
- *Private Key*: `5KFyaxQW8L6uXFB6wSgC44EsAbzC7ideyhhQ68tiYfdKQp69xKo`
The account information is available in [eosio_docker/scripts/accounts.json](eosio_docker/scripts/accounts.json). The key pair in this file is generated **FOR TESTING ONLY** so please **DO NOT** use them for any other purposes.

## Prerequisites

Make sure Docker and Node.js are installed

* Install Docker: https://docs.docker.com/docker-for-mac/install/
* Install Node.js: https://nodejs.org/en/

The DApp and eosio will occupy the ports 3000, 8888 and 9876. Make sure nothing else is already running on these ports.

Clone the repository:
```sh
git clone https://github.com/EOSIO/eosio-card-game-repo.git
```

The following guide assumes you are using macOS.

## Quick start - Run the DApp

In this section we provide a single command script to run all the commands needed to start both the blockchain and UI. For more detail on each component see the `Detailed guide` below.

**To start**
```sh
./quick_start.sh
```

The above command will execute the following in sequence:

1. `first_time_setup.sh`
2. `start_eosio_docker.sh`
3. `start_frontend.sh`

- Login with the following credentials:

**To stop**, press `ctrl+c` on your keyboard, and execute:
```sh
docker stop eosio_cardgame_container
```

## Detailed guide

Please refer to [eosio-project-boilerplate-simple - Detailed guide](https://github.com/EOSIO/eosio-project-boilerplate-simple/blob/master/README.md#detailed-guide) for more information. This repository is using the similar structure as that.

## Lesson List

Expand Down
Empty file added contracts/cardgame/.eosproj
Empty file.
106 changes: 106 additions & 0 deletions contracts/cardgame/cardgame.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "gameplay.cpp"

void cardgame::login(name username) {
// Ensure this action is authorized by the player
require_auth(username);

// Create a record in the table if the player doesn't exist in our app yet
auto user_iterator = _users.find(username.value);
if (user_iterator == _users.end()) {
user_iterator = _users.emplace(username, [&](auto& new_user) {
new_user.username = username;
});
}
}

void cardgame::startgame(name username) {
// Ensure this action is authorized by the player
require_auth(username);

auto& user = _users.get(username.value, "User doesn't exist");

_users.modify(user, username, [&](auto& modified_user) {
// Create a new game
game game_data;

// Draw 4 cards each for the player and the AI
for (uint8_t i = 0; i < 4; i++) {
draw_one_card(game_data.deck_player, game_data.hand_player);
draw_one_card(game_data.deck_ai, game_data.hand_ai);
}

// Assign the newly created game to the player
modified_user.game_data = game_data;
});
}

void cardgame::endgame(name username) {
// Ensure this action is authorized by the player
require_auth(username);

// Get the user and reset the game
auto& user = _users.get(username.value, "User doesn't exist");
_users.modify(user, username, [&](auto& modified_user) {
modified_user.game_data = game();
});
}

void cardgame::playcard(name username, uint8_t player_card_idx) {
// Ensure this action is authorized by the player
require_auth(username);

// Checks that selected card is valid
check(player_card_idx < 4, "playcard: Invalid hand index");

auto& user = _users.get(username.value, "User doesn't exist");

// Verify game status is suitable for the player to play a card
check(user.game_data.status == ONGOING,
"playcard: This game has ended. Please start a new one");
check(user.game_data.selected_card_player == 0,
"playcard: The player has played his card this turn!");

_users.modify(user, username, [&](auto& modified_user) {
game& game_data = modified_user.game_data;

// Assign the selected card from the player's hand
game_data.selected_card_player = game_data.hand_player[player_card_idx];
game_data.hand_player[player_card_idx] = 0;

// AI picks a card
int ai_card_idx = ai_choose_card(game_data);
game_data.selected_card_ai = game_data.hand_ai[ai_card_idx];
game_data.hand_ai[ai_card_idx] = 0;

resolve_selected_cards(game_data);

update_game_status(modified_user);
});
}

void cardgame::nextround(name username) {
// Ensure this action is authorized by the player
require_auth(username);

auto& user = _users.get(username.value, "User doesn't exist");

// Verify game status
check(user.game_data.status == ONGOING,
"nextround: This game has ended. Please start a new one.");
check(user.game_data.selected_card_player != 0 && user.game_data.selected_card_ai != 0,
"nextround: Please play a card first.");

_users.modify(user, username, [&](auto& modified_user) {
game& game_data = modified_user.game_data;

// Reset selected card and damage dealt
game_data.selected_card_player = 0;
game_data.selected_card_ai = 0;
game_data.life_lost_player = 0;
game_data.life_lost_ai = 0;

// Draw card for the player and the AI
if (game_data.deck_player.size() > 0) draw_one_card(game_data.deck_player, game_data.hand_player);
if (game_data.deck_ai.size() > 0) draw_one_card(game_data.deck_ai, game_data.hand_ai);
});
}
132 changes: 132 additions & 0 deletions contracts/cardgame/cardgame.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include <eosio/eosio.hpp>

using namespace std;
using namespace eosio;
class [[eosio::contract]] cardgame : public eosio::contract {

private:

enum game_status: int8_t {
ONGOING = 0,
PLAYER_WON = 1,
PLAYER_LOST = -1
};

enum card_type: uint8_t {
EMPTY = 0, // Represents empty slot in hand
FIRE = 1,
WOOD = 2,
WATER = 3,
NEUTRAL = 4,
VOID = 5
};

struct card {
uint8_t type;
uint8_t attack_point;
};

const map<uint8_t, card> card_dict = {
{ 0, {EMPTY, 0} },
{ 1, {FIRE, 1} },
{ 2, {FIRE, 1} },
{ 3, {FIRE, 2} },
{ 4, {FIRE, 2} },
{ 5, {FIRE, 3} },
{ 6, {WOOD, 1} },
{ 7, {WOOD, 1} },
{ 8, {WOOD, 2} },
{ 9, {WOOD, 2} },
{ 10, {WOOD, 3} },
{ 11, {WATER, 1} },
{ 12, {WATER, 1} },
{ 13, {WATER, 2} },
{ 14, {WATER, 2} },
{ 15, {WATER, 3} },
{ 16, {NEUTRAL, 3} },
{ 17, {VOID, 0} }
};

struct game {
int8_t life_player = 5;
int8_t life_ai = 5;
vector<uint8_t> deck_player = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
vector<uint8_t> deck_ai = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
vector<uint8_t> hand_player = {0, 0, 0, 0};
vector<uint8_t> hand_ai = {0, 0, 0, 0};
uint8_t selected_card_player = 0;
uint8_t selected_card_ai = 0;
uint8_t life_lost_player = 0;
uint8_t life_lost_ai = 0;
int8_t status = ONGOING;
};

struct [[eosio::table]] user_info {
name username;
uint16_t win_count = 0;
uint16_t lost_count = 0;
game game_data;

auto primary_key() const { return username.value; }
};

struct [[eosio::table]] seed {
uint64_t key = 1;
uint32_t value = 1;

auto primary_key() const { return key; }
};

typedef eosio::multi_index<name("users"), user_info> users_table;

typedef eosio::multi_index<name("seed"), seed> seed_table;

users_table _users;

seed_table _seed;

void draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand);

int calculate_attack_point(const card& card1, const card& card2);

int ai_best_card_win_strategy(const int ai_attack_point, const int player_attack_point);

int ai_min_loss_strategy(const int ai_attack_point, const int player_attack_point);

int ai_points_tally_strategy(const int ai_attack_point, const int player_attack_point);

int ai_loss_prevention_strategy(const int8_t life_ai, const int ai_attack_point, const int player_attack_point);

int calculate_ai_card_score(const int strategy_idx, const int8_t life_ai,
const card& ai_card, const vector<uint8_t> hand_player);

int ai_choose_card(const game& game_data);

void resolve_selected_cards(game& game_data);

void update_game_status(user_info& user);

int random(const int range);

public:

cardgame( name receiver, name code, datastream<const char*> ds ):contract(receiver, code, ds),
_users(receiver, receiver.value),
_seed(receiver, receiver.value) {}

[[eosio::action]]
void login(name username);

[[eosio::action]]
void startgame(name username);

[[eosio::action]]
void endgame(name username);

[[eosio::action]]
void playcard(name username, uint8_t player_card_idx);

[[eosio::action]]
void nextround(name username);

};
Loading