Reactで書かれた囲碁ボードをReagentで作ってみる(Views編)
前回からの続き。
Reagentコンポーネントを定義するviews.cljsの説明。
まずは点の大きさを表すGRID_SIZEを定義し、盤上の「点」をコンポーネント化する。
(def GRID_SIZE 40) (defn BoardIntersection [[row col] color click-fn] (let [style {:top (* row GRID_SIZE) :left (* col GRID_SIZE)} classes (str "intersection" (cond (= color :black) " black" (= color :white) " white" :else ""))] [:div {:className classes :style style :onClick #(click-fn [row col])}]))
クリックされた時の挙動は完全に外から渡されたclick-fnに準拠する。ゲームのロジックは全く組み込まれていない。のでこのコンポーネントを全く変えずに使ってオセロも作れる。
一つ気がかりなのは、盤上の端を特に考慮していないこと。できれば端は見た目を変えて表現したい。一から作る時にはこれもやってみよう。
BoardIntersectionコンポーネントを合わせてBoardViewコンポーネントを作る:
(defn BoardView [game-state click-fn] (let [size (:size game-state) style {:width (* size GRID_SIZE) :height (* size GRID_SIZE)} main-div [:div {:id "board" :style style}] coords (for [x (range size) y (range size)] [x y]) get-color (fn [coord] (get-in game-state [:board coord])) intersections (for [coord coords] ^{:key coord} [BoardIntersection coord (get-color coord) click-fn])] (into main-div intersections)))
game-stateから盤の大きさと、各点の状態を取得して、その情報を元にforループで全ての点のIntersectionコンポーネントを作成し、親Divのベクトルにintoで挿入している。ここら辺のコンポジションはReact/Reagentの面目躍如と言ったところか。
get-color関数をここでも定義してしまっているのは残念。game-stateの実装の知識がここで漏れ出てしまっている。修正するときはgame-state関連の関数として定義したものをインポートして使うべきか。
パス用のボタン:
(defn PassView [pass-fn] [:input {:id "pass-btn" :type "button" :value "Pass" :onClick pass-fn}])
クリックされた時の挙動は完全に外部からのpass-fn次第。
特殊な状態を表示するAlertView:
(defn AlertView [game-state] (let [text (cond (:game-over game-state) "GAME OVER" (:in-atari game-state) "ATARI" (:attempted-suicide game-state) "SUICIDE!" :else "")] [:div {:id "alerts"} text]))
React版をベースにしているのだけど、インターフェイスとしては少しいじりたくなる気がする。例えばアタリと自殺手が重複してたりすると自殺手のワーニングがでないのを、ゲームロジックの方で重複しないようにしている点。ここも要変更。
上記のコンポーネントを組み合わせてGameコンポーネントができる:
(defn Game [game-state click-fn pass-fn] [:div [AlertView game-state] [PassView pass-fn] [BoardView game-state click-fn]])
ゲーム状態やクリック時の挙動は外部から渡されるだけ。というわけでviews.cljsで定義されるコンポーネントはあくまで渡されたデータを元に見た目を構築するコードのみを記述したものになる。
views.cljsとlogic.cljsをcore.cljsで組み合わせて出来上がり。
core.cljsについては次回。