create account

Making a Decentralized Game on Hive - Tic Tac Toe - Part 1 by mahdiyari

View this thread on: hive.blogpeakd.comecency.com
· @mahdiyari · (edited)
$21.49
Making a Decentralized Game on Hive - Tic Tac Toe - Part 1
<center>![tic-tac-toe.png](https://images.hive.blog/DQmYne66xZ9RBsrUwF9N76S5XnjJGyzEgBPbbsZRnNAHUzx/tic-tac-toe.png)</center>
We will develop a decentralized game by the end of this series. The goal is to make learning development on Hive blockchain easier by using a simple game as the training project.

## Target audience
Of course, it's not for everybody. I will try to keep it simple as possible for people with less experience with development. But some degree of understanding code is necessary to learn something. I will explain anything related to the Hive blockchain that we use.

You can find the links for the final result of this part at the end of this post.

## Why "tic-tac-toe"?
It's a simple multiplayer game and it covers most of the topics needed for a bigger decentralized game or application. Most people are already familiar with this game and it's easier to code and its rules are simple.

## Development
We will use Javascript for the game because it's simple enough so most people understand easily. The front-end will be pure HTML. Also, I think MySQL is a good fit as the database. The game needs a database to keep track of games and players. MySQL docker can be set up in a few minutes.

The decentralized game will work without depending on one central software. The game will talk only to the blockchain and there is no central database. It doesn't need a private entity to hold players' data. Anyone can run an interface for the game.

(We have a database but it's not a central private database and it can be synced through blockchain. Anyone should be able to run an instance of the game and the game will get the same exact database by reading data from the blockchain. It's like hivemind, the database that holds and serves most of the data on Hive.)

## Tools I'm using
- Visual Studio Code
- Nodejs
- MySQL docker setup
- Chrome browser

I didn't plan anything beforehand so I don't know how many posts it will take. I will list the things that come to my mind right now.

## Planning
- Front-end
  - Make a login method on the client-side
  - Display available games list
  - Create/Request to join a game
  - Design the game visuals and controls
- Back-end
  - Stream the blockchain and listen for custom_json operations
  - Define custom_json operations
  - Game mechanics
  - API to communicate with front-end
  - Replay/resync method to update the database on newly deployed game clients

The above list may or may not change. Anyway, let's start with the front-end and add a login method.
***
## Part 1: Front-end - Login method
I think the HTML part doesn't need any explanation. Page title, description, bootstrap navbar, and a login link. Added `css/style.css` and `js/app.js` too. When the user clicks on the "login" link, a modal with the login form will appear. It will then fire `login()` function on submit.

`index.html`:
```
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="description" content="A decentralized game on hive blockchain" />
  <title>Tic-Tac-Toe on Hive blockchain</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous" />
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0"
    crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/hive-tx/dist/hive-tx.min.js"></script>
  <link rel="stylesheet" href="css/style.css" />
</head>

<body>
  <nav class="navbar navbar-expand navbar-dark bg-dark">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">Tic-Tac-Toe</a>
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link" href="#" data-bs-toggle="modal" data-bs-target="#login-modal" id="login-button">
            Login
          </a>
        <li class="nav-item dropdown" id="logout-menu" style="display: none;">
          <a class="nav-link dropdown-toggle" href="#" id="username-button" role="button" data-bs-toggle="dropdown"
            aria-expanded="false"></a>
          <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="username-button">
            <li><a class="dropdown-item" href="#" onclick="logout()">Logout</a></li>
          </ul>
        </li>
        </li>
      </ul>
    </div>
  </nav>
  <div class="modal fade" id="login-modal" tabindex="-1" aria-labelledby="login-modal-title" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="login-modal-title">Login</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <form onsubmit="login(); return false">
            <div class="mb-3">
              <label for="username" class="form-label">Username:</label>
              <div class="input-group mb-3">
                <span class="input-group-text">@</span>
                <input type="text" class="form-control" placeholder="username" aria-label="username" id="username"
                  required>
              </div>
              <div class="form-text">Your Hive username. Lowercase.</div>
            </div>
            <div class="mb-3">
              <label for="posting-key" class="form-label">Posting key:</label>
              <input type="password" class="form-control" id="posting-key" placeholder="Private posting key" required>
              <div class="form-text">Your key will never leave your browser.</div>
            </div>
            <p id="login-error"></p>
            <button type="submit" class="btn btn-primary" id="login-form-btn">Login</button>
            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
          </form>
        </div>
      </div>
    </div>
  </div>
  <script src="js/app.js"></script>
</body>

</html>
``` 
***
### Styles
`css/style.css`:
```
.navbar-nav {
  margin-right: 30px;
}
.navbar-brand {
  margin-left: 30px;
}
#login-error {
  color: #e31337;
  display: none;
}
```
***
## Javascript
`js/app.js`
An object for user data.
```
const userData = {
  authorized: false,
  username: '',
  key: ''
}
```
Let's define the login function. It will verify the posting key and username then keep the data in localStorage. We use the [hive-tx](https://github.com/mahdiyari/hive-tx-js) library for converting keys.

```
const login = async () => {
  const loginModal = bootstrap.Modal.getInstance(
    document.getElementById('login-modal')
  )
  const loginButtonForm = document.getElementById('login-form-btn')
  loginButtonForm.setAttribute('disabled', 'true')
  const loginError = document.getElementById('login-error')
  loginError.style.display = 'none'
  const username = document.getElementById('username').value
  const key = document.getElementById('posting-key').value
  const validate = await validatePostingKey(username, key)
  if (validate.result === 0) {
    loginError.innerHTML = validate.error
    loginError.style.display = 'block'
    loginButtonForm.removeAttribute('disabled')
    return
  }
  userData.authorized = true
  userData.username = username
  userData.key = key
  window.localStorage.setItem('userData', JSON.stringify(userData))
  loginButtonForm.removeAttribute('disabled')
  updateState()
  loginModal.hide()
}
```
As you can see there are 2 more functions used inside the login function. The first one is `validatePostingKey()`. It's a post for itself.
Let me explain it. First, we make a call to the Hive RPC API node by using hive-tx library and get the account information including the public posting key. Then we convert the user's private posting key to the public key and compare the two values. If the two values are equal then the user-provided private key is correct and we can authorize the user. There are also other ways to achieve the same result like signing a message with the private key and validating that signature with the public key.

```
const validatePostingKey = async (username, privateKey) => {
  const accounts = await hiveTx.call('condenser_api.get_accounts', [[username]])
  if (
    !accounts ||
    !accounts.result ||
    !Array.isArray(accounts.result) ||
    accounts.result.length < 1
  ) {
    return { result: 0, error: 'Network error or wrong username' }
  }
  try {
    const account = accounts.result[0]
    const publicWif = account.posting.key_auths[0][0] || ''
    const generatedPublicKey = hiveTx.PrivateKey.from(privateKey)
      .createPublic()
      .toString()

    if (generatedPublicKey !== publicWif) {
      return { result: 0, error: 'Wrong key' }
    }
    return { result: 1 }
  } catch (e) {
    return { result: 0, error: 'Wrong key or network error' }
  }
}
```
updateState() is used to update the HTML interface after user login and logout.
```
const updateState = () => {
  const loginButton = document.getElementById('login-button')
  const logoutMenu = document.getElementById('logout-menu')
  const usernameButton = document.getElementById('username-button')
  if (userData.authorized && userData.username && userData.key) {
    loginButton.style.display = 'none'
    logoutMenu.style.display = 'block'
    usernameButton.innerHTML = '@' + userData.username
  } else {
    loginButton.style.display = 'block'
    logoutMenu.style.display = 'none'
  }
}
```
And it's time for the logout function.
```
const logout = () => {
  userData.authorized = false
  userData.username = ''
  userData.key = ''
  window.localStorage.removeItem('userData')
  updateState()
}
```
We need to check localStorage on the page reload and log in the user if the key is in the localStorage.
```
const checkState = () => {
  const localData = window.localStorage.getItem('userData')
  let data
  if (!localData) {
    return
  }
  try {
    data = JSON.parse(localData)
  } catch (e) {
    data = userData
  }
  if (data.authorized && data.username && data.key) {
    userData.authorized = true
    userData.username = data.username
    userData.key = data.key
    updateState()
  }
}
checkState()
```
Now we have a working login and logout system. It keeps user data in localStorage which stays on the browser only.
What we have done so far is just the front-end. Our game needs a back-end server to provide the game data. We will stream blocks on the back-end and process game data then serve it through API. Our front-end will broadcast transactions which will update the back-end. In other words, the back-end is only serving the data it receives through the blockchain. We could stream the blocks on the client-side (browser) but it's not efficient and it is just unnecessary bandwidth waste.
***
You can see the running app on https://tic-tac-toe.mahdiyari.info/
The final code is on GitLab https://gitlab.com/mahdiyari/decentralized-game-on-hive

In the next part, we will set up our back-end server and database. Now that I think about it, MySQL might be an overkill for this project. Anyway, let's stick to it for now.

I want to get feedback from the community before continuing further. Help me with your comments and let me know what you think about this project. How can I improve it? Should I explain everything from the basics? I greatly appreciate your feedback.

Thanks for reading.

[Next part >>](https://hive.blog/hive-139531/@mahdiyari/making-a-decentralized-game-on-hive-part-2)
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 81 others
properties (23)
authormahdiyari
permlinkmaking-a-decentralized-game-on-hive-tic-tac-toe-part-1
categoryhive-139531
json_metadata{"tags":["dev","game","decentralized","hive"],"image":["https://images.hive.blog/DQmYne66xZ9RBsrUwF9N76S5XnjJGyzEgBPbbsZRnNAHUzx/tic-tac-toe.png"],"links":["https://github.com/mahdiyari/hive-tx-js"],"app":"hiveblog/0.1","format":"markdown"}
created2021-03-13 20:04:06
last_update2021-04-04 08:23:15
depth0
children13
last_payout2021-03-20 20:04:06
cashout_time1969-12-31 23:59:59
total_payout_value12.310 HBD
curator_payout_value9.183 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length11,737
author_reputation199,858,416,089,067
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,347,849
net_rshares36,094,012,994,747
author_curate_reward""
vote details (145)
@brittandjosie ·
Shared in discord 
properties (22)
authorbrittandjosie
permlinkre-mahdiyari-qq9xc2
categoryhive-139531
json_metadata{"tags":["hive-139531"],"app":"peakd/2021.03.7"}
created2021-03-20 15:21:39
last_update2021-03-20 15:21:39
depth1
children0
last_payout2021-03-27 15:21:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length18
author_reputation525,661,217,955,513
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,486,523
net_rshares0
@dexterdev ·
$0.18
@mahdiyari : I did tried to get initiated with such a project(although unequipped with coding). After my thesis submission I had few spare time last year. But unfortunately I got busy with doing science again and I stopped that project in between. Thank you for posting this on twitter and it made me to come back to HIVE blockchain. This is a great initiative in fact. Please keep writing about it from basics. I am following it. <3
👍  
properties (23)
authordexterdev
permlinkre-mahdiyari-2021314t162622774z
categoryhive-139531
json_metadata{"tags":["hive-139531","dev","game","decentralized","hive"],"app":"ecency/3.0.15-vision","format":"markdown+html"}
created2021-03-14 14:26:24
last_update2021-03-14 14:26:24
depth1
children2
last_payout2021-03-21 14:26:24
cashout_time1969-12-31 23:59:59
total_payout_value0.088 HBD
curator_payout_value0.089 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length433
author_reputation17,771,704,061,240
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,361,744
net_rshares451,634,142,839
author_curate_reward""
vote details (1)
@mahdiyari ·
$0.02
Thanks for following me through this. I will do my best.
👍  ,
properties (23)
authormahdiyari
permlinkqpyraq
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2021-03-14 14:37:42
last_update2021-03-14 14:37:42
depth2
children1
last_payout2021-03-21 14:37:42
cashout_time1969-12-31 23:59:59
total_payout_value0.012 HBD
curator_payout_value0.012 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length56
author_reputation199,858,416,089,067
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,361,934
net_rshares69,343,482,935
author_curate_reward""
vote details (2)
@dexterdev ·
thank you :)
properties (22)
authordexterdev
permlinkre-mahdiyari-2021314t165044125z
categoryhive-139531
json_metadata{"tags":["ecency"],"app":"ecency/3.0.15-vision","format":"markdown+html"}
created2021-03-14 14:50:42
last_update2021-03-14 14:50:42
depth3
children0
last_payout2021-03-21 14:50:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length12
author_reputation17,771,704,061,240
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,362,132
net_rshares0
@maakue ·
$0.49
Hi,
Trying to figure out this part of the code, what is the meaning of "[[username]]"? Won't username suffice? 

const accounts = await hiveTx.call('condenser_api.get_accounts', [[username]])

Sorry not a JS dev :)
👍  
properties (23)
authormaakue
permlinkr953bn
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2022-03-22 09:21:27
last_update2022-03-22 09:21:27
depth1
children2
last_payout2022-03-29 09:21:27
cashout_time1969-12-31 23:59:59
total_payout_value0.243 HBD
curator_payout_value0.243 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length214
author_reputation1,477,515,545,000
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,579,761
net_rshares362,324,041,837
author_curate_reward""
vote details (1)
@mahdiyari ·
That's not related to JS. The Hive API node wants a call in that format. Check APIs on [devportal](https://developers.hive.io/apidefinitions/#condenser_api.get_accounts)
Parameters are sent in an array. Here, we have to put another array inside that array because API accepts a list of accounts not a single account.

The above code is equivalent to this curl:
```
curl -s --data '{"jsonrpc":"2.0", "method":"condenser_api.get_accounts", "params":[["username"]], "id":1}' https://api.hive.blog
```
properties (22)
authormahdiyari
permlinkr953jh
categoryhive-139531
json_metadata{"links":["https://developers.hive.io/apidefinitions/#condenser_api.get_accounts"],"app":"hiveblog/0.1"}
created2022-03-22 09:26:51
last_update2022-03-22 09:26:51
depth2
children1
last_payout2022-03-29 09:26:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length497
author_reputation199,858,416,089,067
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,579,967
net_rshares0
@maakue ·
Thanks!
properties (22)
authormaakue
permlinkr95484
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2022-03-22 09:40:54
last_update2022-03-22 09:40:54
depth3
children0
last_payout2022-03-29 09:40:54
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length7
author_reputation1,477,515,545,000
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id111,580,295
net_rshares0
@poshbot ·
https://twitter.com/MahdiYari4/status/1370857583200903175
properties (22)
authorposhbot
permlinkre-making-a-decentralized-game-on-hive-tic-tac-toe-part-1-20210313t220138z
categoryhive-139531
json_metadata"{"app": "beem/0.24.20"}"
created2021-03-13 22:01:36
last_update2021-03-13 22:01:36
depth1
children0
last_payout2021-03-20 22:01:36
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length57
author_reputation5,554,335,374,496
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,350,599
net_rshares0
@satishart ·
Very interesting post @mahdiyari My son who is a gamer is very interested
properties (22)
authorsatishart
permlinkqpy6ih
categoryhive-139531
json_metadata{"users":["mahdiyari"],"app":"hiveblog/0.1"}
created2021-03-14 07:08:42
last_update2021-03-14 07:08:42
depth1
children0
last_payout2021-03-21 07:08:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length73
author_reputation3,092,067,408,596
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,356,750
net_rshares0
@simplegame ·
$0.20
Does this allow players to used Hive-Keychain to login?

If not could you focus on how that works and how the data is passed after the login.
👍  
properties (23)
authorsimplegame
permlinkre-mahdiyari-qpxcwd
categoryhive-139531
json_metadata{"tags":["hive-139531"],"app":"peakd/2021.03.7"}
created2021-03-13 20:29:03
last_update2021-03-13 20:29:03
depth1
children3
last_payout2021-03-20 20:29:03
cashout_time1969-12-31 23:59:59
total_payout_value0.099 HBD
curator_payout_value0.099 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length141
author_reputation129,304,695,177,891
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,348,577
net_rshares502,179,672,196
author_curate_reward""
vote details (1)
@mahdiyari ·
It's simple addition and can be added later.
properties (22)
authormahdiyari
permlinkqpxd4f
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2021-03-13 20:33:51
last_update2021-03-13 20:33:51
depth2
children2
last_payout2021-03-20 20:33:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length44
author_reputation199,858,416,089,067
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,348,763
net_rshares0
@marcocasario ·
Looking forward to it
properties (22)
authormarcocasario
permlinkqpxeqq
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2021-03-13 21:08:51
last_update2021-03-13 21:08:51
depth3
children0
last_payout2021-03-20 21:08:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length21
author_reputation18,169,643,257,414
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd0
post_id102,349,706
net_rshares0
@simplegame ·
ok. 
Looking forward to the next few posts.

properties (22)
authorsimplegame
permlinkre-mahdiyari-qpxd61
categoryhive-139531
json_metadata{"tags":["hive-139531"],"app":"peakd/2021.03.7"}
created2021-03-13 20:34:48
last_update2021-03-13 20:34:48
depth3
children0
last_payout2021-03-20 20:34:48
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length45
author_reputation129,304,695,177,891
root_title"Making a Decentralized Game on Hive - Tic Tac Toe - Part 1"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id102,348,782
net_rshares0