MSP:Mine Sweeper Project

2004-12-13

Ruby/Tk編(4) Tkとモデルの分離

タイマーを組んでみて気になった点:
 ラベルのテキストに状態を保持させていいものだろうか?

Tkはあくまでユーザインタフェースを構成するものであり、経過時間というような内部状態に相当するものは制御側(Ruby)が保持すべきものだろうと思うのである。
Tkはオブジェクトとしての記述が明確であり、Rubyから呼び出すとなおのこと実体が明確なので、ついつい内部状態を記述したくなる。RubyならTkLabelから派生させて適当なオブジェクトとすることも容易である。が、やはりTkと内部モデルはちゃんと分離すべきであろう。

次の組み込みは、いよいよ地雷の配置である。これはフィールド(10×10のボタン配列のことね)にランダムに割り当てることになるわけだが、ボタンが地雷を保持する、というのも不自然である。ちゃんとユーザのオペレーションとアプリケーションの役割を考えてみよう。
と、その前に用語定義:
フィールド:ゲームの領域全体
セル:ユーザの操作単位で地雷が設置される単位。ボタンに対応

ユーザのフィールドへの操作
・セルのオープン:地雷がないと判断しての操作。左クリックとする
・セルのマーク:地雷があると仮定して旗を立てる。右クリックまたはシフトクリックとする

セルをオープンした後の処理
・地雷がなければボタンを消し、隣接セルに存在する地雷数の合計を表示
・地雷があればゲームオーバー。全地雷の位置を表示

処理の内容をみると、「隣接セル」から情報をもらったり、「全地雷」の位置を表示したり、とセルの配置や地雷位置情報を処理する必要があることがわかる。特に「隣接セル」の定義は暗黙のうちに8近傍(上下左右斜め4)としているが、実はこの定義も抽象化できるはずである。セルの配置が格子状とは限らず、互い違いに並んでいたら隣接セルの数は6つになる。立体的な格子配置ならば26近傍である。(UIはどうなるかわからんが)
では隣接の情報はだれが管理するかというと、フィールドがセルの位置を管理するために実体として定義すべきではないかと思われる。フィールドが全部のセルの情報にアクセスできるのであれば、地雷に関する情報の経路も明確になる。

隣接セルの地雷数の合計を求める
・ユーザ→セルをオープン
・オープンされたセル→自分が地雷を保持しているかどうか確認
・地雷を保持していない:セル→フィールドに隣接セルの地雷数取得を指示
・フィールドはセルの配置情報から隣接セルのリスト作成
・フィールド→隣接セルの地雷有無を確認
・フィールド→セルに地雷数を通知

ちなみに地雷を当てた場合は、
・地雷を保持している:フィールドにゲームオーバー処理を通知
・フィールドは全セルにゲームオーバーを通知
・地雷を保持しているセルは地雷保持を表示

            
というわけで、オブジェクトの実体として、
・フィールド
・セル
の役割が明確になった。