JavaScriptで2次元配列の重複を取り除く (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

前回までで8パターンの回転・反転パターンを作成することができましたが、いくつかのピースについては重複があります。例えばこちら↓

f:id:yucatio:20190715141354p:plain

このピースの配列は、下記のようになってます。

[
  [
    [1,1,1],
    [1,0,1]
  ],
  [
    [1,1],
    [1,0],
    [1,1]
  ],
  [
    [1,0,1],
    [1,1,1]
  ],
  [
    [1,1],
    [0,1],
    [1,1]
  ],
  [
    [1,0,1],
    [1,1,1]
  ],
  [
    [1,1],
    [0,1],
    [1,1]
  ],
  [
    [1,1,1],
    [1,0,1]
  ],
  [
    [1,1],
    [1,0],
    [1,1]
  ]
]

0番と6番、1番と7番、2番と4番、3番と5番がそれぞれ重複しています。 これからその重複を取り除いていきます。

JavaScriptで配列の重複を取り除くイディオムとして、以下があります。

array.filter((value, i, self) =>
  self.indexOf(value) === i
)

Array.filter ( Array.prototype.filter() - JavaScript | MDN ) のコールバックに渡した関数は、配列の各値(value)が配列の最初に出てくる時のみtrueとなります。2回目以降の同じ値はコールバックがfalseを返すので、重複が削除された配列を得ることができます。

ただし、今回のように2次元配列の重複を取り除くのに、上記はうまく動作しません。 indexOfの内部では、===でオブジェクト同士を比較します。配列の比較の場合、配列の内容が同じでも、違うオブジェクトだと、===の比較ではfalseとなります。 そこで、代わりにfindIndex ( Array.prototype.findIndex() - JavaScript | MDN )を使用します。findIndexでは等しいかどうかを判定するコールバックを渡すことができます。

2次元配列の値同士が等しいかどうか、公式でサポートされている簡単な方法はありません。今回は、JSON.stringify ( JSON.stringify() - JavaScript | MDN ) を用いて配列をJSON文字列に変換して比較します。

重複を取り除くuniqSpin関数は以下のようになります。

function uniqSpin(spinArray) {
  return spinArray.filter((spin, index, array) => (
      index === array.findIndex((spinAnother) => (
        JSON.stringify(spin) === JSON.stringify(spinAnother)
      ))
  ))
}

array.findIndexの中で、spinと同じ内容をもつ、一番初めのindexを検索しています。

次にuniqSpin関数をcreateKataminoSpinList関数から呼び出します。

function createKataminoSpinList(piece) {
  let spinArray = []
  spinArray[0] = copyArrayOfArray(piece)
  spinArray[7] = transpose(spinArray[0])
  spinArray[1] = copyArrayOfArray(spinArray[7]).reverse()
  spinArray[6] = transpose(spinArray[1])
  spinArray[2] = copyArrayOfArray(spinArray[6]).reverse()
  spinArray[5] = transpose(spinArray[2])
  spinArray[3] = copyArrayOfArray(spinArray[5]).reverse()
  spinArray[4] = transpose(spinArray[3])

  // スピンの重複を取り除く
  const uniqSpinArr = uniqSpin(spinArray)

  console.log("uniqSpinArr", uniqSpinArr)

  return uniqSpinArr
}

実行してみて、下記のようになって入れば成功です。

f:id:yucatio:20190715230731p:plain

以上で2次元配列の重複を取り除くことができました。ここまでで配列の内容は以下のようになっています。

f:id:yucatio:20190621083130p:plain


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com