LoginSignup
14
0

More than 1 year has passed since last update.

はじめに

LINE を使用して じゃんけんを行うBOTを作成しました。


機能としては下記の通りです。

  • LINEのじゃんけんチャンネルをフォローする。
  • ユーザーがじゃんけんの手を発言すると、相手が応える。テキストとスタンプに対応。
  • じゃんけんの勝敗を通算で表示する。

事前準備

チャンネルトークンの発行

LINE Messaging APIにて、チャンネルを作成します。チャンネルトークンを発行します。
1. LINE Developersにログインします。
2. Create a new channelを選択します。
3. Messaging APIを選択します。
4. 必要な項目を入力して、Createでチャンネルを作成します。
5. 作成したチャンネルのMessaging APIを選択します。
6. Channel access tokenGoogleAppsScript(GAS)に設定するトークンになります。

チャンネルアクセストークンの設定

GASにて、WEBサーバーを立ち上げます。
1. Googleにログインします。
2. GoogleDriveにてGoogleAppsScriptを開いて、以下のスクリプトを実装します。

  • LINE_CHANNEL_TOKENにLINE Messaging APIで発行したトークンを指定します。
  • SSIDにスプレッドシートのIDとSSN_USERにシート名を指定します。
main.gs
/**
 * じゃんけんBOT
 */
const LINE_CHANNEL_TOKEN = '*****'; // LINE NOTIFYのアクセストークン
const SSID = '*****';
const SSN_USER = 'user'

WEBサーバーの起動

  1. GASのメニュー公開ウェブ アプリケーションとして導入...
    4.png

  2. Who has access to the app:で「Anyone, even anonymous」を選択します。
    5.png

  3. Current web app URL:がLINEのWebhook URLになります。
    6.png

Webhookの登録

LINE Messaging APIにて、GASのWEBサーバーURLをWebhookに登録します。
1. LINE Developersにログインして、作成したチャンネルを選択します。
2. Webhook settingsにWebhook URLを指定します。
15.png

  1. Verifyボタンを実行して、Successになることを確認します。 16.png

チャンネルの友達登録

  1. LINE Developersにログインして、作成したチャンネルを選択します。
  2. QR codeを読み込みます。

フォロー登録

ユーザーがチャンネルをフォローすると、LINE Messaging APIからGASにPOSTが通知されます。GASでは、フォローされたときにユーザー情報をスプレットシートに登録します。

main.gs
/**
 * POSTリクエスト
 * @param {Object} event 
 */
function doPost(event) {
    try {
        if (event.postData) {
            let reqObj = JSON.parse(event.postData.contents);
            execute(reqObj);
        }
    } catch (e) {
        console.error(e.stack);
    }
}

/**
 * イベント処理
 * @param {Object} reqObj 
 */
function execute(reqObj) {

    for (let i in reqObj.events) {
        let reqEvent = reqObj.events[i];
        console.log(reqEvent);

        switch (reqEvent.type) {
            case 'follow':
                executeFollow(reqEvent);
                break;
            case 'unfollow':
                executeUnfollow(reqEvent);
                break;
            case 'message':
                executeMessage(reqEvent);
                break;
        }
    }
}

/**
 * Followイベント処理
 * @param {Object} reqEvent 
 */
function executeFollow(reqEvent) {
    let msgList = [{
        'type': 'text',
        'text': 'スタンプまたはメッセージでじゃんけんができます。',
    }];
    sendLinePush(reqEvent.source.userId, msgList);

    let user = getUser(reqEvent.source.userId);
    if (user) {
        userSheet.getRange(user.index + 2, 3).setValue(1);
    } else {
        userSheet.appendRow([reqEvent.source.type, reqEvent.source.userId, 1, 0, 0, 0]);
    }
}

/**
 * ユーザーを取得する
 * @param {String} userId 
 */
function getUser(userId) {
    let userList = getUserList();
    for (let i in userList) {
        let user = userList[i];
        if (user.userId === userId) {
            return {
                index: parseInt(i),
                item: user
            };
        }
    }
    return null;
}

/**
 * ユーザー一覧を取得する
 */
function getUserList() {
    let userList = [];
    let lastRow = userSheet.getLastRow();
    if (1 < lastRow) {
        userList = userSheet.getRange(2, 1, lastRow, 6).getValues();
        userList = userList.map((row) => {
            return {
                type: row[0],
                userId: row[1],
                follow: row[2],
                winNum: row[3],
                loseNum: row[4],
                drawNum: row[5],
            }
        });
    }
    return userList;
}
  • execute関数では、LINE Messaging APIからの通知内容により、処理を振り分けしています。followの場合は、ユーザー情報をスプレッドシートに登録します。既に登録済みの場合は、フォローフラグをONにします。

フォロー解除

ユーザーがチャンネルのフォローを解除すると、LINE Messaging APIからGASにPOSTが通知されます。GASでは、フォロー解除されたときにユーザー情報をスプレットシートに更新します。

main.gs
/**
 * UnFollowイベント処理
 * @param {Object} reqEvent 
 */
function executeUnfollow(reqEvent) {
    let user = getUser(reqEvent.source.userId);
    if (user) {
        userSheet.getRange(user.index + 2, 3).setValue(0);
    }
}
  • execute関数では、LINE Messaging APIからの通知内容により、処理を振り分けしています。unfollowの場合は、ユーザー情報をスプレッドシートにフォローフラグをOFFに更新します。

リプライ

ユーザーがメッセージを入力するとLINE Messaging APIからGASにPOSTが通知されます。GASでは、メッセージ入力されると、その内容を解析して、じゃんけんの結果と通算を出力します。その後、LINE Messaging APIにPOSTで返します。

main.gs
/**
 * メッセージイベント処理
 * @param {Object} reqEvent 
 */
function executeMessage(reqEvent) {
    let msgList = [];
    let user = getUser(reqEvent.source.userId);
    if (user) {
        let reqHand = -1;
        switch (reqEvent.message.type) {
            case 'text':
                reqHand = getHandFromText(reqEvent.message.text);
                break;
            case 'sticker':
                reqHand = getHandFromSticker(reqEvent.message.packageId, reqEvent.message.stickerId);
                break;
        }

        if (-1 < reqHand) {
            let botHand = getRandom(0, 2);
            let judge = (reqHand - botHand + 3) % 3;

            const BOT_HAND_LIST = ['グー', 'チョキ', 'パー'];
            const RESULT_LIST = ['あいこ', 'あなたの負け', 'あなたの勝ち'];


            let winNum = user.item.winNum;
            let loseNum = user.item.loseNum;
            let drawNum = user.item.drawNum;
            switch (judge) {
                case 0:
                    drawNum++;
                    break;
                case 1:
                    loseNum++;
                    break;
                case 2:
                    winNum++;
                    break;
            }

            msgList.push({
                'type': 'text',
                'text': BOT_HAND_LIST[botHand],
            });
            msgList.push({
                'type': 'text',
                'text': `${RESULT_LIST[judge]}\n\n勝ち: ${winNum}\n負け: ${loseNum}\nあいこ: ${drawNum}`,
            });
            sendLineReply(reqEvent.replyToken, msgList);

            userSheet.getRange(user.index + 2, 4).setValue(winNum);
            userSheet.getRange(user.index + 2, 5).setValue(loseNum);
            userSheet.getRange(user.index + 2, 6).setValue(drawNum);

        } else {
            msgList.push({
                'type': 'text',
                'text': 'わからないよ\nもう一度入力してね',
            });
            sendLineReply(reqEvent.replyToken, msgList);
        }
    }
}

/**
 * テキストからの手を取得する
 * @param {String} text 
 */
function getHandFromText(text) {
    const HAND_LIST = [
        ['グー', 'ぐー', '', '👊'],
        ['チョキ', 'ちょき', '✌️', '✌️'],
        ['パー', 'ぱー', '', '🖐']
    ];
    for (let i in HAND_LIST) {
        let hand = HAND_LIST[i];
        for (let j in hand) {
            let word = hand[j];
            if (text == word) {
                return parseInt(i);
            }
        }
    }
}

/**
 * スタンプから手を取得する
 * @param {String} packageId 
 * @param {String} stickerId 
 */
function getHandFromSticker(packageId, stickerId) {
    const HAND_LIST = [
        [{
            packageId: '2000010',
            stickerId: '219905'
        }, {
            packageId: '2000000',
            stickerId: '47906'
        }],
        [{
            packageId: '2000010',
            stickerId: '219907'
        }, {
            packageId: '2000000',
            stickerId: '47904'
        }],
        [{
            packageId: '2000010',
            stickerId: '219910'
        }, {
            packageId: '2000000',
            stickerId: '47905'
        }]
    ];
    for (let i in HAND_LIST) {
        let hand = HAND_LIST[i];
        for (let j in hand) {
            let item = hand[j];
            if (item.packageId == packageId && item.stickerId == stickerId) {
                return parseInt(i);
            }
        }
    }
}

function getRandom(min, max) {
    let random = Math.floor(Math.random() * (max + 1 - min)) + min;
    return random;
}

/**
 * LINEに応答メッセージを送信する
 * @param {String} replyToken リプライトークン
 * @param {Object} msgList メッセージリスト
 */
function sendLineReply(replyToken, msgList) {
    let url = 'https://api.line.me/v2/bot/message/reply';
    let options = {
        'method': 'post',
        'headers': {
            'Content-Type': 'application/json; charset=UTF-8',
            'Authorization': `Bearer ${LINE_CHANNEL_TOKEN}`
        },
        'payload': JSON.stringify({
            replyToken: replyToken,
            messages: msgList
        })
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}
  • execute関数では、LINE Messaging APIからの通知内容により、処理を振り分けしています。messageの場合は、メッセージの内容を解析します。テキストまたはスタンプから、じゃんけんの手を割り出します。じゃんけんの演算を行い、結果と通算をsendLineReply関数でLINE Messaging APIにPOSTします。

参考リンク

さいごに

ソースコードをGitHubに公開しています。

以上です。

14
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
0