# 자바스크립트 프로그래밍 시작하기: 2차원 배열 다루기

* 데이터를 2차원 배열로 관리하고 배열 데이터를 HTML 화면에 그대로 표시하는 작업

* 2차원 배열

: 배열을 포함하는 배열

(

(null, 'X', null)
('0', null, '0')
(null, '0', 'X')

)

* 테이블을 직접 그리기

– 작업 파괴

: 개체 내 속성 이름 및 할당할 변수 같은 경우 코드를 단축할 수 있습니다.

const body = document.body;   // 원래 코드 

const { body } = document;    // 구조 분해 할당
const obj = {a:1, b:2 };

const a = obj.a;
const b = obj.b;

// 구조분해할당 후 

const { a, b } = obj;
const arr = (1, 2, 3, 4, 5);

const one = arr(0);
const three = arr(2);
const four = arr(3);
const five = arr(4);

// 구조 분해 할당으로 코드 줄이기

const (one, , three, four, five) = arr;

// 두 번째 배열을 제외하려면 , , 하고 콤마 안을 빈칸으로 두면 알아서 스킵함

1분 퀴즈)

// a,c,e 속성을 구조분해할당 문법으로 변수에 할당해보세요 //


const obj = {

	a: 'hello'
    b: {
      c: 'hi',
      d: { e:  'wow' },
    },
  };
  
  
  
 const a = obj.a;
 const c = obj.b.c;
 const e = obj.b.d.e;
 
 // 구조 분해할당으로 코드 줄이기 후
 
 const { a, b: { c, d: { e } } } = obj;

– JS로 테이블 그리기

arr = (

 ($td, $td, $td),
 ($td, $td, $td),
 ($td, $td, $td),
 
)

arr (0)(1).textContent;   // 배열 첫번째 줄에 두번째 td

HTML)

<table>
      <tr>
        <td id="td00"></td>
        <td id="td01"></td>
        <td id="td02"></td>
      </tr>
      <tr>
        <td id="td10"></td>
        <td id="td11"></td>
        <td id="td12"></td>
      </tr>
      <tr>
        <td id="td20"></td>
        <td id="td21"></td>
        <td id="td22"></td>
      </tr>
    </table>

js)

const rows = (); // 줄을 저장할 공간을 배열로 만듦.


for(let i = 1; i <= 3; i++) {   // tr 3줄
    const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
    const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
    for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
        const $td = document.createElement('td'); // td를 선택하는 태그
        cells.push($td); // td의 내용을 cells 배열에 push 한다.
        $tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
    }
    rows.push(cells);
    $table.appendChild($tr);
}

body.appendChild($table);
body.appendChild($result);

* 회전 스위치

: addEventListener를 사용하여 클릭한 셀에 O를 입력합니다. 아래 내용 추가

let turn = 'O'; // turn은 o 

const callback = (e) => { 
    if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
        console.log('빈 칸이 아닙니다'); 
    } else {   // 클릭된 칸이 빈칸이면
        console.log('빈 칸입니다');
        e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
        turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
    //  if문으로 바꾸면
    //    if (turn === 'X') {
    //     turn = 'O';
    //    } else {
    //     turn = 'X';
    //    }
        
    }
};
$td.addEventListener('click', callback); // td칸이 클릭되면 callback 함수를 실행

– 추가 후 코드

let turn = 'O'; // turn은 o 

const callback = (e) => { 
    if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
        console.log('빈 칸이 아닙니다'); 
    } else {   // 클릭된 칸이 빈칸이면
        console.log('빈 칸입니다');
        e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
        turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
    //  if문으로 바꾸면
    //    if (turn === 'X') {
    //     turn = 'O';
    //    } else {
    //     turn = 'X';
    //    }
        
    }
};

for(let i = 1; i <= 3; i++) {   // tr 3줄
    const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
    const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
    for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
        const $td = document.createElement('td'); // td를 선택하는 태그
        $td.addEventListener('click', callback); // td칸이 클릭되면 callback 함수를 실행
        cells.push($td); // td의 내용을 cells 배열에 push 한다.
        $tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
    }
    rows.push(cells);
    $table.appendChild($tr);
}

body.appendChild($table);
body.appendChild($result);

* 이벤트 거품

: 자식 또는 자식 태그에서 이벤트가 발생하면 부모 및 부모 부모 태그에서 이벤트가 발생합니다.

즉, $td에 addEventListener를 적용하면 $tr, $table 모두에서 이벤트가 발생한다. (HTML 속성 기준)

$td.addEventListener('click', callback);

// 이벤트 버블링에 의해

$table.addEventListener('click', callback);

– 이벤트 거품 방지

event.stopPropagation();

* 이벤트 캡처

: 부모에게 발생한 사건이 자식에게로 가는 경우

* 게임을 결정

const { body } = document;
const $table = document.createElement('table');
const $result = document.createElement('div'); // 결과창
const rows = (); // 줄을 저장할 공간을 배열로 만듦.
let turn = 'O'; // turn은 o 


// (
//    (td, td, td),
//    (td, td, td),
//    (td, td, td),
// )


const checkWinner = (target) => {
    let rowIndex; // 몇 번째 줄인지
    let cellIndex;  // 몇 번째 칸인지
    rows.forEach((row, ri) => { // forEach는 인덱스를 제공해줌
        row.forEach((cell, ci) => {
        if( cell === target ) {
            rowIndex = ri;
            cellIndex = ci;
        }
    });
});
// 세 칸 다 채워졌나?
let hasWinner = false; // 검사할 때 시작은 false로 하고 승자가 있으면 true로 바꿔줌.
// 가로줄 검사
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 = (e) => { 
    if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
        console.log('빈 칸이 아닙니다'); 
    } else {   // 클릭된 칸이 빈칸이면
        console.log('빈 칸입니다');
        e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
        if (checkWinner(e.target)) {
            $result.textContent = `${turn}님이 승리!`;
            return;
        }
        // 무승부 검사
        let draw = true;
        rows.forEach((row) => {
            row.forEach((cell) => {
                if(!cell.textContent) {  // 한 칸이라도 비어있으면
                    draw = false;   // 무승부가 아님
                }
            });
        });
        if(draw) {   // 모든 칸이 차 있으면
            $result.textContent = `무승부`; // 무승부다.
            return;
        }
        turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
    //  if문으로 바꾸면
    //    if (turn === 'X') {
    //     turn = 'O';
    //    } else {
    //     turn = 'X';
    //    }
        
};
}

for(let i = 1; i <= 3; i++) {   // tr 3줄
    const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
    const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
    for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
        const $td = document.createElement('td'); // td를 선택하는 태그
     
        cells.push($td); // td의 내용을 cells 배열에 push 한다.
        $tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
    }
    rows.push(cells);
    $table.appendChild($tr);
}
$table.addEventListener('click', callback); // 이벤트버블링
body.appendChild($table);
body.appendChild($result);

******