update を持たないオブジェクトを attach で登録すると、通知の時に初めて落ちます。does で GameEventObserver ロールを持つか確かめて、登録の時点で弾きます。Moo の isa 制約を使う方法と、循環参照の注意点も扱います。
ゲームの実行中にサウンドを ON/OFF できるよう、通知先を attach と detach で付け外しします。設定オブジェクトでまとめて管理する方法と、付け外しで気をつける点も確かめます。
GameEventEmitter クラスに、通知先を登録する attach、外す detach、全員に知らせる notify を実装します。ゲーム側は通知先の中身を知らないまま、全員に通知できるようになります。
Moo::Role の requires で、通知を受け取るクラスは update メソッドを持つという約束を GameEventObserver ロールとして定義します。update を書き忘れたクラスが、どう失敗するかも確かめます。
LogObserver と AchievementObserver を、それぞれ update メソッドを持つ独立したクラスとして作ります。通知を受け取る側を分けて、ゲーム本体のメソッドから個別の処理を取り除きます。
ログに加えて実績も記録したくなり、1つのメソッドに if/else で処理を足していきます。メソッドが肥大化し、新しい機能を足すたびに既存コードを直す羽目になる問題を、コードで確かめます。
Perl と Moo で、ローグライクの「敵を倒した」を表すゲームイベントのクラスを作ります。まずは say で直接ログを出力する素朴な実装から始め、次回以降に通知の仕組みへ育てていく土台にします。
パスワードの総当たりを3重のfor文で書くところから始め、桁数の増加で再帰に行き詰まり、next メソッドを持つ Moo クラスに閉じ込めて Iterator パターンにたどり着くまでの全5回の目次です。第1回から順に読む連載で、どの回で何が変わるかを一覧できます。
シリーズで作った next メソッドを持つクラスに、GoF の Iterator パターンと名前を付けて振り返ります。1億通りを配列に展開せず、いま試す1つだけをメモリに置く遅延評価の利点と、Perl の <$fh> も同じ仕組みであること、CPAN の Iterator 系モジュールを紹介します。
よく使われるパスワードのリストを1行ずつ返す DictionaryIterator を作り、BruteForceIterator と同じ next メソッドを持たせます。コマンドラインの --mode で切り替えても、試行する while ループは1行も変わりません。ポリモーフィズムで攻撃手法を差し替える形を確かめます。
再帰とループの複雑さを BruteForceIterator という Moo クラスに閉じ込め、next を呼ぶたびに次のパスワード候補を1つ返す形に直します。使う側は while で next を呼ぶだけになり、現在の数値を覚えて0埋めするだけの実装で、何桁でも同じ書き方で回せます。
桁数が増えるたびに for 文を書き足す方式は、桁数を実行時に決められません。再帰呼び出しの brute_force 関数で何桁でも総当たりできる形にしますが、理解しにくい、途中で止めて再開できない、組み合わせの生成と試行が1つの関数に混ざる、という3つの困りごとが残ります。
3桁の数字で開くダイヤル錠 PasswordLock を Moo で作り、000から999までの1000通りを3重のfor文で全部試して、正解の777を見つけます。桁数が決まっているうちは for 文のネストで足りること、4桁になった瞬間に書き換えが要ることを確かめます。
Perl と Moo で、HP・所持金・位置を持つ Player のRPGを作り、ゲームオーバーで最初からやり直しになる困りごとを、スナップショット・復元・複数スロット・オートセーブで解決して、最後に Memento パターンと名前を付ける全10回の連載の目次です。どこから読むか、困りごとからも選べます。
ここまで作った Player・PlayerSnapshot・GameManager の組み合わせは、GoF の Memento パターンそのものでした。Originator・Memento・Caretaker の3役に対応づけ、Command パターンとの違いも整理します。