[Let's Get IT 자바스크립트]9장 이차원 배열 다루기_틱택토 게임

2022. 11. 1. 16:00자바스크립트

*본 게시물은 길벗IT의 [Let's Get IT 자바스크립트]를 토대로 만들어졌습니다. 저작권은 길벗IT에게 있습니다.

 

이차원 배열의 예제,

틱택토 게임은 (3X3)삼목 게임이라 생각하면 된다.

+전체코드는 맨 하단에 있다.

 

먼저 개념 정리를 하려고 하는데/ 이차원 배열, 구조분해 할당, 이벤트 버블링, parentNode/children, rowIndex/cellIndex, 유사 배열 객체, every/some, flat에 대해 배웠다.

 

1) 이차원 배열은 배열 안에 배열이 있을 때를 말한다. html의 표도 이차원 배열이라 할 수 있다. 다만 때에 따라 일차원 배열로도 표현은 가능하다.

[

  [null, 'X', null],

  ['O', 'X', 'X'],

  [null, 'O', ''X],

]

 

2) 구조분해 할당은 아래 코드처럼 객체 내부의 속성명과 변수명이 같을 때 줄여쓸 수 있는 것이다.

const {body} = document;

const body = document.body;

 

여러 줄을 한 줄로 표현하는 것도 가능하다.

예-1)

const a = obj.a;

const b = obj.b;

-> const {a, b} = objj

예-2)

const a = array[0];

const b = array[1];

const c = array[2];

-> const [a, b, c] = array;

 

3) 이벤트 버블링은 이벤트 발생 시 부모 태그에도 동일하게 이벤트가 발생하는 것으로, 예를 들어 td에서 클릭했으면 부모 태그인 tr과 그의 부모태그인 table에서도 클릭이 되어 이벤트가 발생하는 것이다.

+좋은점 : event.target과 event.currentTarget을 사용해서 여러개 이벤트를 하나의 이벤트로 구현가능(나중에 removeEventListener하기 편함)

 

4) 부모 태그 찾으려면 parentNode, 자식 태그 찾으려면 children 속성을 사용하면 된다.

 

5) 표에서 몇 번째 줄, 몇 번째 칸인지 알기 위해서는 rowIndex와 cellIndex 속성을 사용하면 된다.

const rowIndex = $tr.rowIndex; 

const cellIndex = $td.cellIndex;

 

6) children 속성같은 유사 배열 객체(array-like object)의 경우 Array.from 메서드를 사용해 배열로 바꿀 수 있다.

 

7) 배열에서 모든 값이 조건에 해당하는지 판단하려면 every메서드를 사용하고, 하나라도 조건에 해당하는지 판단하려면 some 메서드를 사용한다.

every -> 모두 다 true면 true, 하나라도 false면 false

some -> 하나라도 true면 true, 모두 다 false면 false

 

8) flat은 배열을 한차원씩 낮춰주는 메서드이다.


그럼 전체코드를 보면서 살펴보자.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>틱택토</title>
<style>
  table {
    border-collapse: collapse;
  }

  td {
    border: 1px solid black;
    width: 40px;
    height: 40px;
    text-align: center;
  }
</style>
</head>

<body>
<script>
  const { body } = document;
  // => const body = document.body;
  
  const $table = document.createElement('table');
  //누가 클릭했는지 메시지로 띄워줄 result
  const $result = document.createElement('div');
  const rows = [];
  let turn = 'O';
  
  //승부 검사 함수
  const checkWinner = (target) => {
    const rowIndex = target.parentNode.rowIndex;
    const cellIndex = target.cellIndex;
    //아래로 줄여 쓸 수 있음
    /*
    let rowIndex;
    let cellIndex;
    //forEach의 좋은점, 인덱스 알 수 있음
    rows.forEach((row, ri)=>{
        row.forEach((cell, ci)=>{
            if(cell == target){
                rowIndex = ri;
                cellIndex = ci;
            }
        });
    });
    */

    let hasWinner = false;
    // 가로줄 검사
    if (
      rows[rowIndex][0].textContent === turn &&
      rows[rowIndex][1].textContent === turn &&
      rows[rowIndex][2].textContent === turn
    ) {
      hasWinner = true;
    }
    // 세로줄 검사
    if (
      rows[0][cellIndex].textContent === turn &&
      rows[1][cellIndex].textContent === turn &&
      rows[2][cellIndex].textContent === turn
    ) {
      hasWinner = true;
    }
    // 대각선 검사
    if (
      rows[0][0].textContent === turn &&
      rows[1][1].textContent === turn &&
      rows[2][2].textContent === turn
    ) {
      hasWinner = true;
    }
    if (
      rows[0][2].textContent === turn &&
      rows[1][1].textContent === turn &&
      rows[2][0].textContent === turn
    ) {
      hasWinner = true;
    }
    return hasWinner;
  };


  const callback = (event) => {
  	//칸에 글자가 있나?
    if (event.target.textContent !== '') { 
      console.log('빈칸이 아닙니다.');
      return;
    }
    // 빈칸이면
    console.log('빈칸입니다');
    event.target.textContent = turn;
    // 승부 확인
    const hasWinner = checkWinner(event.target);
    if (hasWinner) {
      $result.textContent = `${turn}님이 승리!`;
      $table.removeEventListener('click', callback);
      return;
    }
    // 무승부 검사
    const draw = rows.flat().every((cell) => cell.textContent);
    if (draw) {
      $result.textContent = `무승부`;
      return;
    }
    turn = turn === 'X' ? 'O' : 'X';
  };

  for (let i = 1; i <= 3; i++) {
    const $tr = document.createElement('tr');
    const cells = [];
    for (let j = 1; j <= 3; j++) {
      const $td = document.createElement('td');
      cells.push($td);
      $tr.append($td);
    }
    rows.push(cells);
    $table.append($tr);
  }
  $table.addEventListener('click', callback);
  body.append($table);
  body.append($result);
</script>
</body>
</html>

+실행하면 이렇다!