ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript 입문: 틱택토 게임 - 코딩 단순화 (이차원배열을 일차원배열로)
    컴퓨터 알아가기/JavaScript 2022. 8. 27. 19:30
    728x90
    반응형

    이 글은 제로초 TV의 자바스크립트 강좌를 기본으로 하고 있습니다. 

     

    틱택토 게임은 현재까지 정리한 바에 따르면 구성되는 코딩은 완료가 되었고 다른 사이트에서 참조하여 컴퓨터가 turn되는 코딩은 만들어 보았습니다. 코딩에는 왕도가 없어서 일단 프로그램이 돌아가면 성공이라고 보면 되고 얼마나 깔끔하게 정리하느냐가 실력이라고는 합니다만 프로그램이 돌아가기만 하면 기분은 좋네요. 

     

    오늘은 기존 코딩(이차원배열)을 일차원배열로 바꾸는 연습과 현 코딩을 가지고 역시 컴퓨터가 무작위로 'X'를 표시하여 마치 게임하는 듯한 모습을 공부하도록 합니다. 

     

    1. 이차원 배열을 일차원 배열로 

     

    3 by 3 테이블을 만들때 row를 먼저 반복하고 다음 column (cell)을 반복하는 이차원 배열을 다음과 같이 만들어 보았습니다. 이 목적은 각 cell을 지정하는 인덱스를 부여하기 위한 방법이었는데요. rowIndex와 celolIndex를 구하는 반복문이었구요. 

     

     

    여기서 cell 자체가 <td>이고 이는 곧 target입니다. 

    따라서 cellIndex는 target에 cellIndex를 같이 써주고 rowIndex는 target의 부모관계를 표시해 주면 됩니다. 

     

     

    원래 forEach를 통해서 rowIndex 와 cellIndex를 구하고자하는 목적이었기 때문에 target.cellIndex 자체가 ci 인 셀의 인덱스인겁니다. 

     

    cell의 바로위가 row이기 때문에 rowIndex 또한 parentNode를 같이 써 줌으로싸 부모노드에 연결 시켜 줄 수 있는 겁니다. 따라서 상기 코드와 같이 간단하게 각각의 인덱스를 지정할 수 있게 만들 수 있습니다. 이는 HTML의 특성을 이용한 방식으로 반대로 밑의 자식노드를 지정하고자 하면 target.children 처럼 사용하면 됩니다. 

     

    이제 중요한 각 cell의 인덱스를 구했기 때문에 승부를 판단함에 있어 이차원배열 (이중반복문)을 사용하는 승부판단 코딩도 줄일 수 있습니다. 결국 승부 판단에서 무승부일 경우 이중반복문을 돌리고 있는데요. 이 부분도 일차원 배열로 줄여서 cell기준으로 만들면 되겠습니다. 

     

    원래 무승부는 8칸까지만 차고 승부가 나지 않으면 무승부였는데 다른 방식으로는 9칸이 다 찰때까지 승부가 나지 않아야 무승부이기 때문에 다음과 같이 코딩을 할 수 있습니다. 

     

     

    즉, 무승부가 true라고 가정하고 9개 칸을 이차원배열로 확인하면서 칸이 차 있지 않으면 무승부가 아니다라고 false를 지정해 줍니다. 

     

    이러한 이차원배열을 일차원배열로 나타내기 위해서 .flat(  ) 메소드를 사용하고 일차원배열이 된 상태에서 모든 cell을 검사하면서 전부 문자가 있으면 무승부로 나타낼 수 있습니다. 다음과 같이 할 수 있습니다. 

     

     

    이와 같이 수정한 수 프로그램을 실행해 보면 기존과 같이 문제가 없이 잘 작동합니다. 

     

    이에 대한 전체 자바스크립트 코드는 다음과 같습니다. 

     

    // 변수
    const { body } = document; // 구조할당, document는 객체로 향후 생략 가능
    const $result = document.createElement('div'); // reult표시를 위해 <div>태그 만듦  
    let turn = 'O'; // 순서 변수
    
    // decisionWinner( ) 함수식 
    
    // ① 반복문을 통하여 각 칸에 있는 위치 지정
    const decisionWinner = (target) => { // target은 곧 cell이고 cellIndex
      const rowIndex = target.parentNode.rowIndex; // row는 cell의 부모노드, forEach가 필요없음
      const cellIndex = target.cellIndex; // cellIndex를 전부 가져오는 것, forEach가 필요없음
      
      // 승부 판단전 칸이 비어있는지 여부, 승자가 있는지 여부
      let existWinner = false;
      
      // 가로줄 검사 (각 칸의 세로가 맞아야)
      // [ [00], [01], [02] 
      //   [10], [11], [12] 
      //   [20], [21], [22] 
      // ]
      
      if (rows[rowIndex][0].textContent === turn &&
          rows[rowIndex][1].textContent === turn &&
          rows[rowIndex][2].textContent === turn) {
            existWinner = true;
          } 
      
      // 세로줄 검사 (각 칸 가로가 맞아야)
      
      if (rows[0][cellIndex].textContent === turn &&
          rows[1][cellIndex].textContent === turn &&
          rows[2][cellIndex].textContent === turn) {
            existWinner = true;
      } 
      
      // 대각선 검사
      
      if (rows[0][0].textContent === turn &&
          rows[1][1].textContent === turn &&
          rows[2][2].textContent === turn) {
            existWinner = true;
          }
    
      if (rows[0][2].textContent === turn &&
          rows[1][1].textContent === turn &&
          rows[2][0].textContent === turn) {
            existWinner =true;
          }   
      return existWinner;    
    }
    
    // 이차원 배열 3개 데이터(배열안에 배열)
    // 처음은 row 3개 만들고(tr) 두번째 cell 3개 만듦(td) 
    const rows = [];
    
    // callback 함수 밖으로 빼기 
    const turnback = (e) => { // 9개의 td를 클릭하기 위하여 
      console.log('clicked');  
      if (e.target.textContent !== '') { // 빈칸이 아니면
        console.log('빈칸이 아닙니다');
        return; // else 없애기 위해 (if의 if 중첩은 안좋음)
      } // 빈칸이면
      console.log('빈칸입니다.');
      e.target.textContent = turn; // 활성화 
    
      // 승부판단 위치 및 외부 함수로 빼기 위해 함수이름 만들기
      const whoWinner = decisionWinner(e.target);
      if (whoWinner) {
        $result.textContent = `${turn} 승리`;
        $table.removeEventListener('click', turnback);
        return;
      }
    
      // 무승부 검사  
      const number = rows.flat().every((cell) => cell.textContent); // 이차원배열을 일차원으로 .flat() 이용                                                                
      if (number) {
        $result.textContent = `무승부`;
        $table.removeEventListener('click', turnback);      
        return;
      } 
      
      turn = turn === 'O'? 'X' : 'O';
    }
    
    // 3 by 3 테이블 만들기 
    const $table = document.createElement('table'); // append를 위한 table 활성화 (1번)  
    for (let i = 0; i < 3; i++) { // 테이블안에 3개의 tr 만들기 (2번)
      const $tr = document.createElement('tr');
      const cells = [];
      for (let j = 0; j < 3; j++) { // tr안에 3개의 td 만들기 (3번)
        const $td= document.createElement('td');    
        cells.push($td); // cell에 td를 push
        $tr.append($td); // (3번)
      } 
      rows.push(cells);  
      $table.append($tr); // (2번)
    }
    $table.addEventListener('click', turnback);
    body.append($table); // 만든 테이블 전체 프레임 append (1번), document 생략
    body.append($result); // result 결과표시, document 생략
    반응형

    댓글

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Designed by Tistory.