JavaScriptで三目並べの勝利判定を実装する

そろそろ、勝利を判定して勝者の名前を表示するコードを書く時が来ました。

課題を考えてみると、勝利の有無は毎ターン確認すべきであることがわかります。

javascriptfunction init(selector) {
  let cells = document.querySelectorAll('#field td');
  let i = 0;
  
  for (let cell of cells) {
    cell.addEventListener('click', function step() {
      this.textContent = ['X', 'O'][i % 2];
      this.removeEventListener('click', step);
      
      // ここで勝利または引き分けをチェックする必要がある
      
      i++;
    });
  }
}

セルの配列をパラメータとして受け取り、フィールドに勝利条件があればtrueを、なければfalseを返す関数isVictoryを作成しましょう。 この関数は次のように使用します。

javascriptfunction start(cells) {
  let i = 0;
  
  for (let cell of cells) {
    cell.addEventListener('click', function step() {
      this.textContent = ['X', 'O'][i % 2];
      this.removeEventListener('click', step);
      
      if (isVictory(cells)) {
        alert('勝者の名前');
      }
      
      i++;
    });
  }
}

どうすれば勝者の名前がわかるでしょうか?明らかに、その名前は勝利条件を満たした各セルに格納されています。 説明しましょう:勝利があるということは、水平、垂直、または斜めのいずれかの方向にある3つのセルが同じ値(XまたはO)を持っているということです。

明らかに、これらのセルのいずれかの値が勝者の名前です。 しかし、より直接的でない別の方法を取ることもできます:勝利の有無を毎ターン確認しているのであれば、最後の手を指したプレイヤーが勝者であると考えるのが論理的です。 このプレイヤーの名前は、クリックされたセルのテキストに含まれています。

javascriptfunction start(cells) {
  let i = 0;
  
  for (let cell of cells) {
    cell.addEventListener('click', function step() {
      this.textContent = ['X', 'O'][i % 2];
      this.removeEventListener('click', step);
      
      if (isVictory(cells)) {
        alert(this.textContent); // 勝者の名前を表示
      }
      
      i++;
    });
  }
}

isVictoryの実装

フィールド上の勝利を技術的にどのように判定すればよいでしょうか? よく考えてみると、フィールド上の3つ組のセルの組み合わせは限られた数しかないという結論に達することができます。

つまり、勝利を判定するには、単純にこれらすべての3つ組をチェックすればよいのです。 3つ組が同じ空でない値(つまりXまたはO)を持っているかどうかをチェックする必要があります。

二次元配列を作成し、各サブ配列に3つ組のいずれかのセルの番号を格納しましょう。

javascriptlet combs = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8],
  [0, 3, 6],
  [1, 4, 7],
  [2, 5, 8],
  [0, 4, 8],
  [2, 4, 6],
];

この配列を使用して勝利判定を記述しましょう。

javascriptfunction isVictory(cells) {
  let combs = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  for (let comb of combs) {
    if (
      cells[comb[0]].textContent == cells[comb[1]].textContent &&
      cells[comb[1]].textContent == cells[comb[2]].textContent &&
      cells[comb[0]].textContent != ''
    ) {
      return true;
    }
  }
  
  return false;
}
Задание 1

私のコードを見ずに、自分で説明された内容を実装してください。ゲームプレイがどのように機能するか確認してください。

Задание 2

引き分けの判定を実装してみてください。次のレッスンでこの部分の解説を行います。