본문 바로가기
개발/Javascript

[js] 자바스크립트로 틱택토(심화버전) 구현하기

by 코딩하는 갓디노 2021. 1. 10.

 

이전 포스팅에서 구현했던 
틱택토 게임에서 업그레이드된 심화 과정입니다. 



 

예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다.


틱택토 구현 BEFORE 버전은 아래 포스트로 이동하세요.

https://goddino.tistory.com/102

 

[js] 자바스크립트로 틱택토 구현하기

자바스크립트를 이용하여, 틱택토(Tic Tac Toe) 게임을 구현하는 예제입니다. 예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다. 순서도 css 코드 순수 자바스크립트 코드

goddino.tistory.com


 

추가 구현 기능: 
· 컴퓨터의 턴(나의 턴: X/컴퓨터의 턴: O)
· 무승부일 경우

 

자바스크립트 코드

컴퓨터의 턴

 

순수자바스크립트 코드(컴퓨터의 턴)

let table = document.createElement('table');
let row = []; 
let col = []; 
let turn = 'X'; 

let clickFn = function(e) {
  e.target;
  let rowNo = row.indexOf(e.target.parentNode);
  console.log('줄번호', rowNo);
  let colNo = col[rowNo].indexOf(e.target);
  console.log('칸번호', colNo);

  if (col[rowNo][colNo].textContent !== "") { //빈칸이 아닐 경우 
    console.log('다른 칸을 클릭하세요.');
  } else { //빈칸이면
    col[rowNo][colNo].textContent = turn; //턴 체크
    //위치 중요(턴 패스하기 전)
    //3줄 빙고 확인
    let bingo = false;
    //가로줄 검사
    if (col[rowNo][0].textContent === turn &&
      col[rowNo][1].textContent === turn &&
      col[rowNo][2].textContent === turn) {
      bingo = true;
    }

    //세로줄 검사
    if (col[0][colNo].textContent === turn &&
      col[1][colNo].textContent === turn &&
      col[2][colNo].textContent === turn) {
      bingo = true;
    }

    //대각선 검사 //좌상->우하 대각선 검사
    if (col[0][0].textContent === turn &&
      col[1][1].textContent === turn &&
      col[2][2].textContent === turn) {
      bingo = true;
    }
    if (col[0][2].textContent === turn &&
      col[1][1].textContent === turn &&
      col[2][0].textContent === turn) {
      bingo = true;
    }

    //빙고일 경우 //bingo = true
    if (bingo) {
      result.textContent = `WINNER는 ${turn}님 축하드립니다`;
      //초기화
      turn = 'X';
      //배열의 반복문 forEach - 아처원 배열이므로 forEach 2번 필요
      col.forEach(function(row) {
        row.forEach(function(td) {
          td.textContent = '';
        });
      });
    } else { //빙고가 안되었으면    
      if (turn === 'X') {
        turn = 'O';
      }
      //1초 후 컴퓨터 턴 표시
      setTimeout(function() {
        console.log('컴퓨터의 턴입니다.');
        //빈칸 중 하나를 고름
        let candidates = [];
        //모든 칸들을 candidates으로 넣은 후, 그 중에서 filter()로 빈칸만 고름
        col.forEach(function(row) {
          row.forEach(function(td) {
            candidates.push(td);
          })
        });
        //filter()로 return값이 true인 것(빈칸)만 추출하여 새 배열을 반환
        candidates = candidates.filter(function(el) {
          return el.textContent == "" //빈값 = "", false, null, NaN, 0, return !el.textContent 와 같은 의미
        });
        //candidates중 랜덤으로 한개 추출
        let computerChoice = candidates[Math.floor(Math.random() * candidates.length)];
        computerChoice.textContent = 'O';
        //컴퓨터가 승리했는지 체크
        //3줄 빙고 확인
        let bingo = false;
        //가로줄 검사
        if (col[rowNo][0].textContent === turn &&
          col[rowNo][1].textContent === turn &&
          col[rowNo][2].textContent === turn) {
          bingo = true;
        }

        //세로줄 검사
        if (col[0][colNo].textContent === turn &&
          col[1][colNo].textContent === turn &&
          col[2][colNo].textContent === turn) {
          bingo = true;
        }

        //대각선 검사 //좌상->우하 대각선 검사
        if (col[0][0].textContent === turn &&
          col[1][1].textContent === turn &&
          col[2][2].textContent === turn) {
          bingo = true;
        }
        if (col[0][2].textContent === turn &&
          col[1][1].textContent === turn &&
          col[2][0].textContent === turn) {
          bingo = true;
        }

        //빙고일 경우 //bingo = true
        if (bingo) {
          result.textContent = `WINNER는 ${turn}님 축하드립니다`;
          //초기화
          turn = 'X';
          col.forEach(function(row) {
            row.forEach(function(td) {
              td.textContent = '';
            });
          });
        }

        //턴을 나한테 넘김
        turn = 'X';
      }, 1000)
    }
  }
}

 

코드 리팩토링

· 중복되는 부분 함수로 설정
· 함수로 설정하면서 생기는 스코프 에러 문제 변수 위로 위치 설정
· 컴퓨터의 턴일 경우, 클릭 방지
· 초기화 1초 뒤로 설정
· 무승부 결과 출력

 

전체 코드

<!DOCTYPE html>
<html lang="ko">

  <head>
    <meta charset="UTF-8">
    <title>틱택토 심화</title>
    <style>
      table {
        border-collapse: collapse;
      }

      td {
        width: 60px;
        height: 60px;
        border: 1px solid #666;
        font-size: 30px;
        text-align: center;
      }

    </style>
  </head>

  <body>
    <script>
      let table = document.createElement('table');
      let row = [];
      let col = [];
      let turn = 'X';
      let result = document.createElement('div');
      //리팩토링: 스코프 문제 변수 위치 수정
      let bingo = '';
      let rowNo = '';
      let colNo = '';

      //리팩토링: 함수 설정
      function bingoCheck() {
        bingo = false;
        //가로줄 검사
        if (col[rowNo][0].textContent === turn &&
          col[rowNo][1].textContent === turn &&
          col[rowNo][2].textContent === turn) {
          bingo = true;
        }

        //세로줄 검사
        if (col[0][colNo].textContent === turn &&
          col[1][colNo].textContent === turn &&
          col[2][colNo].textContent === turn) {
          bingo = true;
        }

        //대각선 검사 //좌상->우하 대각선 검사
        if (col[0][0].textContent === turn &&
          col[1][1].textContent === turn &&
          col[2][2].textContent === turn) {
          bingo = true;
        }
        if (col[0][2].textContent === turn &&
          col[1][1].textContent === turn &&
          col[2][0].textContent === turn) {
          bingo = true;
        }
      }

      //리팩토링: 함수 설정
      function reset(tie) { //매개변수로 무승부/승부 처리
        if (tie) { //if = true 일 경우
          result.textContent = `무승부 입니다`;
        } else { //if = false 일 경우
          result.textContent = `WINNER는 ${turn}님 축하드립니다`;
        }

        //리팩토링: 1초 후 초기화
        turn = 'X';
        setTimeout(function() {
          result.textContent = '';
          col.forEach(function(row) {
            row.forEach(function(td) {
              td.textContent = '';
            });
          });
        }, 1000);
      }

      let clickFn = function(e) {
        //리팩토링: 컴퓨터의 턴일때 클릭 방지
        if (turn === 'O') {
          return;
        }
        e.target;

        rowNo = row.indexOf(e.target.parentNode);
        console.log('줄번호', rowNo);
        colNo = col[rowNo].indexOf(e.target);
        console.log('칸번호', colNo);

        if (col[rowNo][colNo].textContent !== "") { //빈칸이 아닐 경우 
          console.log('다른 칸을 클릭하세요.');
        } else { //빈칸이면
          col[rowNo][colNo].textContent = turn; //턴 체크

          bingoCheck(); //리팩토링 함수 콜

          //리팩토링 무승부
          //모든 칸이 다 찼는지 검사
          let candidates = [];
          //모든 칸들을 candidates으로 넣은 후, 그 중에서 filter()로 빈칸만 고름
          col.forEach(function(row) {
            row.forEach(function(td) {
              candidates.push(td);
            })
          });
          candidates = candidates.filter(function(el) {
            //빈값 = "", false, null, NaN, 0, return !el.textContent 와 같은 의미
            return el.textContent == "";
          });

          if (bingo) {
            reset(false); //리팩토링 함수 콜 = reset(); undefined 가 if문 안에 있으면 false와 같음
          } else if (candidates.length === 0) { //빈칸이 없을 때
            reset(true); //무승부일 경우
          } else { //빙고가 안되었으면    
            if (turn === 'X') {
              turn = 'O';
            }

            //1초 후 컴퓨터 턴 표시
            setTimeout(function() {
              console.log('컴퓨터의 턴입니다.');
              //빈칸 중 하나를 고름
              //filter()로 return값이 true인 것(빈칸)만 추출하여 새 배열을 반환
              //candidates중 랜덤으로 한개 추출
              let computerChoice = candidates[Math.floor(Math.random() * candidates.length)];
              computerChoice.textContent = turn;
              //컴퓨터가 승리했는지 체크
              //중요! 컴퓨터의 위치 재정의
              rowNo = row.indexOf(computerChoice.parentNode);
              //console.log('컴퓨터 줄번호', rowNo);
              colNo = col[rowNo].indexOf(computerChoice);
              //console.log('컴퓨터 칸번호', colNo);

              bingoCheck(); //리팩토링 함수 콜

              if (bingo) { //빙고일 경우 //bingo = true
                reset(); //리팩토링 함수 콜
              }
              turn = 'X'; //턴을 나한테 넘김
            }, 1000)
          }
        }
      }

      for (let i = 0; i < 3; i += 1) {
        let tr = document.createElement('tr');
        row.push(tr);
        col.push([]);
        for (let j = 0; j < 3; j += 1) {
          let td = document.createElement('td');
          td.addEventListener('click', clickFn);
          tr.appendChild(td);
          col[i].push(td);
        }
        table.appendChild(tr);
      }
      document.body.append(table);
      document.body.append(result);

    </script>
  </body>

</html>



 

화면 결과(Result 클릭)

반응형

댓글