【Twitter】ランパの台詞botを作成してみる その2

というわけで、今回は「ランパの台詞botを作る」第2弾です。
前回の記事はコチラ!

【Twitter】ランパの台詞botを作成してみる その1

今回は台詞集から出力するテキストを抜き出し、ツイートするところまでやってみます!
ついでに作っている上で苦労していることも紹介します。

台詞の入力

とりあえず「オープニング~ステージ3-2」までと、その他回収できた台詞を書き出してみました!

20170116_02

見直してみると結構喋りますね。
ステージ3-2まででも3000文字近くあります。
ハマグリほどではありませんが、主人公が喋らないのでその影響もあるようです。
一方で全く喋らない(≒登場しない)ステージもそれなりにあるので、各ステージ満遍なく喋るというよりは、1ステージでの回数が多いといった印象です。

それにしても、3点リーダーが尋常でなく多いです。

DSC_0281

恐らく会話ウィンドウ的な都合があるのだと思いますが、それを差し置いても多いです。
実際にツイートさせる時は適度に削除しないと見にくくなってしまいます。

ゲーム自体の対象年齢故にひらがなも多いですが、簡単な漢字とカタカナは含まれているので、そこまで読みにくくはないと思います。
ただ句読点が一切ない上、上記の3点リーダーを削除してツイートする兼ね合いもあるため、適度に句読点は入れています。
それ以外は原文ママで問題ないと思われます。

twitterアイコンの作成

デフォルトのたまごアイコンでは味気ないので、アイコン用にランパを描いてみました。
ステージ選択のアイコンを元にしました。

20170116_rampa_icon1

うーん・・・また何とも言えない出来ですが、まあ及第点でしょう。
まあアイコンなんて小さいものなので、割と大雑把なくらいがちょうどよかったりします。

個人ページの背景は・・・後回しにします(ぁ
今の自分のイラスト力では描ける気がしないので・・・。

bot用PHPファイルの修正

前回ほぼコピペだったPHPファイルを修正します。
自分は手続き型っぽく書くのが嫌いなので、意味もなくクラスをインスタンス化するようにしました。
ツイートする部分は同じですが、ランパの台詞の抽出と整形部分を大きく変えています。

ツイートの際の理想の形式は「ランパの台詞 (改行)【発言した場面】」です。
また、台詞が複数行になることもあるので、その点も考慮する必要があります。

<?php

require_once("twitteroauth-master/autoload.php");
require_once('twitteroauth-master/src/TwitterOAuth.php');

use Abraham\TwitterOAuth\TwitterOAuth;

/**
 * ランパの台詞集から台詞を抽出・ツイートするクラス
 */
class TwitterRampaBot {

    private $customer_key;
    private $customer_secret;
    private $access_token;
    private $access_token_secret;

    const file_path = 'rampa_serifu.txt';
    const max_tweet_len = 140;

    /**
     * コンストラクタ
     */
    public function __construct() {
        $this->customer_key = "customer_key";
        $this->customer_secret = "customer_secret";
        $this->access_token = "access_token";
        $this->access_token_secret = "access_token_secret";

        mb_internal_encoding('UTF-8');
    }

    /**
     * つぶやきを送信する
     */
    public function tweet() {
        $message = $this->getTweetWord();

        // 文字数チェック
        if (self::max_tweet_len < mb_strlen($message)) {
            trigger_error('ツイート可能な文字数を超えています。', E_USER_ERROR);
            exit;
        }

        // サーバにつぶやきを送信
        $connection = new TwitterOAuth($this->customer_key, $this->customer_secret, $this->access_token, $this->access_token_secret);
        $connection->post("statuses/update", array("status" => $message));
    }

    /**
     * ツイート用の文字列を取得・整形する
     *
     * @return string
     */
    private function getTweetWord() {
        // テキストファイルから文字列読み込み
        $input_lines = file(self::file_path);
        $words = array();

        // 先頭 # の行を取得するまでループ
        while(true) {
            $line_num = rand(0, count($input_lines));

            // 先頭が # で始まる行を抽出
            if (preg_match('/^\# .*$/', $input_lines[$line_num])) {
                // # 以降を場面として取得
                $scene = $this->excludeLineFeed($input_lines[$line_num]);
                $scene = str_replace('# ', '', $scene);

                // 複数行の台詞を全て取得するまでループ
                for ($i = $line_num + 1; ; $i++) {
                    // 文字列か空or改行コードのみの場合は終了
                    if (empty($input_lines[$i]) || preg_match('/^' . PHP_EOL . '$/', $input_lines[$i])) {
                        break;
                    }

                    $words[] = $this->excludeLineFeed($input_lines[$i]);
                }
                break;
            }
        }

        // 台詞と発言場面を設定
        $message = '';
        foreach ($words as $word) {
            $message .= $word . PHP_EOL;
        }

        $message .= '【' . $scene . '】';

        return $message;
    }

    /**
     * 指定した文字列から改行コードを除外する
     *
     * @param string $str
     * @return string
     */
    private function excludeLineFeed($str) {
        return str_replace(PHP_EOL, '', $str);
    }
}

$twitterRampaBot = new TwitterRampaBot();
$twitterRampaBot->tweet();

exit;

?>

GitHub から落とした「TwitterOAuth」を使用していますが、バージョンによってやり方に差があるようです。
自分も他サイトのコピペでは全然動きませんでした。

あれこれ考えた結果、ファイルから取得した後、正規表現で取捨選択するのが最も手っ取り早かったです。
テキストファイルから抽出した文字列から、以下の条件で抽出します。
・# から始まる行を発言場面として抽出
・#以下から次の空白行 (実際は改行コード) までを台詞として抽出
・空白行は抽出しない

台詞集となるテキストファイルもそれに則って書いていきます。
サンプルとして、いくつか台詞を記載します。

# ステージ1-3
・・・どうしてこんなところに・・・
それに何でたたかっていたんだ・・・
うう・・・思い出そうとするとアタマがイタイ・・・
もしかして・・・ボクのきおく・・・

# ステージ1-4
あ・・・うん!!
スタフィーのボクをたすけたいって思う気もちが
ボクのへんしんのチカラ、『ドランパ』を思い出させてくれたんだ・・・

# ステージ2-2
あ、そうだ!ボクとチカラをあわせて下からゴォォォーってやってみる?
ドランパで、上ボタンをおしながらゴォォォーってできるよ
ためしてみて!

注意点として、Linux 上から動作させる関係上、改行コードは「LF」にしておく必要があります。
サクラエディタであれば保存時に指定できます。

かなり効率の悪い処理ですが、何度も実行するような処理ではないので、速度はあまり気にしません。
他にもいろいろ考えましたが、.ini は設定ファイルの趣が強く、このためだけに yaml や json のパーサを入れるのも嫌なので、とりあえずこの形でいってみようと思います!

苦労している点

プレイ日記に片足突っ込みつつ、製作している上で苦戦していることを紹介します。

データが消える

ある意味最大の壁です。
本体がダメなのか、ソフトが古いためか、プレイ中に接触不良→次回起動時にデータ消失ということがあります。
特にカートリッジを抜いておくと、次回起動時に差しても高確率で認識しません。

スロットからカートリッジを出さなければ順調なので、差しっぱなしにすることでカバーしていますが、当分の間3DSがスタフィー専用機となることを意味します。
最近3DSはほとんど起動していないので、あまり実害はないと思われますが、MHXX発売までには完成させたいところです。

ステージクリア後にオートセーブ

カートリッジ故にセーブは高速で、普通にプレイする分には問題ありません。
ただ、ランパの台詞を取り逃してしまったり、間違えていた場合、ステージをクリアするまでにリセットしないとアウトです。
ストーリーが進んでしまうと読み直すことができないので、漏れなくニューゲームとなります。
後半のステージでこれをやってしまうと悲惨なので、最も注意すべき人的エラーですね。

会話後に再度会話をすると内容が異なる

ステージの所々に会話イベントがありますが、会話後に再度キャラクターと会話すると、内容が異なる場合があります。
ゲーム的には素晴らしい作り込みですが、台詞をまとめる上では注意が必要です。

DSC_0283

しかも再会話時の台詞は長いものが多いです。
これも上記のオートセーブと同じく、気付かずにストーリーを進めてセーブされると、最初からやり直す羽目になりかねません。

まとめ

そんなわけで、ランパbotの作成日記その2でした!
まだ途中までしか作っていませんが、アカウントを作ってしまった上、完成がいつになるか分からないので、今のレパートリーで試運転してみようと思います。
cron で1日2回、12時間置きにツイートさせるように設定しています。

ひとまず問題なく稼働しているみたいです。
あとはランパの台詞を逃すことなく追加していけば完成すると思われます!

【Twitter】ランパの台詞botを作成してみる その1

【2017/01/16】
サンプルソースを修正しました。

というわけで、今回はタイトル通り、Twitterのbot作成に挑戦してみます!
作るのは伝説のスタフィーに登場するキャラクター「ランパ」の台詞集です!

ranpa31

上のような、宇宙服を着たウサギのようなキャラです。
(自分が描いたイラストなので実物とは異なります)
「ランパ星」というまんまな星の王子で、いろいろな動物に変身することができます。
「キャラクターとしての魅力は?」と言われれば・・・回答が難しいところですが、自分は「見た目」と「至って普通な性格」と返します。
主人公であるスタフィーとの変身形態の1つにアザラシがあるので、むしろそっちに惹かれたりしていましたが・・・。

DSC_0278

そんなランパの台詞集、誰も作っていなかったので、ネタとしてのポストは空いています。
前からbotを作ってみたかったのもあるので、どんな感じなのかやってみました!

Twitterアカウントの作成

まずはbot用のTwitterアカウントを作成します。
マイアカウントでログインしっぱなしなので一度ログアウトし、新しくアカウントを作成します。

新規アカウントのためにはメールアドレスが必要ですが、bot専用のアカウントを作るのも嫌なので、Gmailのエイリアス機能を使用します。
[アドレス]+[任意文字列]@gmail.com でメールを自動的に転送してくれるらしいです。
細かいことはぐぐればたくさんでるので割愛します。

shot2ss20161223224502738

「ランパ」とだけ打つと、歯の矯正手術とかそっち系のばかりヒットするため、頭にスタフィーと入れておきます。
ちなみにランパのスペルは「Rampa」らしいです。
海外版では「bunston」と全く別名だったりしますが、とりあえずランパで行きます!

shot2ss20161223224725777

電話番号認証の後、ユーザIDを入力します。
まあ日本の方ならアカウント名見れば分かると思うので、シンプルにいきます。

あとはおすすめされる通知設定やフォローを全て拒否して完了です。

「Twitter Developers」でアプリケーションの作成

Twitter連携用のアプリケーションを作成します。

https://dev.twitter.com/

サイト上の「My Apps」をクリックし、次画面の右上からログインしましょう。

shot2ss20161223231237770

アプリ名、アプリの詳細、サイトURLを入力します。
割と適当でも大丈夫です。
サイトを持っていない場合は適当なURL(example.comとか)でも良いらしいです。

作成時に電話番号認証が行われていない場合、エラーとなって先に進めません。
しかも電話番号はアカウント間で共有することが出来ないそうです。
面倒ですが、メインアカウントの電話番号で一時的に認証してしまいました。

完了後にアプリケーションの詳細画面が表示されるので、「Application Settings」のあたりを撮っておきます。
上タブの「Keys and Access Tokens」の情報と、画面下の「Create My Access Token」クリック後の情報もメモしておきます。

実行用PHPファイルの作成と自動実行設定

GitHub上で公開されている「TwitterOauth」というPHPで作るのが一般的らしいです。
ほぼ他の参考サイトのコピペです。

<?php
require_once("twitteroauth-master/autoload.php");
require_once('twitteroauth-master/src/TwitterOAuth.php');

use Abraham\TwitterOAuth\TwitterOAuth;

$customer_key = "customer_key";
$customer_secret = "customer_secret";
$access_token = "access_token";
$access_token_secret = "access_token_secret";

$filelist = file('rampa_serifu.txt');
if(shuffle($filelist) ){
    $message = $filelist[0];
}

$connection = new TwitterOAuth($customer_key, $customer_secret, $access_token, $access_token_secret);
$connection->post("statuses/update", array("status" => $message));
?>

file() でテキストファイルの中身を取得し、無作為に1行抽出しているようです。
TwitterOAuth のパスや各種キーは環境に応じて設定して下さい。

実際は後述の台詞集入力で手間取っているため、まだ動かしていません。
またツイート時に「どこで発言したか」も入れたいので、単純にテキストファイルから取ってくるだけではきついかなーとも思います。
行く行くは正規表現であれこれして出力する感じでしょうか。

台詞集の入力

あとはランパの台詞を読み込ませるだけなのですが・・・。
ランパが登場するのは「伝説のスタフィー たいけつ!ダイール海賊団」という作品になりますが、もう発売から10年近く経つゲーム故、台詞をまとめてあるサイトなんてどこにもありません。
もちろんROM解析する知識・技術もなければ、それを行うための機材もありません。

ただ、ソフト自体は今でもとってあります。DSもあります。
つまりこういうことです!

DSC_0277

素でゲームを最初からエンディングまでプレイし、ランパの発言を残すことなく記録していくしかないでしょう。
クリアデータがありますが、一度クリアしたステージのストーリーを再度見ることは出来ません。
また、マリオやカービィと違ってステージ中にも会話が入るので、そういった意味でもプレイしないと厳しいです。

必要なのは「ランパが落ちてくるところからダイール撃破まで」のステージ1~8で、9~10は(確か)一言も喋らないので除きます。
隠しステージの攻略が必要かどうかは微妙なところです。
(うる覚えですが、ドランパに関することでランパが何か喋った気がします)
その他サブ要素(今日のゲストとメモ)で幾つか台詞があった気がしますが、既存のクリアデータで回収できます。

・・・と思いきや、セーブ中にソフトの接触不良→再起動時にデータ真っ白というアクシデント!
サブ要素をメモった後だったのが幸いですが、(ほぼ)コンプリートしたデータが消し飛んでしまいました。
元々最初からやり直す予定だったので、新規で始めますが・・・。

DSC_0279

DSC_0280

何かステージがところどころおかしいです。
水中なのに地上扱いになっていたり、壁のブロックが消えていたりします。
使用している3DSのカートリッジスロットの認識が悪いので、本体を入れ替えてからプレイしないと危険な気がします・・・。
ちょっとやり方を考える必要がありそうです。

というトラブルがあったことを踏まえると、実際の完成はかなり先の話になってしまいそうです。
こういう「台詞bot」って割とよく見かけますが、どうやって作っているのでしょうか。
やはり気合で入力するしかないのでしょうか・・・。

一気にやるのは無理があるので、暇なときにやっていくようにします。
ゲーム的な難易度は低めなので、「詰まる」という意味での障害はないと思われます。

まとめ

というわけで、Twitterでランパの台詞botを「形だけ」作ってみました!
botだけなら自作でも簡単に作れてしまうようです。
むしろゲーム内のランパの台詞をかき集める作業の方が大変かもしれません・・・。
気が向いたらときに少しずつ作っていくしかなさそうです。

余談

海外では「starfy wiki」というシリーズ全体のwikiがあります。
スタフィーシリーズは5作目まで海外で発売されていなかったにも関わらずです。
過去シリーズはおろか、過去に発売されたグッズやROM内の没データまで、内容量も凄まじいです。
英語のサイトですが、スタフィー好きな方は読んでみると面白いかもしれません。

http://starfywiki.org/wiki/Main_Page