LoginSignup
16
23

Google Apps Scriptで百人一首を検索するLINE Botを作った

Last updated at Posted at 2021-03-22

作ったもの

スマホ向けリンク

機能

以下のメッセージに反応して,百人一首の歌・番号・作者名・決まり字を返します。

  • 歌番号
  • 決まり字
  • 上の句の5文字目くらいまで(一部でも可)
  • 作者名
  • 取り札の上3文字

image.png

候補が複数ある場合には,決まり字の一覧を返します。
image.png

作った経緯

趣味で競技かるたをしており、百人一首に触れる機会が多いです。
「ちはやぶる〜の歌の作者って誰だっけ?」「歌番号40の歌って何だっけ?」
そんなときすぐ調べられたら便利だと思い,最近勉強していたGASの練習も兼ねて作ってみました。

準備

サーバーを用意する必要がなく,ブラウザ上で簡単に作れそうなので,LINE BotとGoogle Apps Script(GAS)を組み合わせて作ります。

LINE Developersに登録

登録は前にしていたので,省略します。
以下のリンクが参考になります。
参考:LINEのBot開発 超入門(前編) ゼロから応答ができるまで

「Messaging API設定」の下にある,チャンネルアクセストークン(長期)を取得しておきます。
スクリーンショット_2021-03-22_16_08_49.png

Google Apps Scriptを開く

歌のデータベース代わりにスプレッドシートを使います。

Googleドライブにログインして,Googleスプレッドシートを選択。
スクリーンショット_2021-03-22_16_14_34.png

スプレッドシートから「ツール」→「スクリプト エディタ」を選択。
スクリーンショット_2021-03-22_16_16_44.png

エディタが開くので,コードを書いていきましょう。
スクリーンショット_2021-03-22_16_17_36.png

コードを書く

言語はJavaScriptがベースになっています。

メッセージを受け取って返信する関数

メッセージを受け取り,返信メッセージを作り,送信する doPost 関数を書きます。
チャンネルアクセストークンを,ここにアクセストークンを入れますの部分にコピペします。
返信メッセージを作成する部分以外は,以下のリンク先のコードを参考にさせていただきました。

参考:Google Apps ScriptでLINE BOTつくったら30分で動かせた件

main.gs
// アクセストークン
const ACCESS_TOKEN = 'ここにアクセストークンを入れます';

function doPost(e) {
  // WebHookで受信した応答用Token
  const replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  // ユーザーのメッセージを取得
  const userMsg = JSON.parse(e.postData.contents).events[0].message.text;
  // 応答メッセージ用のAPI URL
  const url = 'https://api.line.me/v2/bot/message/reply';

  //返信メッセージを作成
  if (1 <= parseInt(userMsg) && parseInt(userMsg) <= 100) {
    var post_msg = numToMessage(parseInt(userMsg));
  } else { 
    var post_msg = wordToMessage(userMsg);
  }

  //変数post_msg を本文として返信を送る
  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': replyToken,
      'messages': [{
        'type': 'text',
        'text': post_msg ,
      }],
    }),
  });
}

歌番号から返信メッセージを作成する関数

受信メッセージが1から100までの数値の場合は,以下の処理を行います。

  1. 歌番号から該当する歌の情報を取得する
  2. 返信メッセージを返す
    そのための numToMessage 関数を用意します。

予め,以下のようなシートを作っておきます。
(シート名は「tanka_list」としました)
image.png

【追記】閲覧用リンクを貼っておきます。

numToMessage 関数のコードを書きます。

message.gs
//1から100までの歌番号から,メッセージを作成
function numToMessage(msg) {

  //tanka_listシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('tanka_list');

  //歌番号からシートの行番号を取得
  const row = get_row(msg, sheet, 'A');

  //歌番号,上の句,下の句,詠み人,決まり字を取得
  const num = sheet.getRange('A'+ row).getValue();
  const kami = sheet.getRange('B'+ row).getValue();
  const shimo = sheet.getRange('C'+ row).getValue();
  const yomibito = sheet.getRange('D'+ row).getValue();
  const kimariji = sheet.getRange('E'+ row).getValue();

  //メッセージを作成
  return kami + '\n' + shimo +'\n\n歌番号:' + num + '\n詠み人:' + yomibito + '\n決まり字:' + kimariji;
}

コード内で出てくる get_row 関数は,以下の記事のものを使わせていただきました。
参考:GASで列内で特定の値に一致する行番号を取得する - shikaku's blog

get_row.gs
//keyに一致する値をもつ行番号を返す
function get_row(key, sh, col){
  const array = get_array(sh, col);
  const row = array.indexOf(key) + 1;
  return row;
}

//シートの1列を全て配列に入れる
function get_array(sh, col){
  const last_row = sh.getLastRow();
  const range = sh.getRange(col + '1:' + col + last_row)
  const values = range.getValues();
  const array = [];
  for(let i = 0; i < values.length; i++){
    array.push(values[i][0]);
  }
  return array;
}

(例) 受信メッセージが40の場合,以下のようなメッセージを返り値として返します

しのぶれど 色に出でにけり 我が恋は
物や思ふと 人の問ふまで

歌番号:40
詠み人:平兼盛
決まり字:しの

決まり字や作者名から歌番号を取得する

受信メッセージが歌番号の数字以外の場合には,2つの場合が考えられます。

  • 歌が特定できる場合(決まり字や歌人名)は,まず歌番号を取得し,numToMessage 関数に送る
  • 歌が特定できない場合は,候補が複数あるのか,全くないのかの判定をする

そのための wordToMessage 関数を用意します。

予め,以下のようなシートを作っておきます。
(シート名は「word_list」としました)
image.png
仮名遣いによる表記揺れや作者の別名(wiki調べ)などに対応するため,800行くらい用意しました。
(本当は正規表現とかでもっと行数減らせるかもしれないですが,未確定のときにも反応してしまいそうなのでやめました)

wordToMessage 関数のコードを書きます。

message.gs
//決まり字や上の句,歌人名から,メッセージを作成
function wordToMessage(msg) {

  //word_listシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('word_list');

  //メッセージからシートの行番号を取得
  const row = get_row(msg, sheet, 'A');

  //メッセージを作成
  if (row === 0) {
    return partToMessage(msg);
  } else { 
    const num = sheet.getRange('B'+ row).getValue();
    return numToMessage(num);
  };
}

もしここでも一致しない場合には,後述する partToMessage 関数で候補を調べます。

候補が複数あるときのメッセージを作成する

受信メッセージから歌番号が確定できない場合は,以下の2通りの場合が考えられます。

  • 歌の候補が複数ある場合には,その候補を返す
  • ない場合には,'見つかりませんでした…'を返す。

そのための partToMessage 関数を用意します。

予め,以下のようなシートを作っておきます。
(シート名は「part_list」としました)
image.png
(上の句の出だしだけでなく,「六歌仙」なども入れてあります)

partToMessage 関数のコードを書きます。
行ごとに最終列の位置が異なるため,以下のようにコードを書いています。

  1. get_row 関数で該当する行番号を見つける
  2. 『「ひ」は3枚あります』のような文字列 kouho を作る
  3. 該当行の最終列の値を取得し,定数 lastCol に代入
    参考:もりさんのプログラミング手帳
  4. for文で3列目から最終列までの値を kouho の後ろに加えていく
  5. kouho の値を返す
message.gs
//確定できない場合に,候補の札を示すメッセージを作成
function partToMessage(msg) {

  //part_listシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('part_list');

  //メッセージからシートの行番号を取得
  const row = get_row(msg, sheet, 'A');

  //メッセージを作成
  if (row === 0) {
    return '見つかりませんでした…';
  } else { 
    const num = sheet.getRange('B'+ row).getValue();
    let kouho = '' + msg + '」は,' + num + '枚あります。';
    const lastCol = sheet.getRange(row, 3).getNextDataCell(SpreadsheetApp.Direction.NEXT).getColumn();

    for (i = 3; i <= lastCol; i++) {
      let fuda = sheet.getRange(row, i).getValue();
      kouho = kouho.concat('\n' + fuda);
    }

    return kouho;
  };
}

アプリを公開する

公開して,LINE Botとして使えるようにするには,デプロイして利用できる状態にしたあと,LINE DevelopersでWebhookの設定をする必要があります。

デプロイする

右上の「デプロイ」から「新しいデプロイ」を選択します。
スクリーンショット_2021-03-22_18_06_10.png

種類を「ウェブアプリ」に,アクセスできるユーザーを「全員」に設定してから「デプロイ」します。
image.png

(初回は,アクセス権の承認画面が出てきます)

出てきたウェブアプリのURLをコピーします。
image.png

Webhookの設定をする

LINE DevelopersのMessaging API設定に,Webhook設定という項目があります。
編集をクリックして,先ほどのウェブアプリのURLを貼り付けます。
また,Webhookの利用をオンにしておきます。
image.png

検証をクリックし「成功」と表示されれば正しく設定できています。

あとは実際にLINEで友達登録して返信できるかテストするだけです。

今後やりたいことなど

初めてBotを作ってみましたが,非常に楽しかったです。
制作に10時間ほどかかりましたが,時間が経つのを忘れて作ってしまいました。

画像を送ったり,これから百人一首を覚えたい人に向けてクイズを出すなど,文章を返信する以外の機能を加えたBotなども作れたら面白いなと思っています。

追記:画像送信するものも作りました。

ゴロ合わせの覚え方をイラストとともに紹介します。

スマホ向けリンク

16
23
2

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
16
23