🍐

【Vue】includesでは配列に特定の1次元配列が含まれているかチェックできなかった

2024/10/25に公開

Vueでオセロを作っていて、2次元配列の中に1次元配列が含まれているかチェックしたいときにincludesが使えないということを学んだのでメモします。

オセロを作るにあたり、盤上のマスを[行,列]で[[1,1][1,2],...[8,8]]としていて、すでに石が置かれているマスや黒い石を置いてるマス、白い石を置いているマス、を2次元配列として管理しています。

試合が始まるときはこんな感じ

const usedCells = ref([[4, 4], [5, 5], [4, 5], [5, 4]]);
const blackCells = ref([[4, 5], [5, 4]]);
const whiteCells = ref([[4, 4], [5, 5]]);

すでに石が置かれているマスには石を置けないので、クリックしたマスがusedCellsに含まれていないかを確認したり、石を置いた隣のマスの状態を確認するために、隣のマスがblackCellsに含まれているかを確認したいことが頻繁に起こりました。

includesを使った場合

まず配列の中身チェックということで、最初に試したのがincludesメソッド。
ただ、この場合はうまくいきませんでした。

usedCellsにクリックしたマスが含まれているかどうかを確認するために以下のコードを用意し[4,5]のマスをクリックしました。

const usedCells = ref([[4, 4], [5, 5], [4, 5], [5, 4]]);
const selectCell = (cell) => {
    selectedCell.value = cell;
    const check = usedCells.value.includes(selectedCell.value);
    console.log(check);
}

[4,5]はusedCellsに含まれているので、trueが返ってきてほしいところですが、結果はfalseでした。
CuesorのAIさんに理由を聞いたところ以下の回答でした。

includes メソッドは、配列内に特定の要素が存在するかどうかを確認しますが、配列の要素がオブジェクトや配列の場合、参照の比較が行われるため、期待通りに動作しないことがあります。具体的には、selectedCell.value が usedCells.value 内の配列と同じ内容を持っていても、異なる参照を持つため、includes は false を返します。

someメソッドを使った場合

someメソッドは配列から1つずつ要素を取り出して正誤判定してくれます。
配列の要素が1つでも正になれば、正を返してくれます。

includesメソッドでは判定できなかったusedCellsのチェックをsomeメソッドを使って判定してみます。

const usedCells = ref([[4, 4], [5, 5], [4, 5], [5, 4]]);
const selectCell = (cell) => {
    selectedCell.value = cell;
    const check = usedCells.value.some(usedCell => usedCell[0] === selectedCell.value[0] && usedCell[1] === selectedCell.value[1]);
    console.log(check);
}

これで[4,5]のマスをクリックするとちゃんとtrueが返ってきます。
そして、usedCellsに含まれていないマスをクリックしたらfalseを返してくれます。
includesメソッドではうまくできなかった正誤判定をsomeメソッドならうまくやってくれそうです。

詳細メモ

パッと見でsomeメソッドが何をしてくれているのか分かりにくかったので、メモです。

usedCells.value.some(usedCell => usedCell[0] === selectedCell.value[0] && usedCell[1] === selectedCell.value[1]);

usedCells(複数形)はあらかじめ定義している2次元配列で、[4, 4], [5, 5], [4, 5], [5, 4]の4つの要素が入っています。

const usedCells = ref([[4, 4], [5, 5], [4, 5], [5, 4]]);

()の中で使われているusedCell(単数形)にはusedCells(複数形)の要素が一つずつ入り、=>の後ろの正誤判定をusedCellsに入っている要素の個数分の繰り返して行われるイメージです。

※usedCell(単数形)は分かりやすく単数形にしただけで、ここの変数名は何でもいいです。

selectedCellにはクリックしたマスの[行,列]が入っているので[4,5]のマスをクリックしたら
selectedCell.value[0]は4、selectedCell.value[1]は5がになっています。

usedCellにも[行,列]が入っているので、=>の後ろの処理はusedCellとselectedCellの[行,列]がどちらも同じ場合だけtrueを返します。

usedCell[0] === selectedCell.value[0] && usedCell[1] === selectedCell.value[1]

[4,5]のマスをクリックした時の処理としては以下のイメージです。
1回目:usedCellsの1個目の[4,4]と比べて列が違うからfalse
2回目:usedCellsの1個目の[5,5]と比べて 行が違うからfalse
3回目:usedCellsの1個目の[4,5]と比べて行も列も同じだからtrue
4回目:usedCellsの1個目の[5,4]と比べて行も列も違うからfalse

そして、someメソッドとしては「3回目がtrueだったのでtrueを返しますね」という結果になっています。

※厳密にはsomeメソッドはtrueが返ってきたらすぐに処理をやめるようですが、配列の個数回繰り返すとイメージする方がわかりやすいので、ここでは気にしないことにしてます。

Discussion