Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Intermediate · 1 hour

RAPA Game on Reach

The business purpose of this tutorial is to teach how the Reach platform can be used on Algorand Blockchain development. Allow developers to create new Algorand solutions in a fraction of the time, without the need to worry about building both the smart contract and the client endpoints.
The objective of this tutorial is to teach how to create a decentralized application using the Reach platform. Through a backend consensus network like Algorand, we will allow this game to transfer, receive value in the form of network-specific tokens, like ALGO. 
The creation of “contracts” will ensure that all the players follow the same rules on every play.

Requirements

Background

The “RAPA” game was once a very traditional Portuguese game of Jewish origin. This game has simple rules, with a small four-sided top, where the letters R, T, P and D are printed on each side and a handful of beans, money or whatever you want to play. Then just run the “RAPA” and wait for your luck.
The players decide the amount that will be placed in the middle of the table for every time they rotate the “RAPA”.
According to the letters that come out, the player performs the task.
R means “RAPA” collect all from the table.
T means “TIRA” removes only one bean or the amount previously stipulated.
P means the player must put one or the amount previously stipulated on the pile of beans.
D or leave, everything stays the same and the turn pass to the next player.
The player to start the game will need to add funds to the GameTable. Then following the rules will rotate the “RAPA” and wait for the result.
The player can connect the account using MyAlgo wallet add the funds and use the account to play. The GameTable will be provided by the user. The user must add a Game Wallet to simulate the Game table.
When the Player start the game by pressing the play button the Reach compiler automatically derives a contract for the consensus network via a connector that enforces these rules.

Steps

1.Setting up Project

First, let’s start to set up the project.
This project will be built using Visual Studio Code. The React RAPA game will be created with a tool called Create React App. This tool will require NPM, make sure you have NPM installed with Node.js 5.2 or higher.
Let’s start creating our app with the Create React App tool. Open your Terminal on Mac or your command prompt on PC. Change your directory folder, run the following commands and hit return.

Note: If you run some error when you run this command, first run

npm cache clean --force

And then create your app.

npx create-react-app myrapagame
cd myRapaGame
npm start

EditorImages/2021/11/21 12:53/s101.png

Figure 1 Create React

2. External installs

Now we need to install other libraries and we need to do all the work by ourselves.
In this project, we need to install the following React Component Libraries. Don’t be scared about the installations we need to accomplish this is what we do when working on the web. That’s the way it is.

React Icons

npm install react-icons

Tailwind CSS
A framework to make your app look great.

npm install -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9 @tailwindcss/forms

EditorImages/2021/11/21 12:55/s201.png

Figure 2-1 Tailwind CSS

CRACO
Because the current version of the Create React App doesn’t yet support PostCSS 8, one more utility must be installed (CRACO).

npm install @craco/craco

Open your project on Visual Studio Code. We need to modify our package.json and add these scripts so we can use CRACO.

"start": "craco start",
"build": "craco build”
"test": "craco test”,

EditorImages/2021/11/21 12:59/s202.png

Figure 2-2 CRACO

On your app in Visual Studio Code create a craco.config.js file, and add the following.

module.exports = {
    style: {
      postcss: {
        plugins: [
          require('tailwindcss'),
          require('autoprefixer'),
        ],
      },
    },

EditorImages/2021/11/21 12:59/s203.png

Figure 2-3 CRACO Config

Another installation requires the Tailwind CSS plugin and Autoprefixer, which were part of the installation that we did earlier. We are almost there.

npx tailwindcss init

EditorImages/2021/11/21 13:01/s204.png

Figure 2-4 Tailwind CSS plugin

Now that we create the tailwind.config.js, let’s configure and customize Tailwind CSS.

purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
...
plugins: [ require('@tailwindcss/forms')]

EditorImages/2021/11/21 13:02/s205.png

Figure 2-5 Tailwind Config

We need to change our CSS file because tailwind needs three different sorts of sub-components. Open up the index.css file and just replace everything with these three lines of code.

@tailwind base;
@tailwind components;
@tailwind utilities;

EditorImages/2021/11/21 13:03/s206.png

Figure 2-6 index.css

3. Reach Installation

Next, we need to install Reach JavaScript standard library, stdlib, using the terminal with this command.

Note: First, make sure you install Docker on Mac or Windows with Docker Desktop.

First, and in the right folder “cd my-app”, install Reach by running on the terminal:

 curl https://docs.reach.sh/reach -o reach ; chmod +x reach

EditorImages/2021/11/21 13:07/s301.png

Figure 3-1 Reach

Second, and in the right folder “cd my-app”, install Reach JavaScript standard library by running on the terminal:

npm install @reach-sh/stdlib@latest

EditorImages/2021/11/21 13:07/s302.png

Figure 3-2 Reach stdlib

To run your app with Reach you need to check if everything is aligned. If Reach stdlib doesn’t match you need to run the following commands by order.
docker system prune > ./reach docker-reset > ./reach upgrade > ./reach update one after another should get everything aligned.

EditorImages/2021/11/21 13:11/s303.png

Figure 3-3 Reach stdlib version

The final step and the most important, can you believe it.
First, make sure you are in your /src folder, than run

 curl https://docs.reach.sh/reach -o reach ; chmod +x reach

To run your app on a web browser we need to compile your Reach program index.rsh to the backend and build artefact build/index.main.mjs running ./reach compile. Don´t forget to compile you need Docker Running. After the build was generated you can close Docker.

   ./reach compile

4. MyAlgo Wallet

The Reach team are frequently adding new features, so be sure you are running the last version.

Now on Reach, it can provide a wallet that directly connects to the Algorand network.

Start to import Reach library and MyAlgoConnect for Algorand in our App.js file.

import * as backend from './build/index.main.mjs';
import MyAlgoConnect from "@reach-sh/stdlib/ALGO_MyAlgoConnect";
import { loadStdlib } from '@reach-sh/stdlib';

Second, need to specified the network connection and the key to set the wallet fallback to be My Algo used with Algorand TestNet.

const stdlib = loadStdlib("ALGO");

stdlib.setWalletFallback(
  stdlib.walletFallback({
    providerEnv: "TestNet",
    MyAlgoConnect,
  })
);

EditorImages/2021/11/21 13:17/s401.png

Figure 4 MyAlgo Wallet

5. RAPA Animation

In our rapagame App.js file, we start to import all the assets needed for the game.
On the /src folder, I create an images folder add my images.
Then on App.js import all the assets.

import rapalogo from "../src/imgs/rapalogo.png";
import deixa from "../src/imgs/deixa.png";
import poemimg from "../src/imgs/poem.png";
import rapaimg from "../src/imgs/rapa.png";
import tiraimg from "../src/imgs/tira.png";
import rapas from "../src/imgs/rapas.jpg";

EditorImages/2021/11/21 13:19/s501.png

Figure 5-1 Assets

React components will re-render, so we will incorporate the useState and useEffect hook from the React library. A hook is a function that allows you to add functionality to a component. This just simply renders a status from the game.

import React, { useState, useEffect } from 'react';

Add the game variables.

var addr = "Hello";
var addrGameWallet = "Hello";
var balAtomic = "balance";

var balAtomicGameWallet = "balance";
var roll = 0;
var hand = 0;
var WagerValue = 0;

var playerpaytoplay = false;
var poem = 2;
var tira = 0;
var rapa = 0;
var gameWalletBalance = '';
var fmtGameWallet = '';
var fmt = '';

useState hook and useEffect
A hook is a function that allows you to add some functionality to the component. And useState is a built-in hook that we can use to handle state changes in our application. The useEffect is going to allow us to perform side effects inside of our function components. This will be added inside our “ComponentDidMount1” Function.

const [Aliceplayer, setAliceplayer] = useState('');
  useEffect(() => {

  }, [Aliceplayer]);

  const [alicePublicKey, setalicePublicKey] = useState('');
  useEffect(() => {

  }, [alicePublicKey]);

  const [walletG, setWalletG] = useState('');
  useEffect(() => {

  }, [walletG]);

  const [rapalist, setRapaValue] = useState();

  useEffect(() => {


  }, [rapalist]);

  const [rapaRound, setrapaRound] = useState();

  useEffect(() => {


  }, [rapaRound]);

  const [tablegamevalue, settableGameValue] = useState();

  useEffect(() => {


  }, [tablegamevalue]);

  const [input, setInput] = useState('');

Rapa Animation
I’m going to create a Rapa function here and I’ll pass props, or properties is an object in React that contains properties about the component.
The property now can be accepted dynamically anytime the value change and can be displayed on the screen.

function Rapa(props) {

  if (props.list === 0) {

    return <img src={poemimg} height={200} alt="Algorand Blockchain" />;

  } else if (props.list === 1) {

    return <img src={tiraimg} height={200} alt="Algorand Blockchain" />;

  } if (props.list === 2) {

    return <img src={rapaimg} height={200} alt="Algorand Blockchain" />;

  } if (props.list === 3) {

    return <img src={deixa} height={200} alt="Algorand Blockchain" />;

  } else {

    return <img src={rapas} height={200} alt="Algorand Blockchain" />;
  }

}

EditorImages/2021/11/21 13:25/s503.png

Figure 5-2 Rapa Faces

Inside our “ComponentDidMount1” Function will put “rapaAnimation”
Function. In this step, the game will simulate the RAPA roll and generate one of the possible odds “P”, “T”, “R” and “D”.
A setTimeout will be added so the player can see the result before “getGameResult” Function was called.

function rapaAnimation() {
    if (playerpaytoplay === true) {
      (async () => {
        const accgameWalletUpdate = await stdlib.newAccountFromMnemonic(input);
        const balAtomicGameWalletUpdate = await stdlib.balanceOf(
          accgameWalletUpdate
        );
        const gameWalletBalanceUpdate = stdlib.formatCurrency(
          balAtomicGameWalletUpdate,
          4
        );
        setWalletG(gameWalletBalanceUpdate);
      })();

      setTimeout(getGameResult, 2000);

      let counter = 0;
      const interval = setInterval(() => {
        counter += 1;
        if (counter >= 15) clearInterval(interval);
        roll = Math.floor(Math.random() * 4);

        setRapaValue(roll);

        //console.log(roll);

        playerpaytoplay = false;
      }, 100);
    } else {
      console.log("add funds to play");

      playerpaytoplay = false;
      alert("Add Funds to Play!");
    }
  }

EditorImages/2021/12/10 01:02/s503.png

Figure 5-3 Rapa Animation

6. Add Funds

First, in rapagame App.js file, we start to import all the assets needed for the game. Before any Player can start roll the RAPA must follow the rules. The first rule each Player needs to find the Game Table with 10 Algos and then the Player can roll the RAPA.

Now, connect MyAlgo Wallet.
We need to set the default account to MyAlgo Wallet. For Tutorial proposes all The players choose and agree to add a wallet as the Game Table so can all the players can add and get the funds. On A input field is added on the app Web Screen to insert the mnemonic account for the Game Table.
Reach will perform the transaction with the transfer expression. The “stdlib.transfer” will perform a transfer of network tokens from the Default Account “accAlice” to the receiver account “accgameWallet” with the amount established “MICROALGOS”.

async function foundGameTableAccount() {

    if (input !== "") {
      const MICROALGOS = '10000000';
      const accAlice = await stdlib.getDefaultAccount();

      const accgameWallet = await stdlib.newAccountFromMnemonic(input);
      const balAtomic = await stdlib.balanceOf(accAlice);
      const balAtomicGameWallet = await stdlib.balanceOf(accgameWallet);
      console.log(balAtomicGameWallet);
      await stdlib.transfer(accAlice, accgameWallet, MICROALGOS);
      console.log(balAtomic);
      gameWalletBalance = stdlib.formatCurrency(balAtomicGameWallet, 4);

      setWalletG(gameWalletBalance);
      playerpaytoplay = true;

      alert("Game Table Funded!");

    } else {

      playerpaytoplay = false;
      alert("Mnemonic input is empty!");

    }
  }

EditorImages/2021/11/21 14:51/s601.png

Figure 6 Add funds

7. Front-end Game

Now we define an asynchronous function and create the body of our game. The player “accAlice” and the Game Table as “accgameWallet” are the accounts that will be used on this game.
The balance will be set so it can be rendered on screen as the player public key on the game.

EditorImages/2021/11/21 14:52/s701.png

Figure 7-1 The player

Contract
Each participant will attempt to deploy a contract for an application. Reach defines that to interact with a deployed contract, you must construct a contract handle from an account.

The Odds

The constants defined here for the arrays that hold the meaning of the results from the game, I maintain the variables names as the Reach docs tutorial.
You can check at this link .

The variables are now implemented.

EditorImages/2021/12/10 01:17/s702.png

Figure 7-2 The Odds

Promise
A promise is an object that represents the eventual result of an asynchronous operation.
In this step, the application will wait for the operation to complete and track its status.

EditorImages/2021/12/10 01:18/s703.png

Figure 7-3 Promise

import rapalogo from "../src/imgs/rapalogo.png";
import deixa from "../src/imgs/deixa.png";
import poemimg from "../src/imgs/poem.png";
import rapaimg from "../src/imgs/rapa.png";
import tiraimg from "../src/imgs/tira.png";
import rapas from "../src/imgs/rapas.jpg";
import React, { useState, useEffect } from "react";

import * as backend from "./build/index.main.mjs";
import MyAlgoConnect from "@reach-sh/stdlib/ALGO_MyAlgoConnect";
import { loadStdlib } from "@reach-sh/stdlib";
const stdlib = loadStdlib("ALGO");

stdlib.setWalletFallback(
  stdlib.walletFallback({
    providerEnv: "TestNet",
    MyAlgoConnect,
  })
);

var addr = "Hello";
var addrGameWallet = "Hello";
var balAtomic = "balance";

var balAtomicGameWallet = "balance";
var roll = 0;
var hand = 0;
var WagerValue = 0;

var playerpaytoplay = false;
var poem = 2;
var tira = 0;
var rapa = 0;
var gameWalletBalance = "";
var fmtGameWallet = "";
var fmt = "";

function Rapa(props) {
  if (props.list === 0) {
    return <img src={poemimg} height={200} alt="Algorand Blockchain" />;
  } else if (props.list === 1) {
    return <img src={tiraimg} height={200} alt="Algorand Blockchain" />;
  }
  if (props.list === 2) {
    return <img src={rapaimg} height={200} alt="Algorand Blockchain" />;
  }
  if (props.list === 3) {
    return <img src={deixa} height={200} alt="Algorand Blockchain" />;
  } else {
    return <img src={rapas} height={200} alt="Algorand Blockchain" />;
  }
}

function ComponentDidMount1(props) {
  async function foundGameTableAccount() {
    if (input !== "") {
      const MICROALGOS = "10000000";
      const accAlice = await stdlib.getDefaultAccount();

      const accgameWallet = await stdlib.newAccountFromMnemonic(input);
      const balAtomic = await stdlib.balanceOf(accAlice);
      const balAtomicGameWallet = await stdlib.balanceOf(accgameWallet);
      console.log(balAtomicGameWallet);
      await stdlib.transfer(accAlice, accgameWallet, MICROALGOS);
      console.log(balAtomic);
      gameWalletBalance = stdlib.formatCurrency(balAtomicGameWallet, 4);

      setWalletG(gameWalletBalance);
      playerpaytoplay = true;
      console.log(gameWalletBalance);
      alert("Game Table Funded!");
    } else {
      playerpaytoplay = false;
      alert("Mnemonic input is empty!");
    }
  }

  function rapaAnimation() {
    if (playerpaytoplay === true) {
      (async () => {
        const accgameWalletUpdate = await stdlib.newAccountFromMnemonic(input);
        const balAtomicGameWalletUpdate = await stdlib.balanceOf(
          accgameWalletUpdate
        );
        const gameWalletBalanceUpdate = stdlib.formatCurrency(
          balAtomicGameWalletUpdate,
          4
        );
        setWalletG(gameWalletBalanceUpdate);
      })();

      setTimeout(getGameResult, 2000);

      let counter = 0;
      const interval = setInterval(() => {
        counter += 1;
        if (counter >= 15) clearInterval(interval);
        roll = Math.floor(Math.random() * 4);

        setRapaValue(roll);

        //console.log(roll);

        playerpaytoplay = false;
      }, 100);
    } else {
      console.log("add funds to play");

      playerpaytoplay = false;
      alert("Add Funds to Play!");
    }
  }

  function getGameResult() {
    tira = Math.round(gameWalletBalance * 0.1);
    rapa = Math.round(gameWalletBalance * 0.8);

    console.log("The value of poem is " + poem);
    console.log("The value of tira is " + tira);
    console.log("The value of rapa is " + rapa);

    hand = roll;

    if (roll === 0) {
      WagerValue = poem;
      settableGameValue(WagerValue);
    } else if (roll === 1) {
      WagerValue = tira;
      settableGameValue(WagerValue);
    } else if (roll === 2) {
      WagerValue = rapa;
      settableGameValue(WagerValue);
    } else if (roll === 3) {
      WagerValue = 0;
      settableGameValue(WagerValue);
    } else {
      WagerValue = 0;
      settableGameValue(WagerValue);
    }
    //console.log(WagerValue);
    console.log("!!!!The value of wagervalue is " + WagerValue);
    console.log("!!!!The value of hand is " + hand);
    console.log("pay to play");
    console.log(playerpaytoplay);

    (async () => {
      const accAlice = await stdlib.getDefaultAccount();
      const accgameWallet = await stdlib.newAccountFromMnemonic(input);

      addr = stdlib.formatAddress(accAlice.getAddress());
      addrGameWallet = stdlib.formatAddress(accgameWallet.getAddress());
      console.log(addr);
      console.log(addrGameWallet);
      balAtomic = await stdlib.balanceOf(accAlice);
      fmt = (x) => stdlib.formatCurrency(balAtomic, 4);
      balAtomicGameWallet = await stdlib.balanceOf(accgameWallet);
      fmtGameWallet = (x) => stdlib.formatCurrency(balAtomicGameWallet, 4);

      setAliceplayer(fmt);
      setalicePublicKey(addr);
      setWalletG(fmtGameWallet);

      const getBalance = async (who) => fmt(await stdlib.balanceOf(who));
      console.log(getBalance);

      const getBalanceGameWallet = async (who) =>
        fmtGameWallet(await stdlib.balanceOf(who));
      console.log(getBalanceGameWallet);

      const beforeAlice = await getBalance(accAlice);

      const beforeGameWallet = await getBalanceGameWallet(accgameWallet);
      console.log(beforeAlice);
      console.log(beforeGameWallet);

      const ctcAlice = accAlice.contract(backend);
      console.log(ctcAlice);
      const ctcGameWallet = accgameWallet.contract(backend, ctcAlice.getInfo());
      console.log(ctcGameWallet);

      const HAND = ["Poem", "Tira", "Rapa", "Deixa"];
      const OUTCOME = ["Alice poem", "Alice tira", "Alice rapa", "Alice deixa"];

      const Player = (Who) => ({
        ...stdlib.hasRandom, // <--- new!
        getHand: () => {
          const hand = roll;

          console.log(`${Who} played ${HAND[hand]}`);
          setrapaRound(`${HAND[hand]}`);
          return hand;
        },

        seeOutcome: (outcome) => {
          console.log(`${Who} saw outcome ${OUTCOME[outcome]}`);
        },
         informTimeout: () => {
          console.log(`${Who} observed a timeout`);
          }, 

      });

      await Promise.all([
        backend.Alice(ctcAlice, {
          ...Player("Alice"),

          wager: stdlib.parseCurrency(WagerValue),
          deadline: 10,
        }),

        backend.GameWallet(ctcGameWallet, {
          ...Player("GameWallet"),

          acceptWager: (amt) => {
            console.log(
              `Game Table accepts Alice play result of ${fmtGameWallet(amt)}.`
            );
          },
        }),
      ]);

      const afterAlice = await getBalance(accAlice);
      const afterGameWallet = await getBalanceGameWallet(accgameWallet);

      console.log(`Alice went from ${beforeAlice} to ${afterAlice}.`);
      console.log(
        `GameWallet went from ${beforeGameWallet} to ${afterGameWallet}.`
      );

      (async () => {
        const accgameWalletUpdate = await stdlib.newAccountFromMnemonic(input);
        const balAtomicGameWalletUpdate = await stdlib.balanceOf(
          accgameWalletUpdate
        );
        const gameWalletBalanceUpdate = stdlib.formatCurrency(
          balAtomicGameWalletUpdate,
          4
        );

        const accAliceUpdate = await stdlib.connectAccount({
          addr: addr,
        });

        const balAtomicAliceWalletUpdate = await stdlib.balanceOf(
          accAliceUpdate
        );
        const aliceBalanceUpdate = stdlib.formatCurrency(
          balAtomicAliceWalletUpdate,
          4
        );

        setWalletG(gameWalletBalanceUpdate);
        setAliceplayer(aliceBalanceUpdate);
      })();
      playerpaytoplay = false;
    })(); // <-- Don't forget these!
  } //comound2

  const [Aliceplayer, setAliceplayer] = useState("");
  useEffect(() => {}, [Aliceplayer]);

  const [alicePublicKey, setalicePublicKey] = useState("");

  useEffect(() => {}, [alicePublicKey]);

  const [walletG, setWalletG] = useState("");
  useEffect(() => {
    gameWalletBalance = walletG;
  }, [walletG]);

  const [rapalist, setRapaValue] = useState("");

  useEffect(() => {}, [rapalist]);

  const [rapaRound, setrapaRound] = useState("");

  useEffect(() => {}, [rapaRound]);

  const [tablegamevalue, settableGameValue] = useState("");

  useEffect(() => {}, [tablegamevalue]);

  const [input, setInput] = useState("");

8. Web Browser

Now we need to implement all the Styles needed to display our game on the screen.
You can check this link to customise and understand all styles used here .

EditorImages/2021/11/21 14:58/s801.png
Figure 8 The Div

 return (
    <>
      <div >

        <div className=" App container mx-auto mt-3 mb-8 font-thin">

          <img className="w-1920 h-800 md:w-1920 md:h-auto md:rounded-none rounded-full mx-auto" src={rapalogo} height={200} alt="Algorand Blockchain" />

          <div className="flex justify-center mt-6 ">
            <Rapa list={rapalist} />

          </div>
          <div className="App container mx-auto mt-8 mb-8 font-thin">

            <ul className="grid grid-cols-1 gap-4 h-24">
              <li>
                <div className="flex justify-center shadow bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 h-full ">
                  <button type="button" onClick={() => rapaAnimation()} className="transition duration-500 ease-in-out justify-center px-4 py-2 bg-blue-400 hover:bg-blue-600 text-sm text-white transform hover:-translate-y-1 hover:scale-110 ...">
                    Play RAPA
                  </button>

                </div>
              </li>
            </ul>

          </div>
          <ul className="grid grid-cols-2 gap-4 h-48">
            <li>
              <div className="shadow bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 h-full ">


                <div className="font-light text-4xl align-middle mb-2">Please Specify Mnemonic as Table Game</div>
                <div className="py-5">
                  <input value={input} onInput={e => setInput(e.target.value)} className=" focus:border-normal-blue-700 focus:ring-2 focus:ring-light-blue-700 focus:outline-none w-full text-sm text-black placeholder-gray-500 border border-gray-400 rounded-md py-2 pl-10" type="password" aria-label="Filter projects" placeholder="Insert Mnemonic as Table Game " />
                </div>

                <div className="font-light text-xl align-middle mb-2">Add 10 Algos on the Game Table to play</div>


                <div className="py-2">
                  <button type="button" onClick={() => foundGameTableAccount()} className="transition duration-500 ease-in-out justify-center px-4 py-2 bg-blue-400 hover:bg-blue-600 text-sm text-white transform hover:-translate-y-1 hover:scale-110 ...">
                    Add Founds
                  </button>
                </div>


              </div>
            </li>
            <li>
              <div className="shadow bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 h-full">

                <div className="font-light text-4xl align-middle mb-2">Game Status</div>

                <div className="ring-blue-500 ring-4 text-center rounded-md p-2 my-4">Result from game round: {tablegamevalue} Algos</div>
                <div className="ring-blue-500 ring-4 text-center rounded-md p-2 my-4">Total Amount in Game Table: {walletG} Algos</div>
                <div className="text-left">
                  <div className="font-light text-1xl align-middle mb-2">Player Result</div>
                  <div className="ring-blue-500 ring-4 text-center rounded-md p-2 my-4">Total Amount in Player Wallet:{Aliceplayer} Algos</div>

                </div>

              </div>
            </li>
            <li>
              <div className="shadow bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 h-full">
                <div className="text-xl font-semibold font-mono whitespace-nowrap px-1 py-1 ml-1 rounded text-white bg-red-700 rounded-2">Game Rules</div>

                <ul className="list-inside list-disc">
                  <li>Each player add 10 algo to the Game Wallet</li>
                  <li>When Get <span className="font-bold">P</span> the player Add 2 algo on the Game Wallet</li>
                  <li>When Get <span className="font-bold">T</span> the player Take 10% algo from the Game Wallet</li>
                  <li>When Get <span className="font-bold">R</span> the player Take 80% algo from the Game Wallet</li>
                  <li>When Get <span className="font-bold">D</span> pass your turn to the next Player</li>

                </ul>

              </div>
            </li>
            <li>
              <div className="shadow bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 h-full">
                <div className="font-light text-xl align-middle mb-2">Other Info</div>


                <h1> Player in game: <span className="font-bold">{alicePublicKey}</span> </h1>
                <h1>Player played <span className="font-bold">{rapaRound}</span></h1>

              </div>
            </li>
            <li>
              <div className="col-span-1 bg-white rounded-lg whitespace-nowrap px-2 py-1 ml-1 mt-4 mb-8 h-full">
                <p className="text-md leading-tight">Mario Fernandes 2021 </p>

              </div>

            </li>

          </ul>

        </div>

      </div>
    </>
  );

9. index.rsh

Start to create a file named index.rsh. As you can check the file was created inside of the /src folder.
First, we need to set at the top of the file that is a Reach program.

 'reach 0.1’;

Second, the main export what Reach compiler will look at.

export const main = Reach.App(() => {}

Assertation
To ensure that we computed the correct value, we need to implement assertions like the following.
Define the rules of RAPA Game.

const [ isHand, Poem, Tira, Rapa, Deixa ] = makeEnum(4);
const [ isOutcome, Alice_poem, Alice_tira, Alice_rapa, Alice_deixa ] = makeEnum(4);


 const winner = (handAlice) =>
   handAlice;

Define the rules of RAPA Game.
Check the response as expected.

 assert(winner(Poem) == Alice_poem);
 assert(winner(Tira) == Alice_tira);
 assert(winner(Rapa) == Alice_rapa);
 assert(winner(Deixa) == Alice_deixa);

At this step, we get the numbers declared on the frontend.

const Player = {
  getHand: Fun([], UInt),
  seeOutcome: Fun([UInt], Null),
  informTimeout: Fun([], Null),

};

Now we specify the players. Alice as the first participant and GameWallet as the game table participant.
Alice will provide the amount as the “wager” that will share between the two players.
GameWallet is a method called acceptWager that can get the wager value.
Now we can deploy and start writing our program.

 const Alice = Participant('Alice', {
        ...Player,

        // Specify Alice's interact interface here
        wager: UInt,
        // time delta (blocks/rounds)
       deadline: UInt,

        });

        //alice play game and collect the wager or pays the wager

       const GameWallet = Participant('GameWallet', {
        ...Player,
        // Specify Alice's interact interface here

        //gametable  collect the wager or pays the wager

        acceptWager: Fun([UInt], Null),
    }); 

            deploy();

informTimeout
informTimeout method, this timeout clause ensure a returned wager to all participants if any of the participants have not accepted or played within a certain amount of time.

const informTimeout = () => {
              each([Alice, GameWallet], () => {
                interact.informTimeout();
              });
            }; 

The next block of code defines something that only each of the participant perform.
 Alice.only()
 We have two variables the “wager” as the amount played on the front-end. The “handAlice” is a value that Alice got on the roll RAPA. 
Alice now joins the application by publishing the value to the consensus network. 
Next, Alice shares and can transfer the amount as part of the publication and commit the state of the consensus network.

 Alice.only(() => {

    const wager = declassify(interact.wager);

    const deadline = declassify(interact.deadline);

  });

  Alice.publish(wager,handAlice, deadline)

  .pay(wager);

  commit();

GameWallet participant, show and accept the wager. GameWallet doesn’t play but the participant can accept and transfer his funds.
The timeout specifies that if GameWallet does not achieve this action on time (time delta of deadline), all the funds are transferred to Alice back.

 GameWallet.only(() => {

  interact.acceptWager(wager);

 });

 GameWallet.pay(wager)
 .timeout(relativeTime(deadline), () => closeTo(Alice, informTimeout));

The DApp will be running in a consensus step and the contract itself now will compute the outcome and commit the state.
It will run twice and transfer the corresponding amounts based on the outcome result. This transfer takes place from the contract to the participants, not from the participants to each other because all of the funds reside inside of the contract.

const outcome = winner(handAlice);


if (outcome === 0) {
  transfer(wager).to(GameWallet); 
} else if (outcome === 1) {
  transfer(wager).to(Alice); 
}else if (outcome === 2) {
  transfer(wager).to(Alice); 
}else if (outcome === 3) {
  transfer(wager).to(Alice); 
}else {
  transfer(wager).to(Alice); 
}



if (outcome === 0) {
  transfer(wager).to(GameWallet); 
} else if (outcome === 1) {
  transfer(wager).to(Alice); 
}else if (outcome === 2) {
  transfer(wager).to(Alice); 
}else if (outcome === 3) {
  transfer(wager).to(Alice); 
}else {
  transfer(wager).to(Alice); 
}


commit();

    each([Alice, GameWallet, ], () => {
interact.seeOutcome(outcome);

});  

10.Run and Test

In order to run your app on a web browser we need to compile your Reach program index.rsh to the backend and build artifact build/index.main.mjs with:
   ./reach compile
   Note: make sure you are in your /src folder.

Then hit run with the CRACO start script.

EditorImages/2021/11/21 15:03/s1001.png

Figure 10-1 Craco Run

Note: Fund your account Using Dispenser - TestNet Dispenser link

For TestNet with Reach, we need to fund the account that you want to use as the sender (“getDefaultAccount()”).

Now we are ready to start debugging our project.

EditorImages/2021/11/21 16:05/s1002.png

Figure 10-1 Web App

EditorImages/2021/11/21 16:06/s1003.png

Figure 10-1 Result

11. Github Project

Go to the following link and try the full project.
https://github.com/3dlifee/rapagame.git

Thanks.

This tutorial is intended for learning purposes only. It does not cover error checking and other edge cases. Therefore, it should not be used as a production application