yucatio@システムエンジニア

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

KATMINOを解くメインのプログラムの準備 (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

KATAMINOを解くメインのプログラムを作成します。 ディレクトリとhtmlファイルを用意しましょう。

KATAMINO-SOLVERフォルダの下に KATAMINO-SOLVER-mainという名前のフォルダを作成してください。

その下に index.htmlファイルを作成し、以下の内容を書き込んで保存します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>KATAMINO SOLVER</title>
  </head>
  <body>   
    <script src="js/util.js"></script>
    <script src="js/katamino-arr.js"></script>
    <script src="js/solver.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>

KATAMINO-mainフォルダの下に、jsフォルダを作成し、 その下にmain.jskatamino-arr.jssolver.jsutil.jsという名前の空のファイルを作成します。

それぞれのファイルは以下の用途で使用します。

ファイル 用途
main.js メインのプログラムを記載する
katamino-arr.js KATAMINOのピースのスピン情報を格納した配列を記載する
solver.js KATAMINOを解くプログラムを記載する
util.js ユーティリティ関数を記載する

ディレクトリ構成はこのようになっています。

KATAMINO-SOLVER/
  |_ KATAMINO-SOLVER-main/
  |   |_ index.html
  |   |_ js/
  |       |_ katamino-arr.js
  |       |_ main.js
  |       |_ solver.js
  |       |_ util.js
  |_ KATAMINO-SOLVER-preparation/
      |_ ....

KATAMINOのスピン情報を持つ配列の準備

js/katamino-arr.jsファイルに、KATAMINO-SOLVER-preparation/index.html で画面に表示された内容をコピーします。 手動コピーはかなり良くない方法だとは思いますが、他によい方法が見当たりませんでした。

f:id:yucatio:20190721171338p:plain

js/katamino-arr.js

const KATAMINO_ARR = [[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":0,"y":4}],[{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":3,"y":0},{"x":4,"y":0}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":0}],[{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":3,"y":0},{"x":3,"y":1}],[{"x":0,"y":3},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":1},{"x":3,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":1},{"x":3,"y":0},{"x":3,"y":1}],[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":3}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":0},{"x":2,"y":0},{"x":3,"y":0}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":0}],[{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1},{"x":3,"y":1}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":1}],[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":2}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0},{"x":3,"y":0}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0},{"x":3,"y":0}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],[{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":0}],[{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1},{"x":3,"y":1}],[{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":0},{"x":1,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":1}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":2,"y":0}],[{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":2},{"x":1,"y":2},{"x":2,"y":0},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":2},{"x":2,"y":2}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1}],[{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1}],[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":1},{"x":1,"y":2}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":2}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":0},{"x":2,"y":0},{"x":2,"y":1}],[{"x":0,"y":0},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2}],[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":0}],[{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":2}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":0}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1}],[{"x":0,"y":1},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":0},{"x":2,"y":1}],[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":2}],[{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":1},{"x":2,"y":1}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":0}],[{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":2}]],[[{"x":0,"y":0},{"x":0,"y":1},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":2}],[{"x":0,"y":1},{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0}],[{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1},{"x":2,"y":2}],[{"x":0,"y":2},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":0},{"x":2,"y":1}]],[[{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1}]]]

KATAMINOを解くプログラムの準備

js/solver.jsファイルの準備をします。以下の内容を記載してください。

const solver = {
  init : (targetPiece) => {
    console.log("init start")
    console.log("targetPiece", targetPiece)
  },

  solve : () => {
    console.log("solve start")
  },
}

targetPieceは、KATAMINOを解く対象のピースの配列です。例えば、[1, 2, 9]であれば、以下の3つのピースです。

f:id:yucatio:20190721171620p:plain

ピースの番号とピースの形一覧は以下になります。

f:id:yucatio:20190721171738p:plain

main.jsの準備

solver.jsを呼び出すmain.jsの準備をします。

js/main.js

solver.init([1,2,9])

solver.solve()

動作確認

index.htmlを開きましょう。引き続きGoogle Cromeを使用します。 ディベロッパーツールを表示します。Windowsの場合はF12キー、Macの場合はCommandOptionIキーで開きます。 コンソールを開きます。以下のように表示されていれば成功です。

f:id:yucatio:20190721173110p:plain

以上でKATMINOを解くメインのプログラムの準備は完了です。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

2次元配列からピースがある場所のリストを作成する (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

2次元配列からピースがある場所のリストを作成します。こちらの記事を参考にしてください。

yucatio.hatenablog.com

現在はピースを以下のように2次元配列で表現しています。ピースの場所を1, ピースでない場所を0で表現しています。

f:id:yucatio:20190620083647p:plain:w200

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

ここからリストの形式に変換します。

f:id:yucatio:20190620084008p:plain:w200

[
  {x:0, y:0},
  {x:0, y:1},
  {x:1, y:1},
  {x:2, y:1},
  {x:2, y:2}
]

実装

2次元配列を受け取り、値が1のインデックスのリストを作成する関数matrixToListを作成します。

function matrixToList(spin) {
  // 変換後の値を格納する配列
  const places = []
  spin.forEach((row, i) => {
    row.forEach((value, j) => {
      if (value === 1) {
        // 値が1だったら場所を変換後の配列に追加する
        places.push({x:i, y:j})
      }
    })
  })
  return places
}

2重のループを回して、値が1のときは、その時のインデックスを配列に追加しています。

createKataminoSpinListからこの関数を呼び出します。

function createKataminoSpinList(piece) {
  // 回転した形を格納する配列
  let spinArray = []

  spinArray[0] = copyArrayOfArray(piece)
  // 中略
  spinArray[4] = transpose(spinArray[3])

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

  // 各スピンをリストの形式に変換する
  const spinLists = uniqSpinArr.map((uniqSpin) => matrixToList(uniqSpin))
  console.log("spinLists", spinLists)

  return spinLists
}

動作確認

実行結果です。ピースが置かれている場所のリストが表示されました。

f:id:yucatio:20190716084053p:plain

リファクタリング

matrixToListreducefiltermapなどを使って一時的な配列を宣言せず記述することも可能ですが、 現在のままの方がわかりやすいので、このままにします。

仕上げ

最後に、作成した関数を画面に表示します。

const KATAMINO_ARRAY = KATAMINO_ORG_ARRAY.map((piece, pieceId) => createKataminoSpinList(piece, pieceId))

document.write("const KATAMINO_ARR = " + JSON.stringify(KATAMINO_ARRAY))

function createKataminoSpinList(piece) {
  // 略
}

実行結果です。この結果を次回使用します。

f:id:yucatio:20190721112716p:plain

以上で2次元配列からピースがある場所のリストを作成することができました。KATAMINOを解くためのピースの準備がこれで整いました。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

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

8パターンのスピンを作成する (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

前回までで、ピースの転置・反転のプログラムが作成できたので、残りのピースを作成します。 8パターンのスピンの作成については以下の記事を参照してください。

yucatio.hatenablog.com

各spinは0番を始めとして矢印の順番で生成します。

f:id:yucatio:20190702083723p:plain

前回までで0番と7番、1番のスピンを作成したので、今回は残りの6、2、5、3、4番を順に作成します。

function createKataminoSpinList(piece) {
  // 回転した形を格納する配列
  let spinArray = []

  spinArray[0] = copyArrayOfArray(piece)
  // 0番を転置したものが7番
  spinArray[7] = transpose(spinArray[0])
  // 7番をコピーして上下反転したものが1番
  spinArray[1] = copyArrayOfArray(spinArray[7]).reverse()
  // 1番を転置したものが6番
  spinArray[6] = transpose(spinArray[1])
  // 6番をコピーして上下反転したものが2番
  spinArray[2] = copyArrayOfArray(spinArray[6]).reverse()
  // 2番を転置したものが5番
  spinArray[5] = transpose(spinArray[2])
  // 5番をコピーして上下反転したものが3番
  spinArray[3] = copyArrayOfArray(spinArray[5]).reverse()
  // 3番を転置したものが4番
  spinArray[4] = transpose(spinArray[3])

  console.log("spinArray", spinArray)

  return spinArray
}

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

f:id:yucatio:20190715140542p:plain

上記は以下の8つのスピンを表しています。(上記画像では7個しか表示されていませんので、実行結果をご自身でご確認ください)

f:id:yucatio:20190715140644p:plain

ちなみに、以下のようにインデックス0,1,2..の順に格納しなかったのは、画面にスピンを順に表示したときに、裏返さず同じ向きで回転させた方がきれいだからです。

function createKataminoSpinList(piece) {
  // 回転した形を格納する配列を宣言する
  let spinArray = []

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

  console.log("spinArray", spinArray)

  return spinArray
}

以上で各ピース、8パターンのスピンを作成することができました。

配列の中身は現在以下の図のように、各ピースに重複したスピンが含まれています。

f:id:yucatio:20190621121150p:plain

次回は重複を取り除いていきます。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

JavaScriptで2次元配列のコピーと配列の反転 (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

ピースの反転を行うために2次元配列の反転を行います。8パターンのスピンの作成については以下の記事を参照してください。

yucatio.hatenablog.com

各spinは0番を始めとして矢印の順番で生成します。

f:id:yucatio:20190702083723p:plain

前回は0番のスピンから7番のスピンを作成しました。今回は7番の形から1番のスピンを作成します。

配列の反転は、JavaScriptではreverse (Array.prototype.reverse() - JavaScript | MDN) という関数が用意されていますので、これを使います。

例えば、こちらのピースだと、

f:id:yucatio:20190708084544p:plain

配列表現はこのようになっています。

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

この配列のreverseは以下のようになります。

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

この配列は、このスピンを表しています。上下反転しています。

f:id:yucatio:20190708084820p:plain

ただし、reverseはもとの配列を変更してしまうので、一旦配列をコピーする必要があります。2次元配列をコピーする関数copyArrayOfArrayを用意し、そのコピーに対してreverseを呼び出しましょう。 コードは以下のようになります。copyArrayOfArrayの実装は一旦仮にしてあります。

function createKataminoSpinList(piece) {
  // 回転した形を格納する配列
  const spinArray = []

  // 受け取ったピースを格納する
  spinArray[0] = piece
  console.log("spinArray[0]", spinArray[0])
  // 0番を転置したものが7番
  spinArray[7] = transpose(spinArray[0])
  console.log("spinArray[7]", spinArray[7])
  // 7番をコピーして上下反転したものが1番
  spinArray[1] = copyArrayOfArray(spinArray[7]).reverse()
  console.log("spinArray[1]", spinArray[1])
}

function copyArrayOfArray(arrayOfArray) {
  // TODO 実装
  return arrayOfArray
}

copyArrayOfArrayを実装していきます。forEachの2重ループを使用して、新しい配列に値をコピーします。

function copyArrayOfArray(arrayOfArray) {
  // arrayOfArrayと同じサイズの配列を定義し、各インデックスを空の配列で初期化する
  let copied = arrayOfArray.map(() => [])

  arrayOfArray.forEach((row, i) => {
    row.forEach((value, j) => {
      copied[i][j] = value
    })
  })
  
  return copied
}

実行結果

7番のピースを上下反転したものがコンソールに表示されて入れば成功です。

f:id:yucatio:20190708110656p:plain

リファクタリング

配列の各要素をコピーするのには、スプレッド構文が便利です。

function copyArrayOfArray(arrayOfArray) {
  return arrayOfArray.map(array => ([...array]))
}

下記のように書くと中の配列の中の配列はコピーされず、参照が残ったままとなってしまうのでNGです。

function copyArrayOfArray(arrayOfArray) {
  // このように書くのはNG
  return [...arrayOfArray]
}

以上で2次元配列のコピーと配列の反転を行うことができました。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

JavaScriptで転置を実装する (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

ピースの回転、反転を行うために2次元配列の転置を行います。転置を行う理由については以下の記事を参照してください。

yucatio.hatenablog.com

各spinは0番を始めとして以下の順番で生成します。

f:id:yucatio:20190702083723p:plain

はじめに0番目のスピンから7番目のスピンを作成します。

コーディング

プログラミングしていきます。 まず、回転した形を格納する配列を宣言し、0番に受け取ったピースを格納します。

0番を転置して7番のspinを作成します。転置を行う関数(transpose)は一旦仮の実装にしてあります。

function createKataminoSpinList(piece) {
  // 回転した形を格納する配列
  let spinArray = []

  // 受け取ったピースを格納する
  spinArray[0] = piece
  console.log("spinArray[0]", spinArray[0])
  // 0番を転置したものが7番
  spinArray[7] = transpose(spinArray[0])
  console.log("spinArray[7]", spinArray[7])
}

/*
 * 2次元配列の転置をする
 */ 
function transpose(spin) {
  // TODO 実装
  return spin
}

transposeを実装していきましょう。もとの配列が2*3の配列だとしたら、転置後は3*2の配列になります。JavaScriptでは2次元配列を宣言する構文はないので、配列を宣言後、その配列の各要素にさらに配列を入れます。

転置するには、1番目と2番目のインデックスを入れ替える必要があるので、forEachの2重ループを使います。

function transpose(spin) {
  // 転置した配列
  let transposed = []

  // 2次元配列に初期化する
   spin[0].forEach((_, i) => {
     transposed[i] = []
   })

  // 1番目のインデックスと2番目のインデックスを入れ替える
  spin.forEach((row, i) => {
    row.forEach((value, j) => {
      transposed[j][i] = value
    })
  })

  return transposed
}

実行結果

それぞれのピースを転置したものがコンソールに表示されて入れば成功です。

f:id:yucatio:20190705231827p:plain

リファクタリング

ネットを検索したところ、transposeは以下のようにリファクタリングできます。 理解に時間がかかりますが、こちらを採用しても良いでしょう。

function transpose(spin) {
  return  spin[0].map((_, i) => spin.map(row => row[i]));
}

先ほど作成したプログラムで、最初の配列の配列を準備するところだけ、以下のようにspin[0]の数だけ空で初期化された配列を用意する方法にしてもよいです。

function transpose(spin) {
  let transposed = spin[0].map(() => [])

  spin.forEach((row, i) => {
    row.forEach((value, j) => {
      transposed[j][i] = value
    })
  })

  return transposed
}

以上で転置を実装して、7番の行列を得ることができました。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

最終的に出来上がる配列の確認と関数の準備 (KATAMINOを解くプログラムを作成する)

★前回の記事

yucatio.hatenablog.com

前回、もととなるピースの配列を作成しました。 ここから各ピースを転置・反転したものを作成していきます。

現在各ピースは、

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

のように2次元配列で表現されています。これを最終的には(最大で)8種類の回転・反転したものを求め、ピースが存在する場所のリストで表します。

例えば、以下のピースだと、

f:id:yucatio:20190704073902p:plain

もとの配列は以下で、

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

最終的に作成する配列は以下のようになります。

[
  [{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":1}],  // 0番のspin
  [{"x":0,"y":0},{"x":1,"y":0},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":0}],  // 1番のspin
  [{"x":0,"y":2},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],  // 2番のspin
  [{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":1},{"x":3,"y":1}],  // 3番のspin
  [{"x":0,"y":1},{"x":1,"y":0},{"x":1,"y":1},{"x":1,"y":2},{"x":1,"y":3}],  // 4番のspin
  [{"x":0,"y":1},{"x":1,"y":1},{"x":2,"y":0},{"x":2,"y":1},{"x":3,"y":1}],  // 5番のspin
  [{"x":0,"y":0},{"x":0,"y":1},{"x":0,"y":2},{"x":0,"y":3},{"x":1,"y":2}],  // 6番のspin
  [{"x":0,"y":0},{"x":1,"y":0},{"x":1,"y":1},{"x":2,"y":0},{"x":3,"y":0}]   // 7番のspin
]

この配列の各要素と順番は以下の8種類の回転・反転に対応しています。(参考:

yucatio.hatenablog.com

)

f:id:yucatio:20190704075922p:plain

これ以降、この各回転・反転のことをスピン(spin)と呼びます。

プログラミングしていきましょう。 KATAMINO_ORG_ARRAYの各要素を変換していくので、map関数を使います。mapの中で、createKataminoSpinList関数を呼んでいます。この関数は、各ピースから、そのピースのスピンを求め、それぞれのスピンのピースの場所をリストで表現したものを返します。

const KATAMINO_ARRAY = KATAMINO_ORG_ARRAY.map(piece => createKataminoSpinList(piece))

/*
 * 各ピースを回転・反転した時のピースの場所のリストを作成する
 */
function createKataminoSpinList(piece) {
  console.log("piece", piece)

  return piece
}

出力が以下のようになっていればOKです。

f:id:yucatio:20190704075327p:plain

以上で最終的に出来上がる配列とmapを使用してピースの回転リストを作成する準備ができました。


★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com