このページの本文へ

日曜プログラマーのための「Clovaスキルつくり隊!」 第5回

応用技でつくるプログラミングを学ぼう

読み手をClovaにやってもらう「江戸いろはかるた」スキルをつくってみよう

2019年08月23日 13時00分更新

文● ASCII編集部

  • この記事をはてなブックマークに追加
  • 本文印刷

かるた遊びもClovaさえあればすぐできちゃう!

 人気スマートスピーカーLINEの「Clova」シリーズ向けに、大人も子供も楽しめるスキルをつくろう!という日曜プログラマーなお父さんのための連載「Clovaスキルつくり隊!」。今回も、新たなスキルの作成に挑戦していきましょう。

 今回挑戦するのは「江戸いろはかるた」スキルです。

 漫画『ちはやふる』のヒット以降、競技かるたがちょっとしたブームになりました。とはいえ、百人一首は、小さなお子さんにはちょっと敷居が高いのも確か。そこで今回は、小さな子供でも楽しめる昔ながらのかるた遊び、江戸いろはかるたの読手を、Clovaにやってもらうためのスキルを作っていきましょう。

 ご自宅にかるた札がない、という方でも、ネット上には無料で印刷して絵札を作れる素材データがいくつかあります。たとえば、プリンターを販売しているキヤノンの無料印刷素材提供サイト『Creative Park』では、かるた札のデータが用意されていて、誰でも印刷して切り離せば即かるた遊びが楽しめます。読み手をClovaにやってもらえれば、小さな子供たちだけでも、親子2人で取り合って楽しむこともできちゃいます。

作品ナンバー05
『江戸いろはかるた読手』

江戸いろはかるた読手

 今回もスキルのアイコンには、「かわいいフリー素材いらすとや」さんのイラストを使わせていただきました。今回使用したのは、「かるたのイラスト」です。

 というわけで、さっそく見て行きましょう。できあがったのがこちらのスキルです。

 ソースコードはこちら(リスト1)。Node.js(サーバー側でJavaScriptを使う言語)で書かれています。

const clova = require('@line/clova-cek-sdk-nodejs');
const express = require('express');

const karuta = [
'犬も歩けば,棒に当たる',
'論より証拠',
'花より団子',
'憎まれっ子,よにはばかる',
'骨折りぞんのくたびれ儲け',
'屁をひって,尻すぼメル',
'年寄りの冷や水',
'ちりも積もれば山となる',
'律儀ものの,子ダくサん',
'盗人の,ひるネ',
'瑠璃も玻璃も,照らせば光る',
'オイては,こ二従え',
'割れなべ煮,閉じぶタ',
'かッタイの,かさ恨み',
'よしの髄から天井覗く',
'旅は道連れ,ヨは情け',
'良薬は,口ににがし',
'総領,の,甚六',
'月とすっぽん',
'念には念を入れよ',
'泣きっ面に蜂',
'楽あればくあり',
'無理が通れば,道理が引っ込む',
'嘘から出た,まこと',
'いもノ,煮えたも,ご存知ない',
'喉元過ぎれば,あつさを,わすれる',
'鬼に金棒',
'くさいものに,蓋をする',
'安物ガいの,ゼにウ死ナい',
'負けるが勝ち',
'芸は身を助く',
'ふみはやりたし,書く手はもたぬ',
'子は,サんがいの首枷',
'えてに帆をあぐ',
'亭主の好きな,赤烏帽子',
'アタマKAくシテ,尻隠さず',
'三べん回って,煙草にSyo',
'聞いて極楽,見て地獄',
'油断タイテキ',
'目の上のこぶ',
'身から出たさび',
'知らぬが仏',
'縁はイなもの,味なもの',
'貧乏暇なし',
'門前のコゾ卯,習わぬ経を読む',
'急いては事を仕損じる',
'すいは,身をく鵜',
'京の夢,大阪の夢'
];

const clovaSkillHandler = clova.Client
.configureSkill()

//起動時
.onLaunchRequest(responseHelper => {
responseHelper.setSpeechList([
{
lang: 'ja',
type: 'PlainText',
value: '江戸いろはかるたよみて、を起動しました。'
},
{
lang: 'ja',
type: 'PlainText',
value: '読んで、または、スタート、の掛け声で、ふだを読み上げます。'
}
]);
})

//ユーザーからの発話が来たら反応する箇所
.onIntentRequest(async responseHelper => {
//セッション情報を取得
const karuta_session = responseHelper.getSessionAttributes();

let karuta_number = [];
let select_number;

//1-①セッションが空なら最初から、存在していればカルタの配列番号を格納する
if (Object.keys(karuta_session).length == 0) {
for (let i = 0; i < karuta.length; i++) {
karuta_number.push(i);
}
} else {
karuta_number = karuta_session['karuta_number'];
select_number = karuta_session['select_number'];
}

const intent = responseHelper.getIntentName();
switch (intent) {

//1-②読んで
case 'KarutaIntent':
//karuta_numberが空だったら終了
if (karuta_number.length == 0) {
//セッション終了
responseHelper.endSession();
//セッションを初期化
responseHelper.setSessionAttributes();
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: 'すべてのふだが読み上げられました、江戸いろはかるたよみてを終了します。'
});
} else {
let speechlist = [];
//ランダムで選定
let random = Math.floor(Math.random() * karuta_number.length);
let current_number = karuta_number[random];
select_number = current_number;
karuta_number.splice(random, 1);

//セッション情報の保存
responseHelper.setSessionAttributes({'karuta_number':karuta_number, 'select_number':select_number});

speechlist = [
{
lang: 'ja',
type: 'PlainText',
value: karuta[current_number]
}
];

//karuta_numberが空になったら
if (karuta_number.length == 0) {
speechlist.push({
lang: 'ja',
type: 'PlainText',
value: 'すべてのふだが読み上げられました。'
});
} else {
//リプロンプト
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: '読んで、または、スタート、といってください。'
}, true);
}

responseHelper.setSpeechList(speechlist);
}
break;
//1-③もう一度読んで
case 'RepeatIntent':
let repeatSpeech;
//select_numberが空なら読み上げない
if (select_number == null) {
repeatSpeech = '読み上げた札はありません。';
} else {
repeatSpeech = karuta[select_number];
}
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: repeatSpeech
});
break;
//初期化
case 'ResetIntent':
//セッションを初期化
responseHelper.setSessionAttributes();
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: '初期化しました。'
});
break;
//使い方
case 'Clova.GuideIntent':
responseHelper.setSpeechList([
{
lang: 'ja',
type: 'PlainText',
value: '読んで、または、スタート、の掛け声で、ふだを読み上げます。'
},
{
lang: 'ja',
type: 'PlainText',
value: 'リピート、または、もう一度読んで、と言うと、最後に出たふだを、読み上げます。'
},
{
lang: 'ja',
type: 'PlainText',
value: '初期化して、と言うと、初期の状態の戻ります。'
}
]);
break;
//1-④予想していない発話
case 'Clova.FallbackIntent':
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: '開始するには、読んで、または、スタート、といってみてください。'
});
break;
}

console.log('Intent:' + intent);
})

//終了時
.onSessionEndedRequest(responseHelper => {
const sessionId = responseHelper.getSessionId();
})
.handle();

//ポート3000番で起動しリクエスト待受
const app = new express();
const port = process.env.PORT || 3000;

//applicationIdの検証、基本情報のExtension IDを入力
const clovaMiddleware = clova.Middleware({applicationId: 'YOUR_APPLICATION_ID'});

//ルートディレクトリ配下の本ディレクトリを指定
app.post('/PATH/TO/DEV', clovaMiddleware, clovaSkillHandler);
app.listen(port, () => console.log(`Server running on `));

 どんな命令が実行されているかは、「//」で始まる行に書いてあるコメントを参照してください。

 それでは、今回のプログラムのポイントを少し詳しくみていきましょう。

スキルづくりのワンポイントテク
スキルの中で音楽を再生する

 今回の開発ポイントは、前回のビンゴスキルを流用して効率的にプログラム開発をしている点と、かるた読みの発話が正しくない箇所の読み方をテキスト変更して工夫した点です。

■ポイント1.ビンゴスキルとの比較

1-①セッションが空なら最初から、存在していればカルタの配列番号を格納する

 ビンゴは1~75までの数字をfor分を使い配列bingo_numberに格納しましたが、カルタの読みては48種類ですので、0~47の数字をfor分を使い配列bingo_numberに格納します。

//1-①セッションが空なら最初から、存在していればカルタの配列番号を格納する
if (Object.keys(karuta_session).length == 0) {
for (let i = 0; i < karuta.length; i++) {
karuta_number.push(i);
}
} else {
karuta_number = karuta_session['karuta_number'];
select_number = karuta_session['select_number'];
}

1-②読んで

 ビンゴの「BingoIntent」と同様「KarutaIntent」で読み上げを行います。ビンゴの場合は次の数字読み上げまでインターバルの時間をとりましたが、今回は、すぐ次の読み上げが開始できるようにしました。

 また、ビンゴで実装した、今までの数字を読み上げ処理は不要なため、ReadIntentを削除してます。

1-③もう一度読んで処理

 RepeatIntentはビンゴの「LastNumberIntent」と同様に最後の内容を読み上げます。

if (select_number == null) {
repeatSpeech = '読み上げた札はありません。';
} else {
repeatSpeech = karuta[select_number];
}
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: repeatSpeech
});

 初期化、使い方もビンゴ同様の実装としています。

1-④予想していない発話

 Clova Extensions Kitv3.1.2から追加されたビルトインインテント「予想していない発話」処理を追加しました。

case 'Clova.FallbackIntent':
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: '開始するには、読んで、または、スタート、といってみてください。'
});

■ポイント2.発話の工夫

 かるた読みの発話が正しくない箇所の読み方をテキスト変更して工夫しました。たとえば、次のような個所です。わざわざ当て字を入力しておくことで、本来発話してほしいイントネーションに近づけています。

へ 屁をひって尻すぼめる → 屁をひって,尻すぼメル
り 律義者の子沢山 → 律儀ものの,子ダくサん
ぬ ぬすびとの昼寝 → 盗人の,ひるネ
る るりもはりも照らせば光る → 瑠璃も玻璃も,照らせば光る
を 老いては子に従え → オイては,こ二従え
わ われ鍋にとじ蓋 → 割れなべ,閉じぶ
か かったいのかさうらみ → かッタイの,かさ恨み
た 旅は道連れ世は情け → 旅は道連れ,は情け
や 安物買いの銭失い → 安物ガいの,ゼにウ死ナい
あ 頭隠して尻隠さず → アタマKAくシテ,尻隠さず
さ 三遍回って煙草にしょ → 三べん回って,煙草にSyo
も 門前の小僧習わぬ経を読む → 門前のコゾ卯,習わぬ経を読む
す すいは身を食う → すいは,身をく

 いろはかるたは、江戸いろはかるたのほかに、京都いろはかるたや、大阪いろはかるたなどもあります。また、キャラクターかるたなどにも、かるた読みのセリフを変更することで対応させることがあでき、なかなか応用が利くプログラムになっています。

 この連載では、これからも面白いスキルをジャンジャンつくっていくので、みんなもぜひ挑戦してみてくださいね!

カテゴリートップへ

この連載の記事