ノンプログラマーがSymbolブロックチェーンでゲームを作ってみた

この記事は [nem Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nem) 5日目の記事です。

#はじめに

プログラム経験ゼロでも、**Symbolというブロックチェーン**を利用すれば**、
Web環境とテキストメモだけ**で、ブロックチェーンゲームが作れます。

**はじめてのプログラムはSymbolブロックチェーン**から、
冬休みの学びに、是非お楽しみください。

#自己紹介

日常生活で**プログラムに一切触れない** 仕事をしつつ

[nembear(ねむぐま)](https://twitter.com/nembear)

という名前で、暗号通貨Symbol界隈で**開発以外**の活動をしております。

そんな私でも、**ほぼコピペ**でSymbolを利用した**独自のブロックチェーンゲーム**を作ることが出来たので、皆さんにも紹介します。

#本記事で作るブロックチェーンゲーム

ブロックチェーンを利用したスロットゲームを作ります。3つの数字が揃えば、**「symbol:xym」**というトークンが**送信**される仕組みです。この**トークンの送信**の部分に**Symbolのブロックチェーン**を利用します。この記事を読めば、このゲームだけでなくあなたのオリジナルブロックチェーンゲームを**ほぼコピペ**で作成することが出来るようになります。

※アドカレ用にnembearトークンがもらえるバージョンを作りました。とても簡単なゲームですので是非、遊んでください。
↓↓↓↓↓↓

http://nembear.html.xdomain.jp/NembearAdventCalendar2021.html


##必要な環境とスキル

【環境】
・インターネット接続環境
・Google Chromeブラウザ
・テキストメモ

【スキル】
・コピー＆ペースト

##開発までの流れ

１．SymbolWalletを手に入れる（約5分）

２．Symbol送金プログラムを書いて体験する（約20分）

３．ボタンを押すとSymbol送金されるWebアプリ作成(約10分）

４．スロットゲームにSymbol送金を組み合わせる（自由時間）

５．完成(自由時間）

※イメージ
１．スロットに利用するコインを保管する金庫を作ります。

２．コインの保管と金庫からコインを送信する仕組みを学びます。

３．２で学んだ仕組みを利用して、簡単なアプリを作ります。

４．上記までの学びを利用して、スロットゲームに組み込みます。

５．実際に遊んでみましょう！


#Symbolブロックチェーンゲーム作成方法

##１．SymbolWalletを手に入れる（約5分）

ここでは**スロットに利用するコインを保管する"金庫"を作ります。**
その"金庫"となるものが**「SymbolWallet」**です。これは暗号資産Symbol：XYMを保管するために最もポピュラーでセキュリティの高いWalletとなります。
テキストと動画で同じ内容の作成方法を説明します。お好みに合わせて選択してください。

■テキストでの説明はこちらから
※ポイント：リンク先の**「項目３－４」では必ず「TESTNET」**を選択してください。

https://note.com/nembear/n/n56d2c9a28e8a

■動画での説明はこちらから
※ポイント：動画内のSymbolWalletはこちらからダウンロードしてください。
↓↓↓
https://github.com/symbol/desktop-wallet/releases
<br>

<iframe width="560" height="315" src="https://www.youtube.com/embed/VrEWYXtz0Uo?start=68" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br>

##２．Symbol送金プログラムを書いて体験する（約20分）
ここでは、**コインの保管と金庫からコインを送信する仕組み** を学びます。
前項目で作成した「金庫：SymbolWallet」に、ゲーム内で利用するコインを保管します。そして保管したコインを送信するところまでを、プログラムで体験してもらいます。ここで言う**コインとはSymbolのトークンである「XYM」**です。（テスト用のXYMの為、購入する必要はありません。）

ここからSymbolブロックチェーンに触れることになりますが、すべてコピペで体験出来ます。リラックスしてお進みください。**Symbolがいかに簡単で誰にでも使いやすいものであるか**を感じてもらえますと幸いです。

※ポイント：本項目は @nem_takanobu さんの記事を参考に実施しております。以下のリンク記事を開いて動画をご覧ください。

https://qiita.com/nem_takanobu/items/e2b1f0aafe7a2df0fe1b

<br>

<iframe width="560" height="315" src="https://www.youtube.com/embed/Clp27eTdskc?start=68" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


##３．ボタンを押すとSymbol送金されるWebアプリ作成（約10分）
ここでは、**項目２で学んだ仕組みを利用して、簡単なアプリを作ります。** 先ほどはコンソール画面にコードを打ち込んで送金を体験しました。操作は簡単ではありましたが、毎回何度もあの操作を繰り返すのは大変ですよね？ですので、送信までの動作をボタン1つにまとめて、**ボタンを押せばSymbolブロックチェーンを利用して送信される**装置を作ってみましょう。

###３－１．ボタンを押すと動作が発生するベースを作る
■準備するもの
→テキストエディタ（メモ帳でOK）

■手順
１．以下のコードをすべてテキストエディタにコピペし、保存する。
２．保存したテキストの名前を「test.html」に変更する。
３．「test.html」をダブルクリックする。

早速、以下のコードをテキストエディタにコピペしましょう。

```javascript:test.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>nembear nemAdventCalendar2021</title>
</head>

<body>

    <p>button click</p>

    <input type="button" value="button" id="btn">

    <script>
        function butotnClick() {
            alert('Ok');
        }

        let button = document.getElementById('btn');
        button.addEventListener('click', butotnClick);
    </script>

</body>

</html>
```

時々質問で、↑のコードが良く分からない。という話を聞きますが、私も良く分かりません。私たちはエンジニアではないので、読める必要は無いのです。上記のサンプルも「html ボタン クリック」でWeb検索し、1番最初に上がってきた記事のサンプルを使ってます。深く考えるのはあとで、先ずは実践していきましょう。

次に、コピペしたテキストの名前を「test.html」として保存します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/8720da42-f510-3a29-f9cf-756bf6b985c8.png)
「test.html」をダブルクリックしてください。
こんな画面が出てきたと思います。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/ff49e6c3-2bcb-962a-e351-b61be438f252.png)
「button」をクリックしてみましょう。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/c9fd2884-948f-25d6-22c9-8bbeb0acdc51.png)
「Ok」のPOPが表示されました。おめでとうございます。これで、ボタンを押すと何かしら動作する（これなら「Ok」のPOPが出る）装置が完成しました。次の項目で、この装置にSymbolブロックチェーンの送金部分を投入してみましょう。

###３－２．ボタンを押すとSymbol：XYMが送信されるアプリを作る
■準備するもの
→テキストエディタ（メモ帳でOK）

■手順
１．以下のコードをすべてテキストエディタにコピペし、保存する。
２．保存したテキストの名前を「test2.html」に変更する。
３．「test2.html」をダブルクリックする。

※ポイント：先ほど作った「test.html」の中身を確認すると、以下の部分がどうやら「Ok」POPが出るための呪文のようです。（試しに、この'Ok'を他の言葉に変えると、変えた内容のPOPが出ます。）

``` 
function butotnClick() {
            alert('Ok');
        }
```
つまり、ボタンを押すと、「 alert('Ok'); 」の処理が動くということです。だとしたらば、**項目２で実施したSymbol送金のコードをすべてここに書き込めば**、ボタン押すだけで送金出来るのではないでしょうか？

早速、以下のコードをテキストエディタにコピペしましょう。

※ポイント：項目２の動画で一緒に入力していたコードをそのまま利用してます。**秘密鍵とアドレスだけ、あなたが作成したSymbolWalletのものを入力**してください。

```javascript:test2.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>nembear nemAdventCalendar2021</title>
</head>

<body>
    <!-- 設定値の定義とライブラリのインポート&ライブラリのインスタンス生成 -->
    <script src="https://xembook.github.io/nem2-browserify/symbol-sdk-1.0.1.js"></script>
    <script language="JavaScript">

        NODE = 'https://sym-test-09.opening-line.jp:3001';
        GENERATION_HASH = '7FCCD304802016BEBBCD342A332F91FF1F3BB5E902988B352697BE245F48E836';
        EPOCH_ADJUSTMENT = 1637848847;
        nem = require("/node_modules/symbol-sdk");

    </script>

    <p>button click</p>

    <input type="button" value="button" id="btn">

    <script>
        function butotnClick() {
            // アカウントの登録（自分のWalletの秘密鍵を入れてください）
            alice = nem.Account.createFromPrivateKey('あなた自身のSymbolWalletの秘密鍵を入力', nem.NetworkType.TEST_NET);
            console.log(alice);

            // トランザクション作成（自分のWalletのアドレスを入れてください）
            tx = nem.TransferTransaction.create(
                nem.Deadline.create(EPOCH_ADJUSTMENT),
                nem.Address.createFromRawAddress("あなたのSymbolアドレスを入力"),
                [new nem.Mosaic(new nem.MosaicId('3A8416DB2D53B6C8'), nem.UInt64.fromUint(1000000))],
                nem.PlainMessage.create('nemAdventCalendar2021'),
                nem.NetworkType.TEST_NET,
                nem.UInt64.fromUint(100000)
            );

            console.log(tx);
            // 署名
            signedTx = alice.sign(tx, GENERATION_HASH);

            console.log(signedTx);

            // 署名したトランザクションをネットワークにアナウンス
            new nem.TransactionHttp(NODE)
                .announce(signedTx)
                .subscribe((x) => console.log(x), (err) => console.error(err));

            alert('Ok');
        }

        let button = document.getElementById('btn');
        button.addEventListener('click', butotnClick);
    </script>

</body>

</html>
```

次に、コピペしたテキストの名前を「test2.html」として保存し、ダブルクリックして表示させてください。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/cc0978d9-670d-f567-52b7-f521f210025e.png)

「test.html」と同様の表示内容です。ですが、ボタンを押した後の処理が大きく異なります。あなたのWalletを開いたままで、ボタンを押してください。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/80d8e81e-4b04-16c5-1aeb-3bf27019c4fe.png)

「チャキン」という音と共に、あなたのWalletに**１XYMが送金されている**と思います。おめでとうございます。これであなたは、この世のどんなコードにも、Symbolブロックチェーンを繋げることが出来ました。これは嘘ではありません。**”javascript”フリーコード等で検索して出てきた世界中のコードに、Symbolブロックチェーンを繋げることが出来る**のです。では、次の章でそれを実践してみましょう。

※送信されていない場合は以下の確認をしてください。
１．すべてコピー＆ペーストしているか？
２．秘密鍵とアドレスを正しく記入しているか？
３．Web上で開いている「test2.html」が更新されているか？（F5を押す）

##４．スロットゲームにSymbol送金を組み合わせる
では早速、3章の最後に言った、**”javascript”フリーコード等で検索して出てきた世界中のコードに、Symbolブロックチェーンを繋げることが出来る**を証明したいと思います。今回はスロットゲームなので、「javascript スロットゲーム」で検索して出てきたサンプルコードを利用します。

早速出てきた「programmercollege」さんのサンプルコードを利用します。

https://programmercollege.jp/column/9113/

以下のコードをコピペし、「slot1.html」という名前で保存、起動してください。

```javascript:slot1.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>slot nemAdventCalendar2021</title>
</head>

<body>
    <h1>slot nemAdventCalendar2021</h1>

    <script language="JavaScript">

        var time1;
        var time2;
        var time3;

        // START
        function slot() {
            start1();
            start2();
            start3();
        }

        //各ランダム値を表示
        function start1() {
            document.getElementById("dat1").value = Math.floor(Math.random() * 2);
            time1 = setTimeout(start1, 10);
        }
        function start2() {
            document.getElementById("dat2").value = Math.floor(Math.random() * 2);
            time2 = setTimeout(start2, 10);
        }
        function start3() {
            document.getElementById("dat3").value = Math.floor(Math.random() * 2);
            time3 = setTimeout(start3, 10);
        }

        // STOP
        function stop1() {
            clearTimeout(time1);
        }
        function stop2() {
            clearTimeout(time2);
        }
        function stop3() {
            clearTimeout(time3);
            const textbox = document.getElementById("dat1");
            const inputValue1 = textbox.value;
            console.log(inputValue1);
            const textbox2 = document.getElementById("dat2");
            const inputValue2 = textbox2.value;
            console.log(inputValue2);
            const textbox3 = document.getElementById("dat3");
            const inputValue3 = textbox3.value;
            console.log(inputValue3);
            if (inputValue1 === inputValue2 && inputValue3 === inputValue1) {
                alert('Win');
            }
            else {
                alert('Lose');
            }
        }

    </script>

    <style>
        table,
        tr,
        td {
            border-style: none;
        }
    </style>

    <div style="background-color : rgb(214, 82, 82); padding : 20px;">
        <table>
            <tr>
                <td colspan="3">
                    <input type="button" value="START" onClick="slot()" style="width:100%;">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="text" id="dat1" value="0" style="text-align:center;font-size:30px">
                </td>
                <td>
                    <input type="text" id="dat2" value="0" style="text-align:center;font-size:30px">
                </td>
                <td>
                    <input type="text" id="dat3" value="0" style="text-align:center;font-size:30px">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="button" value="STOP" onClick="stop1()" style="width:100%;">
                </td>
                <td>
                    <input type="button" value="STOP" onClick="stop2()" style="width:100%;">
                </td>
                <td>
                    <input type="button" value="STOP" onClick="stop3()" style="width:100%;">
                </td>
            </tr>
        </table>
    </div>
    </script>
</body>

</html>
```

早速立ち上げてみましょう。
こんな感じで、startを押すと数字が変化し（便宜上０，１だけにしてます）、すべて揃えば「Win」揃わなかったら「Lose」のPOPが出力されます。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217292/a8a1b1da-6483-b488-7619-65ca06faf840.png)

3章で学んだことを思い出してください。前回は**「Ok」のPOPが表示されるきっかけ**で送金コマンドを登録してましたよね？ということは、今回も**「Win」POPが表示されるきっかけの箇所にSymbol送金コマンドを張り付けるだけ**ではないでしょうか。イメージではもう完成してませんか？Symbolって簡単すぎますよね。

それでは、ここからは是非、ご自身で書いてみてほしいですが、どうしてもうまくいかない場合は以下のサンプルコードをご利用ください。

※ポイント：**秘密鍵とアドレスだけ、あなたが作成したSymbolWalletのものを入力**してください。

```javascript:slot2.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>slot nemAdventCalendar2021</title>
</head>

<body>
    <h1>slot nemAdventCalendar2021</h1>

    <!-- 設定値の定義とライブラリのインポート&ライブラリのインスタンス生成 -->
    <script src="https://xembook.github.io/nem2-browserify/symbol-sdk-1.0.1.js"></script>
    <script language="JavaScript">

        NODE = 'https://sym-test-09.opening-line.jp:3001';
        GENERATION_HASH = '7FCCD304802016BEBBCD342A332F91FF1F3BB5E902988B352697BE245F48E836';
        EPOCH_ADJUSTMENT = 1637848847;
        nem = require("/node_modules/symbol-sdk");

        var time1;
        var time2;
        var time3;

        // START
        function slot() {
            start1();
            start2();
            start3();
        }

        //各ランダム値を表示
        function start1() {
            document.getElementById("dat1").value = Math.floor(Math.random() * 2);
            time1 = setTimeout(start1, 10);
        }
        function start2() {
            document.getElementById("dat2").value = Math.floor(Math.random() * 2);
            time2 = setTimeout(start2, 10);
        }
        function start3() {
            document.getElementById("dat3").value = Math.floor(Math.random() * 2);
            time3 = setTimeout(start3, 10);
        }

        // STOP
        function stop1() {
            clearTimeout(time1);
        }

        function stop2() {
            clearTimeout(time2);
        }
        function stop3() {
            clearTimeout(time3);
            const textbox = document.getElementById("dat1");
            const inputValue1 = textbox.value;
            console.log(inputValue1);
            const textbox2 = document.getElementById("dat2");
            const inputValue2 = textbox2.value;
            console.log(inputValue2);
            const textbox3 = document.getElementById("dat3");
            const inputValue3 = textbox3.value;
            console.log(inputValue3);
            if (inputValue1 === inputValue2 && inputValue3 === inputValue1) {

                // アカウントの登録（自分のWalletの秘密鍵を入れてください）
                alice = nem.Account.createFromPrivateKey('自分のWalletの秘密鍵を入れてください', nem.NetworkType.TEST_NET);
                console.log(alice);

                // トランザクション作成（自分のWalletのアドレスを入れてください）
                tx = nem.TransferTransaction.create(
                    nem.Deadline.create(EPOCH_ADJUSTMENT),
                    nem.Address.createFromRawAddress("自分のWalletのアドレスを入れてください"),
                    [new nem.Mosaic(new nem.MosaicId('3A8416DB2D53B6C8'), nem.UInt64.fromUint(1000000))],
                    nem.PlainMessage.create('nemAdventCalendar2021'),
                    nem.NetworkType.TEST_NET,
                    nem.UInt64.fromUint(100000)
                );

                console.log(tx);

                // 署名
                signedTx = alice.sign(tx, GENERATION_HASH);

                console.log(signedTx);

                // 署名したトランザクションをネットワークにアナウンス
                new nem.TransactionHttp(NODE)
                    .announce(signedTx)
                    .subscribe((x) => console.log(x), (err) => console.error(err));

                alert('Win');

            }
            else {

                alert('Lose');

            }
        }

    </script>

    <style>
        table,
        tr,
        td {
            border-style: none;
        }
    </style>

    <div style="background-color : rgb(214, 82, 82); padding : 20px;">
        <table>
            <tr>
                <td colspan="3">
                    <input type="button" value="START" onClick="slot()" style="width:100%;">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="text" id="dat1" value="0" style="text-align:center;font-size:30px">
                </td>
                <td>
                    <input type="text" id="dat2" value="0" style="text-align:center;font-size:30px">
                </td>
                <td>
                    <input type="text" id="dat3" value="0" style="text-align:center;font-size:30px">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="button" value="STOP" onClick="stop1()" style="width:100%;">
                </td>
                <td>
                    <input type="button" value="STOP" onClick="stop2()" style="width:100%;">
                </td>
                <td>
                    <input type="button" value="STOP" onClick="stop3()" style="width:100%;">
                </td>
            </tr>
        </table>
    </div>
    </script>
</body>

</html>
```

##５．完成（遊んでみよう！）
アナタが作った、Symbolブロックチェーンゲーム。早速遊んでみましょう。数字が揃うと、XYMが送金されていることが分かります。<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/n3sPRZT0fWA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

私が言っていた**”javascript”フリーコード等で検索して出てきた世界中のコードに、Symbolブロックチェーンを繋げることが出来る**が嘘でないことが証明されたのではないでしょうか？？例えば、シューティングゲームがあって、敵を倒した時？10,000点を超えた時？レースゲームで勝利した時？想像するだけで何でも出来そうな気になりますし、実際に出来ます。あなたの想像力にSymbolはコストゼロで寄り添います。力を貸してくれます。どうぞ、来年はこの新たな武器を手にエンジョイしてください！

#ハッカソン情報（開発イベント）
Symbol/NEMを世の中に広める活動をしているNPO法人NEMTUS内で「ハッカソン」が開催される予定です。誰でも参加出来て、ビギナーにも賞が出るという噂です。是非ここでの学びで挑戦してはいかがでしょうか？しかもテーマが「ゲーム」です！！

https://twitter.com/NemtusOfficial/status/1471676528576454656



#終わりに
いかがでしたでしょうか？**ブロックチェーンがとても近い存在**に感じられたのではないでしょうか？**Symbolはそのように設計**されてます。世界中の誰もが利用できるブロックチェーンです。ごく一部の人間だけが使えるものではありません。

あなたも今日からSymbolを利用する側になりました。ブロックチェーンでアプリケーションを作る側になりました。とても素晴らしいことです。ブロックチェーンは投資するだけのものではないことが理解できたと思います。

私はそんなSymbolで活動する方々へ、支援を続けております。
アナタの活躍に支援する日が来ることを楽しみにしております。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【こころから感謝を込めて】<br>シンくまノードは設立してから丁度半年が経ちました。そしてこの半年間で以下の支援を実施出来ました。<br>✅支援回数：24回（計47名）<br>✅総支援額：104,129XYM<br>すべての委任者の皆さんに感謝いたします🙏<br><br>※シンくまノードはこちら↓<a href="https://t.co/Ctry4cncU2">https://t.co/Ctry4cncU2</a><a href="https://twitter.com/hashtag/Smbol?src=hash&amp;ref_src=twsrc%5Etfw">#Smbol</a> <a href="https://twitter.com/hashtag/XYM?src=hash&amp;ref_src=twsrc%5Etfw">#XYM</a> <a href="https://t.co/o8uIIDG8kS">https://t.co/o8uIIDG8kS</a></p>&mdash; アドカレ12/5 元祖ねむぐま (@nembear) <a href="https://twitter.com/nembear/status/1462984611097497606?ref_src=twsrc%5Etfw">November 23, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


Symbolはいつでもあなたのそばに。

素敵な旅と幸運を。