yucatio@システムエンジニア

趣味で作ったものいろいろ

ピースを戻す表示を追加する (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

現在の実装では、フィールドに新しくピースが置かれたときにフィールドのピースを描画しています。 フィールドに置かれたビースを再描画する際、フィールドに置かれたピースが一気に置き換わる瞬間があります。

f:id:yucatio:20191027135006p:plain

このような描画は少し唐突に思うので、 以下のようにピースを"戻す"過程を表示すると、自然に見えます。

f:id:yucatio:20191027135020p:plain

今回はこの処理を追加します。

戻した状態をスタックに投入する

ピースを"戻す"表示をするために、戻した状態のフィールドをスタックに投入します。 ピースの種類を変えるたびに"戻す"ので、スタックに投入する際、最初に戻した状態をスタックに投入して、ピースのすべてのスピンを投入します。

"戻す"表示用のスタックデータのspinIdspinnullにします。

js/solver.js

const solver = {
  // 中略

  init : (targetPieces) => {
    // 中略

    targetPieces.forEach((pieceId) => {
      // 追加ここから
      solver.solverStack.push({kataminoField, minEmpty, pieceId, spinId:null, spin:null, unPlacedPiece: targetPiece, placedPieces})
      // 追加ここまで
      KATAMINO_ARR[pieceId].forEach((spin, spinId) => {
        solver.solverStack.push({kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece: targetPiece, placedPieces})
      })
    })
  },

  solve : (options) => {
    // 中略

    nextUnPlaced.forEach((nextPieceId) => {
      // 追加ここから
      solver.solverStack.push({kataminoField: nextField, minEmpty: nextEmpty, pieceId:nextPieceId, spinId:null, spin: null, unPlacedPiece: nextUnPlaced, placedPieces: nextPlacedPieces})
      // 追加ここまで
      KATAMINO_ARR[nextPieceId].forEach((nextSpin, nextSpinId) => {
        solver.solverStack.push({kataminoField: nextField, minEmpty: nextEmpty, pieceId:nextPieceId, spinId:nextSpinId, spin: nextSpin, unPlacedPiece: nextUnPlaced, placedPieces: nextPlacedPieces})
      })
    })

    solver.timer = setTimeout(() => solver.solve(options), solver.speed)
  }

  // 後略
}

"戻した"状態の表示

spinnullのときに、フィールド上のピースを更新するように変更します。

js/solver.js

const solver = {
  // 前略
  solve : (options) => {
    const {onUpdatePieces = (placedPieces)=>{}, onSolved = ()=>{}, onNotSolved = ()=>{}} = options

    if (solver.solverStack.length <= 0) {
      console.log("解けなかった")
      onNotSolved()
      return
    }

    const {kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece, placedPieces} = solver.solverStack.pop()

    // 追加ここから
    if (! spin) {
      onUpdatePieces(placedPieces)
      solver.timer = setTimeout(() => solver.solve(options), solver.speed)
      return
    }
    // 追加ここまで

    console.log("pieceId", pieceId)
    console.log("spinId", spinId)

    // 後略
  },
  // 後略
}

ここまでの実行結果

実行結果です。 ピースを戻すことによって、連続的に見えるようになりました。

f:id:yucatio:20191027141310p:plain

しかし1つのピースの配置が長く表示される場合が出てきてしまいました。2回以上同じ表示がされているためです。1度"戻す"表示をして、そのまま別のピースが置かれず、再度同じ表示がされています。

表示時間の制御

前回と同じ表示の場合は、すぐに次のスタックを呼ぶ出すように変更します。前回と同じ表示かは、state.placedPiecesと表示しようとするplacedPiecesの長さが同じかどうかで判定します。

const solver = {
  // 前略
  solve : (options) => {
    // 前略

    const {kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece, placedPieces} = solver.solverStack.pop()

    if (! spin) {
      // 変更ここから
      const timeout = state.placedPieces.length === placedPieces.length ? 0 : solver.speed
      onUpdatePieces(placedPieces)
      solver.timer = setTimeout(() => solver.solve(options), timeout)
      // 変更ここまで
      return
    }

    console.log("pieceId", pieceId)
    console.log("spinId", spinId)

    // 後略
  },
  // 後略
}

実行結果

実行結果です。フィールドに置かれたピースが等間隔で更新されるようになりました。

f:id:yucatio:20191027141701p:plain

以上でピースを戻す表示を追加することができました。

おわりに

以上でKATAMINOを解くプログラムのチュートリアルはおしまいです。おつかれさまでした!


★目次

yucatio.hatenablog.com