フィールドにピースが置けるかどうかの判定 (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

前回まででスピンをどこに移動するか求めることができたので、今回はその位置に置けるかどうかを判定する関数を作成します。

ピースがフィールドに置ける条件は、以下の2点を満たすことです。

  • ピースがフィールドの外に出ていないこと
  • 置こうとする場所にすでに他のピースが置かれていないこと

置ける例↓

f:id:yucatio:20190722133633p:plain:w300

置けない例↓

f:id:yucatio:20190722133621p:plain:w300

実装

フィールドにスピンが置けるかを判定する、isAllEmpty関数とisEmpty関数を定義します。isAllEmptyは、スピンが置かれるすべてのマスが、フィールドの範囲内でまだピースが置かれていないときにtrueを返す関数です。 isEmptyは、placeの位置がフィールドの外でなく、かつまだピースが置かれていないときにtrueを返す関数です。

はじめに呼び出し側の実装をします。isAllEmptyでスピンが置けるか判定し、置けなかった場合には処理を中断し、ループの先頭に戻ります。

js/solver.js

const solver = {
    // 中略

  solve : () => {
    while (solver.solverStack.length > 0) {
      const {kataminoField, minEmpty, pieceId, spinId, spin, unPlacedPiece} = solver.solverStack.pop()

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

      const offset = {x: minEmpty.x, y: minEmpty.y - spin[0].y}

      // 追加ここから
      if (! solver.isAllEmpty(kataminoField, spin, offset)) {
        // フィールドの外か、すでにピースが置かれている
        console.log("フィールドの外か、すでにピースが置かれている")
        continue
      }

      console.log("ピースが置ける")
      // 追加ここまで
    }
  },

  // 追加ここから
  isAllEmpty: (kataminoField, places, offset) => {
    // TODO 実装
    return false
  },

  isEmpty: (kataminoField, place) => {
    // TODO 実装
    return false
  },
  // 追加ここまで
}

isAllEmptyからisEmptyを呼び出しましょう。Array.every ( Array.prototype.every() - JavaScript | MDN ) はコールバックに渡された関数が、配列のすべての要素に対して、true相当を返すかどうかを判定します。 isEmptyの引数には、スピンが実際に置かれるマスを渡すので、offsetをそれぞれ加算した値を渡しています。

  isAllEmpty: (kataminoField, places, offset) => {
    return places.every((place) => (
      solver.isEmpty(kataminoField, {x: place.x + offset.x, y: place.y + offset.y})
    ))
  },

次に、isEmpty関数を実装します。まずはplaceの位置がフィールドの内のときにtrueを返すようにします。JavaScriptの場合は、配列の定義外の範囲を参照するとundefinedが返ってくるので、それで判定します。place.xplace.yundefinedでなければフィールドの範囲内です。

  isEmpty: (kataminoField, place) => {
    return (
      kataminoField[place.x] !== undefined &&
      kataminoField[place.x][place.y] !== undefined
    )
  },

次に、置こうとする場所にすでに他のピースが置かれていないことを判定します。フィールドにピースが置かれているときはそのピースの番号、置かれていないときは-1なので、ピースが置かれているかどうかは0より小さいかどうかで判定します。

  isEmpty: (kataminoField, place) => {
    return (
      kataminoField[place.x] !== undefined &&
      kataminoField[place.x][place.y] !== undefined &&
      kataminoField[place.x][place.y] < 0
    )
  },

動作確認

動作結果です。コンソールの出力はこのようになっています。

f:id:yucatio:20190722162554p:plain

下記の図と対応させてみると、

f:id:yucatio:20190722141550p:plain

(pieceId, spinId) = (9, 1), (9, 0), (2, 7), (2, 1), (1, 7), (1, 3), (1, 1)

が初期状態で置けることが分かり、コンソールの出力結果と一致していることが分かります。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com