MENU

LINE Botで4択クイズを作ってみたお話[GAS]

 

LINEBotに興味を持ったこの頃。何か面白いものが作れないかと悩んでいました。

そこでLINEBotの定番(?)のクイズアプリを作ってみることにしました。

 

下準備(LINE)

まずはLINE Messaging APIのページにログインします。

developers.line.biz

プロバイダーを作成してください。Botの作成者のようなものです。



Messaging APIを選択してください

流れにそってチャネルを作っていき、Messaging API設定のタブへ行き、

応答メッセージの設定を無効化してください

以上でLINE側の設定はほぼ終わりです。

下準備(GAS)

Google Spreadsheetにアクセスし、新しいスプレッドシートを作成してください。

docs.google.com

シートに

のように好きな問題を設定してください。

コードの設定

設定したら、拡張機能→App Scriptを開きます。

以下のコードをコード.gsコピペしてください。

// LINE developersのメッセージ送受信設定に記載のアクセストークン
const ACCESS_TOKEN = アクセストークン';

// スプレッドシートのID
const SPREADSHEET_ID = 'シートID';

// スプレッドシートのシート名
const SHEET_NAME = 'シート名';

// スプレッドシートから問題と正解を取得する関数
function getQuestionsAndAnswers() {
  // スプレッドシートを開く
  const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  // シートを取得する
  const sheet = spreadsheet.getSheetByName(SHEET_NAME);
  // データの範囲を取得する
  const range = sheet.getDataRange();
  // データを二次元配列として取得する
  const values = range.getValues();
  // ヘッダー行を除く
  values.shift();
  // 問題と正解のオブジェクトの配列に変換する
  const questionsAndAnswers = values.map(row => {
    return {
      question: row[0],
      choices: row.slice(1, 5),
      answer: row[5]
    };
  });
  // 結果を返す
  return questionsAndAnswers;
}

// LINEからWebhookで受信したデータを処理する関数
function doPost(e) {
  // Webhookで受信した応答用Token
  const replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  // ユーザーID
  const userId = JSON.parse(e.postData.contents).events[0].source.userId;
  // ユーザーのメッセージを取得
  const userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  
  // クイズの状態を管理するオブジェクト(プロパティストアに保存)
  const quizState = PropertiesService.getScriptProperties();
  
  // クイズが開始されているかどうか判定する
  if (quizState.getProperty(userId)) {
    // クイズが開始されている場合
    
    // 現在の問題番号とスコアを取得する
    const currentQuestionIndex = Number(quizState.getProperty(userId + '_currentQuestionIndex'));
    const score = Number(quizState.getProperty(userId + '_score'));
    
    // 問題と正解のデータを取得する
    const questionsAndAnswers = getQuestionsAndAnswers();
    
    // 現在の問題と正解を取得する
    const currentQuestion = questionsAndAnswers[currentQuestionIndex];
    const currentAnswer = currentQuestion.answer;
    
    // ユーザーが「終了」と言ったらクイズを終了する(追加した部分)
    if (userMessage === '終了') {
      // 終了メッセージを送信する
      replyLine(replyToken, `クイズを終了します。😊\nあなたの正解数は${score}問でした!🎉`);
      // クイズの状態をリセットする
      quizState.deleteProperty(userId);
      quizState.deleteProperty(userId + '_currentQuestionIndex');
      quizState.deleteProperty(userId + '_score');
      return; // 関数を終了する
    }
    
    // ユーザーの回答が正解かどうか判定する
    if (userMessage === currentAnswer) {
      // 正解の場合
      
      // スコアを加算する
      const newScore = score + 1;
      quizState.setProperty(userId + '_score', newScore);
      
      // 正解メッセージを送信する
      replyLine(replyToken, '正解です!👏');
      
      // 次の問題があるかどうか判定する
      if (currentQuestionIndex < questionsAndAnswers.length - 1) {
        // 次の問題がある場合
        
        // 問題番号を更新する
        const nextQuestionIndex = currentQuestionIndex + 1;
        quizState.setProperty(userId + '_currentQuestionIndex', nextQuestionIndex);
        
        // 次の問題を送信する
        sendQuestion(userId, questionsAndAnswers[nextQuestionIndex]);
        
      } else {
        // 次の問題がない場合
        
        // クイズ終了メッセージを送信する(修正した部分)
        replyLine(replyToken, `すべての問題に回答しました!😊\nあなたの正解数は${newScore}問です!🎉`);
        
        // クイズの状態をリセットする
        quizState.deleteProperty(userId);
        quizState.deleteProperty(userId + '_currentQuestionIndex');
        quizState.deleteProperty(userId + '_score');
        
      }
      
    } else {
      // 不正解の場合
      
      // 不正解メッセージを送信する
      replyLine(replyToken, `残念、不正解です...😢\n正解は${currentAnswer}でした。`);
      
      // 次の問題があるかどうか判定する
      if (currentQuestionIndex < questionsAndAnswers.length - 1) {
        // 次の問題がある場合
        
        // 問題番号を更新する
        const nextQuestionIndex = currentQuestionIndex + 1;
        quizState.setProperty(userId + '_currentQuestionIndex', nextQuestionIndex);
        
        // 次の問題を送信する
        sendQuestion(userId, questionsAndAnswers[nextQuestionIndex]);
        
      } else {
        // 次の問題がない場合
        
        // クイズ終了メッセージを送信する(修正した部分)
        replyLine(replyToken, `すべての問題に回答しました!😊\nあなたの正解数は${score}問です!🎉`);
        
        // クイズの状態をリセットする
        quizState.deleteProperty(userId);
        quizState.deleteProperty(userId + '_currentQuestionIndex');
        quizState.deleteProperty(userId + '_score');
        
      }
      
    }
    
  } else {
    // クイズが開始されていない場合
    
    // ユーザーが「クイズ」と言ったらクイズを開始する
    if (userMessage === 'クイズ') {
      
      // 問題と正解のデータを取得する
      const questionsAndAnswers = getQuestionsAndAnswers();
      
      // 最初の問題を取得する
      const firstQuestion = questionsAndAnswers[0];
      
      // クイズ開始メッセージを送信する
      replyLine(replyToken, '英単語の四択クイズを始めます!👍\n「終了」と言ったらクイズを終了します。');
      
      // 最初の問題を送信する
      sendQuestion(userId, firstQuestion);
      
      // クイズの状態を設定する
      quizState.setProperty(userId, true); // クイズ中であることを示すフラグ
      quizState.setProperty(userId + '_currentQuestionIndex', 0); // 現在の問題番号(0から始まる)
      quizState.setProperty(userId + '_score', 0); // 現在のスコア
      
    } else if (userMessage === '終了') {
      
      // 終了メッセージを送信する
      replyLine(replyToken, 'クイズはまだ始まっていません。😅');
      
    } else {
      
      // それ以外のメッセージの場合
      
      // ヘルプメッセージを送信する
      replyLine(replyToken, '「クイズ」と言って英単語の四択クイズを始めてください。😊');
      
    }
    
  }
  
}

  

    // 問題を送信する関数
    function sendQuestion(userId, question) {
      // ボタンテンプレートのオブジェクトを作成する
      const buttonTemplate = {
        type: 'template',
        altText: question.question,
        template: {
          type: 'buttons',
          text: question.question,
          actions: question.choices.map(choice => {
            return {
              type: 'message',
              label: choice,
              text: choice
            };
          })
        }
      };
      // メッセージオブジェクトを作成する
      const message = {
        type: 'text',
        text: '次の問題です!👇'
      };
      // メッセージとボタンテンプレートを配列に入れる
      const messages = [message, buttonTemplate];
      // LINEにメッセージを送信する
      pushLine(userId, messages);
    }

    // LINEにメッセージを送信する関数(応答用Tokenを使う)
    function replyLine(replyToken, message) {
      // メッセージオブジェクトを作成する
      const messageObject = {
        type: 'text',
        text: message
      };
      // リクエストURL
      const url = 'https://api.line.me/v2/bot/message/reply';
      // リクエストヘッダー
      const headers = {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN
      };
      // リクエストボディ
      const body = {
        replyToken: replyToken,
        messages: [messageObject]
      };
      // リクエストオプション
      const options = {
        method: 'post',
        headers: headers,
        payload: JSON.stringify(body)
      };
      // リクエストを送信する
      UrlFetchApp.fetch(url, options);
    }

    // LINEにメッセージを送信する関数(ユーザーIDを使う)
    function pushLine(userId, messages) {
      // リクエストURL
      const url = 'https://api.line.me/v2/bot/message/push';
      // リクエストヘッダー
      const headers = {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN
      };
      // リクエストボディ
      const body = {
        to: userId,
        messages: messages
      };
      // リクエストオプション
      const options = {
        method: 'post',
        headers: headers,
        payload: JSON.stringify(body)
      };
            // リクエストを送信する
      UrlFetchApp.fetch(url, options);
    }

Apps Scriptの画面でコードの一部を編集します。

LINE Messaging APIのページに戻り、アクセストークンを取得します。Messaging APIタブの最下部にあるチャネルアクセストークンの欄から、

const ACCESS_TOKEN = アクセストークン'; のアクセストークンの部分に

発行したアクセストークンを貼り付けます。

const SPREADSHEET_ID = 'シートID';のシートIDは

https://docs.google.com/spreadsheets/d/XXXXXXXXXXXXXXXXXXXX/edit#gid=0

のXの部分にあたります。

const SHEET_NAME = 'シート名';

任意の名前を設定してください。

また、左上のタブのファイル→共有→ウェブに公開の設定を忘れずに行ってください。

デプロイ

右上のデプロイボタンから、デプロイを行います。

新しいデプロイ→種類の選択⚙→ウェブアプリ

アクセスできるユーザーを全員にします。次にアクセスを承認します。

Advancedを押し、Go to ファイル名をクリック。許可をします。

デプロイが完了するとURLが生成されます。コピーして、LINE Messaging API

編集→URLを貼り付け→更新→検証を行います。

そしてWebhookの利用を許可します。以上で設定は終了です。

完成

これで完成です。実際にQRコードをスキャンして友達追加してみてください。ユーザーが「クイズ」といったらクイズを開始し、「終了」といったら成績発表が行われます。よいクイズライフをおくってください。