★前回の記事
スタートボタンを押したときの挙動をプログラミングしていきます。
actionの登録
スタートボタンへactionを登録します。スタートボタンがクリックされたときにaction.startSolve
を呼びます。この関数はすぐ下で実装します。
js/main.js
// 前略 const initializer = { setEvent: () => { // 中略 // 追加ここから $("#start-button").on("click", () => { action.startSolve() }) // 追加ここまで }, }
actionの実装
action.startSolve
を実装します。KATAMINOを解くのをスタートさせ、状態をsolving
(解いている)に変更します。
js/action.js
const action = { // 中略 // 追加ここから startSolve: () => { solver.init(state.targetPieces) solver.solve() stateManager.setSolverState("solving") }, // 追加ここまで }
画面の状態の変更
stateManager.setSolverState
を定義します。
js/stateManager.js
const stateManager = { // 中略 // 追加ここから setSolverState: (solverState) => { state.solverState = solverState // TODO displayの呼び出し console.log("state.solverState", state.solverState) }, // 追加ここまで }
表示するピースのデータ形式の変更
STEP1では、kataminoField
を描画用関数に渡し、kataminoField
のマスをテーブルの1セルに対応させて描画していました。STEP2ではそれをやめ、スピンの画像を表示する方法に変更します。そのためには、ピースのIDとスピンのID、位置を渡す必要があります。位置としてoffset
を渡します。offset
はピースの左上が、フィールドの左上からどのくらい離れているかを表します。
フィールドに置かれているピースのIDとスピンのID、オフセットを格納した配列(placedPieces
)をスタックに追加します。
ピース新たに置かれたら、配列の最後にそのピースのIDとスピンのID、オフセットを追加します。
js/solver.js
const solver = { // 中略 solverStack : [], init : (targetPiece) => { const kataminoField = new Array(5).fill().map(() => ( new Array(targetPiece.length).fill(-1) } solver.solverStack = [] const minEmpty = {x:0, y:0} // 追加 const placedPieces = [] targetPiece.forEach((pieceId) => { KATAMINO_ARR[pieceId].forEach((spin, spinId) => { // placedPiecesを追加 solver.solverStack.push({kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece: targetPiece, placedPieces,}) }) }) }, solve : () => { // 中略 // placedPiecesを追加 const {kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece, placedPieces,} = solver.solverStack.pop() // 中略 console.log("ピースが置ける") const nextField = util.copyArrayOfArray(kataminoField) solver.placeSpin(nextField, spin, offset, pieceId) console.log("nextField", nextField) const nextUnPlaced = unPlacedPiece.filter(id => id !== pieceId) console.log("nextUnPlaced", nextUnPlaced) // 追加ここから const nextPlacedPieces = [...placedPieces, {pieceId, spinId, offset}] console.log("nextPlacedPieces", nextPlacedPieces) // 追加ここまで // 表示用オブジェクトとしてnextPlacedPiecesを渡すように次で変更する display.show(nextField) // 中略 nextUnPlaced.forEach((nextPieceId) => { KATAMINO_ARR[nextPieceId].forEach((nextSpin, nextSpinId) => { // placedPieces: nextPlacedPiecesを追加 solver.solverStack.push({kataminoField: nextField, minEmpty: nextEmpty, pieceId:nextPieceId, spinId:nextSpinId, spin: nextSpin, unPlacedPiece: nextUnPlaced, placedPieces: nextPlacedPieces,}) }) }) setTimeout(solver.solve, 300) }, // 後略 }
表示用コールバックの作成と呼び出し
STEP1で作成したsolver
は、solve
関数の中でdisplay.show
を呼び出していましたが、プログラムの構成の変更にともない呼び出し方を変更します。
stateManager
の呼び出しはaction
から行う必要があるので、solver
にコールバックを渡します。フィールドに置かれたピースが変更された場合にはsolver
からaction
のメソッドを呼び出すようにします。(stateManager.setPlacedPieces
はまだ定義していません)
js/action.js
const action = { // 中略 startSolve: () => { solver.init(state.targetPieces) // 変更ここから solver.solve({ onUpdatePieces: (placedPieces) => stateManager.setPlacedPieces(placedPieces), }) // 変更ここまで stateManager.setSolverState("solving") }, }
solve
関数を変更してフィールドが変更された時にコールバックを呼び出します。
js/solver.js
const solver = { // 前略 solve : (options) => { // 変更 // 追加 const {onUpdatePieces = (placedPieces)=>{}} = options // 中略 const nextPlacedPieces = [...placedPieces, {pieceId, spinId, offset}] console.log("nextPlacedPieces", nextPlacedPieces) // display.show(nextField) を削除 // 追加 onUpdatePieces(nextPlacedPieces) // 中略 }, // 後略 }
solve
関数の引数が追加されたので、setTimeout
で呼び出しているsolver.solve
にも引数を追加します。そのままでは引数は与えられないので、無名関数でラップします。
js/solver.js
const solver = { // 中略 solve : (options) => { // 中略 if (! solver.isAllEmpty(kataminoField, spin, offset)) { // フィールドの外か、すでにピースが置かれている console.log("フィールドの外か、すでにピースが置かれている") // 変更 setTimeout(() => solver.solve(options), 0) return } // 中略 if (! solver.hasAllFiveTimesCells(nextField, nextEmpty)){ console.log("フィールドが5の倍数以外で分断されている") // 変更 setTimeout(() => solver.solve(options), 300) return } // 中略 // 変更 setTimeout(() => solver.solve(options), 300) }, // 中略 }
stateへのフィールドに置かれているピースの追加
フィールドに置かれているピース(placedPieces
)は描画に必要となるため、state
に登録します。
js/state.js
const state = { // One of "selectPiece", "solving", "solvedSuccess", "solvedFailed", "pause" solverState: "selectPiece", targetPieces: [1, 2, 9, 5, 10], // 追加 placedPieces: [], }
フィールドに置かれているピースの更新
placedPieces
を更新するsetPlacedPieces
関数をstateManager
に作成します。中身は仮実装です。
js/stateManager.js
const stateManager = { // 中略 // 追加ここから setPlacedPieces: (placedPieces) => { state.placedPieces = placedPieces // TODO displayの呼び出し console.log("state.placedPieces", state.placedPieces) }, // 追加ここまで }
実行結果
ここまでの実行結果です。
ピースが置かれたときに、stateManager.setPlacedPieces
が呼ばれ、フィールドに置かれているピースが表示されることが確認できました。
ページが長くなってしまったので、一旦ここで区切ります。ピースの表示は次回行います。
★次回の記事
★目次