Brainf*ckするLINE BotをGASで作る
生きていると、無性にBrainf*ckしたくなることがありますよね。そんな時のために、LINEで手軽にBrainf*ckできるBotを作りました。
QRコード
準備
GASでLINE Botを作る手順は割愛します。以下の記事をご参照ください。
最低限、開発に必要なのは、
- ブラウザ
- LINEアプリ・アカウント
ですが、この手の開発手段はごまんとあるので触れないでおきます。宗教戦争こわい。
処理系を書く
Javascriptでの実装例は調べればたくさん出てきます。ですが、それだと暇潰しにもならないので、オレオレ処理系を愚直に実装しました。
LINE Botにするので、逐次的な入力は求めません。Brainf*ckコードと入力を引数に、出力を返す関数を定義します。
関数 brainfuck
function brainfuck(code, input) {
var ptr = 0; // データポインタ
var mmr = [0, null]; // データ配列
var pc = 0; // プログラムの何文字目を読むかのカウンタ
var ic = 0; // 入力の何文字目を読むかのカウンタ
var tmp = 0; // 二重 [ ] のために使う (後述)
var steps = 0;
var step_limit = 1000000;
var output = "";
for (pc = 0; pc < code.length; pc++) {
switch (code[pc]) {
case '>':
ptr++;
if (!mmr[ptr]) { // 配列に空要素を追加
mmr[ptr] = 0;
mmr.push(null);
}
break;
case '<': ptr--; break;
case '+': mmr[ptr]++; break;
case '-': mmr[ptr]--; break;
case '.':
output += String.fromCharCode(mmr[ptr]);
break;
case ',':
mmr[ptr] = input.charCodeAt(ic);
ic++;
break;
case '[':
if (!mmr[ptr]) {
tmp = 1;
// (`]`の個数)-(`[`の個数)=1になるまでpcを右にずらす
while (tmp) {
pc++;
if (code[pc] == '[') tmp++;
if (code[pc] == ']') tmp--;
}
}
break;
case ']':
if (mmr[ptr]) {
tmp = 1;
// (`[`の個数)-(`]`の個数)=1になるまでpcを左にずらす
while (tmp) {
pc--;
if (code[pc] == ']') tmp++;
if (code[pc] == '[') tmp--;
}
pc--;
}
break;
}
steps++;
if (steps >= step_limit) {
output = "ERR: There are too many steps.";
break;
}
}
return output ? output : "ERR: There is no result.";
}
mmr
を [0, null]
で初期化するアイデアは以下の記事を参考にしました。
出力か無いときと、処理が永遠に終わらないとき (例えば +[]
) は、LINE Botに適さないためエラー文を返します。それ以外の例外は実装していません。孟子も「人は生まれながらにして正しいBrainf*ckプログラムを書く」と言ってました。
メッセージの加工
ユーザーが送ってきた文章のうち、最初の " "
で囲まれた文字列を入力とし、それ以外の文字列から ><+-.,[]
を抽出してこれらを関数 brainfuck
に突っ込みます。
ただ、せっかくのLINE Botなので、いくつか置換を追加しました。
関数 brain
function brain(text) {
var code = text
.replace(/!|\!/g, '>')
.replace(/?|\?/g, '<')
.replace(/〜/g, '+')
.replace(/ー/g, '-')
.replace(/。/g, '.')
.replace(/、/g, ',')
.replace(/(/g, '[')
.replace(/)/g, ']')
.replace(/[^><\+-\.,\[\]]/g, "");
var input = (text + '""')
.replace(/「|」/g, "\"")
.match(/".*?"/g)[0]
.replace(/"/g, "");
return brainfuck(code, input);
}
!?〜ー。、()
をそれぞれ ><+-.,[]
に置換し、
「
と 」
を "
に置き換えます。
これで、日本語フリック入力だけでBrainf*ckできます。
LINE Botの実装
あとは、ユーザーからLINE Botへのメッセージ userMessage
に対して、LINE Botからユーザーに brain(userMessage)
を返信するだけです。
LINE Messaging API で返信
var ACCESS_TOKEN = '(アクセストークンをコピペ)';
var url = 'https://api.line.me/v2/bot/message/reply';
function doPost(e) {
replyMessage(e);
return ContentService.createTextOutput(
JSON.stringify({ content: 'post ok' })
).setMimeType(ContentService.MimeType.JSON);
};
var replyMessage = function (e) {
var userMessage = JSON.parse(e.postData.contents)
.events[0].message.text;
var replyToken = JSON.parse(e.postData.contents)
.events[0].replyToken;
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: brain(userMessage)
}
]
})
});
};
最終的なコードはGistにあります。
完成
clasp push -f && clasp deploy
などあれやこれやすれば完成。
とりあえず、Hello, world!
入力を使ったこんな遊びもできます。おもしろいです。
楽しい「Brainf*ckライフ」を!!〜〜(!〜〜〜?ー)、!(?〜〜〜!ー)?。、、〜〜〜〜〜〜〜。、、?〜〜(!〜〜〜〜〜?ー)!。
Discussion