mikutterの技術的なことを書いていこう

2014年12月14日日曜日

帰ってきたあひる焼きゲーム

<< 13日目 mikutterアドベントカレンダー2015
あひるをやっくのっはたのしいな♪

ある日あひるを焼いていると
怒られました。
どうも自動であひる焼きに反応するmikutterプラグインを書いたようです。
mikutterプラグインを書きたいと言っている人は基本的に書かないので無害ですが、何も言わずにふっとプラグインを生み出す人間にろくな人は今まで居ませんでした。あひるさんもろくな人間ではないのでしょう。

https://github.com/Na0ki/ahiru_yakuna

うわぁ…。今見たらyamlファイルに反応バリエーションが出してあるし…。順調に腕を上げてますね。pull-reqも受け取って比較的活発に開発しているようなので、こういう人は早めに潰しておかなければなりません。

作った

帰ってきたあひる焼きゲーム!
https://github.com/toshia/ahiruyaki

あひる焼きをソーシャルゲームにしました。mikutterの機能をフル活用してあひる焼きを楽しみます。フロント側の機能はREADMEに書いているので、裏で何をしているかちょっと紹介します。

RANK_TABLE
あひる焼きランクは、経験値を溜めると上がっていきます。経験値は減ることはありません。次のランクに上がるために必要な経験値をグラフ化してみました。
途中からやたら経験値が要るようになりますね。計算式は謎めいたものを使っていますが、深い意味はありません。詳しくはソースの6行目あたりからですが、無駄にEnumeratorを使用しているのがポイントですね。こういうことをすると、Enumerable#find で、ある経験値だとランクいくつになるか、というのがわりと直感的に書けます。

Plugin::Ahiruyaki::RANK_TABLE.with_index.find{ |exp, _|
  UserConfig[:ahiruyaki_exp] < exp }[1] + 1

だからどうした感が半端ない。効率はメモ化した再帰関数のほうが良さそうですが、一方でどう見てもボトルネックになるような処理ではありません。

スタミナ
ソーシャルゲームならスタミナがなければいけません。スタミナはランクアップで全回復して、行動によって消費し、時間経過で全回復します。また、スタミナには最大値があります。これはランクアップで上がっていくので、ランクから計算できます。更に、初めてゲームを遊んだ時はスタミナが最大になっているというのもポイントです。
今回はスタミナを数値で保持せず、スタミナが全回復する時刻を保持して、そこから現在のスタミナ値を決定しています。この方法のメリットは、スタミナ回復のことを常に考える必要がないことです。Time.now の戻り値を代入すれば即時回復できますし、mikutterを終了している間もスタミナが回復します。スタミナを消費した時は全回復時刻に加算すればいいだけですし、次回のスタミナ回復時刻が10秒後という時にスタミナを消費した時に、5分にリセットされるとかいうこともありません。
これはいい方法ですね。良い方法なので、多分本物のソーシャルゲームもだいたいこうなっているんじゃないか、という多分一生役に立たない知見を得ることができました。いや、思っただけなので知見でもないですね。本当に得るものがない。

また、 expend_stamina というメソッドは、消費スタミナ値を引数にとり、そのぶんだけスタミナを消費してブロックを実行します。スタミナが足りなければブロックが実行されないし、ブロックの処理途中で例外などで抜けたらスタミナが減らないので便利です。

イベント駆動
今回このプラグインを書くにあたっては、イベントをできるだけ使うようにしました。例えば、経験値は add_experience メソッドでのみ増加しますが、この経験値の増加でランクが上がると、ahiruyaki_rankup イベントが呼ばれます。最大スタミナ値などほとんどのものはランクから自動計算しているので、経験値が上がった瞬間自動的に上がりますが、スタミナの回復だけは処理してやらないといけないので、このイベントをキャッチすることで行ってます。
イベントはどのプラグインでも受け取ることができるため、あひる焼きゲームはMODの開発が簡単です。
とくに、スタミナが全快した時に発生するイベントは、全快したら自動であひるを焼くなど、さまざまな用途に使えそうです。
こういうことをしておくと、ユーザは予想外の意味不明な拡張をしてくるものです。mikutterで何度もそういうことを経験しました。何だよ、あひる焼くなプラグインって。

終わりに
結局、焼きあひるに油を注ぐ結果になっている感じがしてなりません。ゲームのアップデートもしたいのですが、忙しい時期なので、ほかのタスクに圧されて手がついていない状態です。
たまにこういう役に立たないものを書くと心がやすらぎますし、いろんなものを得た気になれるので(実際はそんなことはほぼない)、皆さんもやったら良いと思います。

2014年12月13日土曜日

mikutter-mode

<< 12日目 mikutterアドベントカレンダー2015 14日目 >>
こんにちは。ネタができたので書こうと思います。本日はmikutter-modeのある開発環境についてです。

mikutter-modeとは
Emacsでmikutter開発/mikutterプラグイン開発をするためのelispです。あ、elispっていうのはEmacs Lispで書かれた、あっ Emacs Lispというのは…

Emacsでないと意味のない内容なのか
そうではありません。例えばVimmerと呼ばれる人々は、Emacsでできることを大抵Vim上で実現してしまう習性を持っています。こういった記事をたまに書くことで、他のエディタ/IDEからやばいプラグインが生えてくるのは珍しいことではありません。

過去に触れている記事
実はmikutterの薄い本vol.2 の私の記事「プラグイン開発のベストプラクティス」 にて、
これについては触れています。
ただ、この記事は2012年夏に公開されたもので、その後の変化についてはとくに触れられていないので、あれからやったことを中心に書いていきます。

インストール
このあたりは特に変わってないのでざっと。

Emacs
まず、 mikutter-mode をチェックアウトして、elispよろしく ~/.emacs.d/ 以下とかそういうところに設置します。
Emacs側からは、この中の mikutter.el をロードするようにしましょう。
一応、私はこんな感じのことを書いてます。
変数 mikutter:dir には、mikutter.rbが入っているディレクトリを指定しましょうね。 e2wmを使っている場合、おまけでついてくる mikutter-parsepective を使うと、以下のような画面になって良い感じです。
mikutter
mikutter-modeの plugin/ 以下に、 mikutter_mode というディレクトリがあります。これがEmacsと連携するためのmikutter側のプラグインです。こちらも、このディレクトリを ~/.mikutter/plugin/ に設置します。

mikutterを起動
関数 mikutter-mode を実行すると、mikutterがデバッグモードで起動します。普通にコマンドとかから起動するのと違って、バッファ *mikutter-log* から、デバッグ出力が参照できます。

コード実行
ここからはmikutter-modeを導入しているmikutterなら、Emacsから起動されたものでなくても良いです。
mikutter-modeがインストールされている状態で、mikutterプラグインのソースを開いて C-c C-c と入力すると、mikutterに今表示している内容でプラグインがインストールされます。
mikutterで Alt+xを押してコンソールを開き、そこにプラグインをコピペして実行、という方法を取っている人もいるかと思いますが、 mikutter-mode を使った場合、Emacsからすぐに実行できることに加え、実行前にプラグインをmikutterから除去してくれるので、イベントハンドラが無限増殖しないといったメリットがあります。

選択範囲のコードを実行
mikutterのコードを開いている時に、コードの一部をリージョンで囲い(文字を選択)、 C-c C-c を押すと、バッファ全体ではなく選択したコードがmikutterで実行されます。もちろんこの場合はプラグインが一度除去されるようなことはありません。
なお、C-c C-c と、 C-c C-e で実行されたRubyコードの実行結果は、 *mikutter-result* に出力されます。mikutter-parsepective ならめっちゃ便利。

Emacs上のmikutter console
mikutterコンソールはmikutterの標準機能で、起動中のmikutter内でRubyのコードが実行できるので便利です。mikutter-modeも同様の機能を提供しています。Emacs側で関数 mikutter-console を実行すると、 *mikutter-console* というバッファが開いてきます。
これはただのmikutter-modeのバッファなので、前述のコード実行のキーが使えます。
用途としては、標準のコンソールと同じだと思います。ただし、こちらの場合はEmacsやruby-modeが提供するシンタックスハイライトや補完機能が使えるので、できるだけこちらを使ったほうが良いと思います。

プラグインが動く最小構成のmikutterを作る
これはついさっきやったアップデートです。
mikutterは、ツイートの取得でさえプラグインで実装されているということはご存知のとおりです。
プラグインというのは、入れることも外すことも自在にできるものです。標準プラグインだって外すことができます。
このことが何に使えるかというと、mikutterプラグインを開発する時に、不要なプラグインを取った環境を構築して、そこでプラグインを開発するということが可能になります。起動も早いしそのプラグインだけに集中できるのです。

これを手動でやると従来は大変でした
  • mikutterのディレクトリをコピー
  • いらないプラグインを消す
  • ./mikutter.rb --confroot=適当なディレクトリ でmikutterを別プロファイルで起動
 mikutterの --plugin オプションを使うとプラグインを消す必要がなくなって、例えば以下のようにすると home_timeline と rest プラグインだけがロードされた環境で起動できます。home_timeline は gui と gtk と uitranslator に依存しているので、この指定だけでバッチリ適切な言語でGUIが表示されます。

$ mikutter.rb --plugin=rest,home_timeline

これで確かに起動はするのですが、次普通にmikutterを起動すると、タブやペインの構成がぐっちゃぐちゃになっていると思います。一度消えたタブをまた追加したからですね。他にも設定を破壊する可能性がいろいろあるので、先のconfrootを使って、設定を分けておく必要があります。

となると、結局かなり面倒になってきます。ちょっとプラグインをデバッグするために毎回こんなことをしようと思う人はいません。最近Twitterでヌマクローをよく見かけますけど、この記事書いてて、この話をされた人の顔によく似ていることに気づきました。どんな相手でもこの話をしてからパワーウィップで確1で倒せると思います。

自分がヌマクローにならないようにするにはどうすればいいでしょうか。そう、mikutter-modeを使うのです。適当なmikutterプラグインを開いて C-c C-e と入力すると、mikutterが起動します。このmikutterには、以下のプラグインしかインストールされていません。
  • mikutter-mode
  • カレントバッファのプラグイン(現在開いているプラグイン)
  • そのプラグインが依存している全てのプラグイン(.mikutter.yml に書かれてるやつ)
プラグインによっては、gtkプラグインに依存していないものもあります。この場合、UIが表示されません。gtkプラグインがロードされなかったからです。このような状況でも、Emacsからmikutter上でコードを実行することができるし、出力も見れるのでデバッグが可能です。むしろ、プラグインを検証するときには、不要なGUIが上がってこないのでとても早く行うことができます。
先ほどの設定が壊れる問題については、 /tmp/mikutter-(プラグインスラッグ) / というディレクトリがなければ作られ、その中に ~/.mikutter が自動的にコピーされます。普段使用している環境を壊すことなく再設定の手間を省いています。

まとめ
mikutter-mode に前からやりたかったことをやってみました。
「コードの実行」は、evalのある言語ならではです。これがmikutterのアドバンテージの一つと言っても過言ではありません。
最後の「プラグインが動く最小構成のmikutterを作る」は、流石に最後は全部のプラグインを入れた状態でテストしたほうが良いですが、途中のテストはある程度これでできそうなので、どんどん使っていきたいです。

mikutter-modeは他にもいくつか機能があります。知らなかった人は導入を検討してみましょう。

#mikutter 3.1.1

  • --plugin オプションが正しく機能していなかった
  • アクティビティの設定で、操作したことのないチェックボックスを変更するとクラッシュする
  • 文書の修正等
不具合修正アップデートです。mikutter 3.2に集中するので、深刻な問題であるか、簡単なことしか手が回ってない状態です。つまり今回の不具合修正は選びぬかれた上質な不具合修正だということです。

自分だけの不具合を集めて君だけの最強のmikutterを作ろう!

2014年11月18日火曜日

#mikutter 3.1

mikutter 3.1 をリリースします。

http://mikutter.hachune.net/

見るからに、史上最強の mikutter です。

主な変更内容は mikutter 3.1の新機能です。そこからさらに変更がいろいろあったので、以下にざっとまとめます。

機能
  • Ruby 1.9のサポートを終了。
  • activity
    • アクティビティの設定画面のUIのブラッシュアップ
  • extract
    • データソースが多くなった時にスクロール可能に
    • データソースの階層化
  • list
    • リストタブを廃止。これからはリストデータソースが提供されますmikutter 3.1の新機能参照)。
  • openimg
    • 複数枚画像が添付されているツイートに対応
  • profile
    • 所属するリストタブが多くなった時にスクロール可能に
  • streaming
    • 自分がリツイートしたツイートを他人がふぁぼった場合、そのふぁぼを表示
  • uitranslate
    • 新たな言語、関西弁に対応
API
  • プラグインがロードされた時刻を取得するPlugin DSLメソッド「defined_time」を追加
  • MessageConverterを廃止。EntityにMessageを書き換える機能を追加

大幅に遅れてしまったなあ。まだちょっと既知の不具合もありますが、いつものことなので、時間切れということでリリースにします。流石に今度は12/25リリースを逃すわけにはいかないので…。

2014年11月14日金曜日

#mikutter 3.1.0 alpha5

  • 複数枚画像が添付されたツイートについて、各画像のURLを展開して表示
    • pic.twitter.com を使って画像がアップロードされている場合、画像が1枚でも展開後のURLが表示されるようになりました
  • 自分がリツイートしたツイートがふぁぼられた時、それを表示
機能追加じゃありません!Twitterの仕様に追随しただけです!
複数枚の画像は今更感があるけど、だからこそ3.2とか言わずにねじ込みました。こういうのはほんとさっさとやったほうが良かったなと反省。
早速その反省を活かして、favorited_retweetイベントに早速対応したというわけです。ふぁぼは早いmikutter。

3.1も流石に引っ張りすぎてるのでこの辺で区切らないとなぁという感じです。どうせバグ全部直したと思っても19年後とかに出てくるものですもんね。こわいなぁ。

2014年11月8日土曜日

#mikutter 3.1.0 alpha4

  • extract
    • データソースタブをマウスホイールでのスクロールに対応
    • データソースのカテゴリをデータソースとして選択できてしまう問題
  • プラグインがロードされた時刻を取得するPlugin DSLメソッド「defined_time」を追加
  • list: リスト名に「/」が含まれているときのデータソース表示上の問題
  • Entity#add で追加したリンクに、適切なクリックコールバックが設定されなかった
  • 3.0.9をマージ
クラッシュする可能性のある複数の不具合を修正しました。
ぼちぼち落ち着いてきたし、これ以上引っ張りたくないのでそろそろ…。

#mikutter 3.0.9

    • 細かい不具合修正
    Twitter以外のサービスに対応するようなプラグインを使っているとmikutterがクラッシュするような不具合がありました。ちょっとしたことですが、一応まだ3.1はリリースしてないので…。