はじめに
この記事の続き。
公式チュートリアルの「Wrapping Up」の章(最後)まで進めてみました。部品の大部分をBoardコンポーネントからGameコンポーネントに移し、history
に盤面を保存していくように変更しています。
全ソースはこちら。
1. 実装
(defn square [{:keys [on-click value]}]
[:button.square
{:on-click #(on-click)}
value])
(defn board [& {:keys [squares on-click]}]
(letfn
[(render-square [i]
[square {
:value (squares i)
:on-click #(on-click i)
}])]
[:div
[:div.board-row
(render-square 0)
(render-square 1)
(render-square 2)]
[:div.board-row
(render-square 3)
(render-square 4)
(render-square 5)]
[:div.board-row
(render-square 6)
(render-square 7)
(render-square 8)]]))
(defn game []
(let [state (r/atom {:history (vec [{:squares (vec (repeat 9 ""))}])
:x-is-next? true})]
(fn []
(letfn
[(handle-click [i]
(let [history (get @state :history)
current (last history)
squares (get current :squares)
x-is-next? (get @state :x-is-next?)]
(when (and (= (calculate-winner squares) nil) (= (squares i) ""))
(swap! state
assoc :history
(conj history
(assoc-in current [:squares i] (if x-is-next? "X" "O"))))
(swap! state assoc :x-is-next? (not x-is-next?)))))]
(let [history (get @state :history)
current (last history)
squares (get current :squares)
winner (calculate-winner squares)
status (if (= winner nil)
(str "Next player: " (if (get @state :x-is-next?) "X" "O"))
(str "Winner: " winner))]
[:div.game
[:div.game-board
[board :squares squares
:on-click handle-click]
]
[:div.game-info
[:div status]
[:ol
;"todo"
]]])))))
2.ClojureScriptコーディングあれこれ
2.1. last
(last history)
last
はcollectionの最後の要素を取得する。
2.2. conj
(conj history
(assoc-in current [:squares i] (if x-is-next? "X" "O")))
conj
はcollectionの最後に要素を追加する。