on
[VanillaJS] 바닐라js로 틱택토를 만들어보자 (2)
[VanillaJS] 바닐라js로 틱택토를 만들어보자 (2)
반응형
es2021 강좌의 틱택토 구현 요구사항대로 만들어보고 있는데,
이번 포스팅에서 얘기할 내용은 강의와 다르게 알고리즘 및 코드를 짜다보니 강의코드와 완전 다른 코드가 되어버렸다...
그래도 시간복잡도 및 코드길이가 충분히 좋기 때문에 걱정할 필요는 없어보인다.
(다만, 알고리즘은 강의코드보다 아주약간 더 어려울수도?)
지난 포스팅은 아래와 같다.
https://kth990303.tistory.com/188
컴퓨터의 턴을 추가해주자.
이번 포스팅은 사실 그렇게 길지 않다.
컴퓨터의 턴만 추가하면 끝나기 때문이다.
컴퓨터의 턴은 X, 나의 턴은 O로 진행할 것이다.
그러기 위해선, 컴퓨터의 턴이 될 때, 나의 click 이벤트를 기다리지 않고 자기가 스스로 X를 칠해주게 해야 한다.
그렇기 때문에 칸 선택함수 코드의 마지막 부분에서 turn==='O' ? turn='X' : turn='O'; 부분을 아래 코드로 변경하였다.
// 턴 체인지 turn='X'; setTimeout(()=>{ computerChoice(); }, 500);
computerChoice() 함수에서 컴퓨터가 어떻게 X를 칠해주는지 볼 것이다.
아, 참고로 setTimeOut 동안 내가 칸을 선택할 수 없게 함수 맨 위에 아래 코드도 추가하였다.
// 이미 게임이 끝났거나 컴퓨터의 턴이라면 if(finished || turn === 'X') return;
기존의 finished 에다가 || 연산자와 turn ==='X' 로 조건을 추가한 것이다.
computerChoice() 함수는 아래와 같다.
// 컴퓨터의 턴 const computerChoice=()=>{ const emptyCells=rows.flat().filter(v=>!v.textContent); const randomIdx=Math.floor(Math.random()*(emptyCells.length)); const randomCell=emptyCells[randomIdx]; randomCell.textContent=turn; if(checkWinner(randomCell.parentNode.rowIndex, randomCell.cellIndex)){ $result.textContent=`${turn}님의 승리!`; finished=true; return; } turn='O'; }
filter 함수를 이용해 빈칸 중 랜덤하게 X로 칠해주는 코드이다.
X로 칠해주고 컴퓨터가 승리했는지 안했는지를 판단하기 위해 randomCell의 rowIndex, cellIndex를 파라미터로 checkWinner 함수에 넘겨준다. checkWinner가 true라면 컴퓨터의 승리이므로 리턴해준다.
사실 처음에는 randomCell.textContent=turn; 코드를 checkWinner 함수 아래에 넣었었다.
근데 결과가 원하는대로 나오지 않아 디버깅을 해보았다.
디버깅해보니 이미 X가 선택한 칸에 X로 칠해주지 않아 의도하지 않은 결과가 나온 것이었다.
debugger를 하는 모습
js는 c++, java와 다르게 debugger; 라고 써주면 디버깅이 되는 신기한 모습을 보여준다!
아무튼 여기까지 하면 컴퓨터의 턴에 자기가 스스로 X를 칠해주는 똑똑한 틱택토가 완성된다.
전체코드
틱택토 table{ border-collapse: collapse; } td{ border: 1px solid black; width: 40px; height: 40px; text-align: center; } const { body }=document; const $table=document.createElement('table'); const $result=document.createElement('div'); const rows=[]; let turn='O', count=0, finished=false; // 승부결정 파악 함수 const checkWinner=(rowIndex,colIndex)=>{ let garo=true, sero=true, diagonal=true, revDiagonal=true; for(let i=0;i<3;i++){ if(rows[i][colIndex].textContent!==turn) sero=false; if(rows[rowIndex][i].textContent!==turn) garo=false; if(rows[i][i].textContent!==turn) diagonal=false; if(rows[i][2-i].textContent!==turn) revDiagonal=false; } return garo||sero||diagonal||revDiagonal; } // 컴퓨터의 턴 const computerChoice=()=>{ const emptyCells=rows.flat().filter(v=>!v.textContent); const randomIdx=Math.floor(Math.random()*(emptyCells.length)); const randomCell=emptyCells[randomIdx]; randomCell.textContent=turn; if(checkWinner(randomCell.parentNode.rowIndex, randomCell.cellIndex)){ $result.textContent=`${turn}님의 승리!`; finished=true; return; } turn='O'; } // 칸 선택함수 const selectCol=(i, j)=>(e)=>{ // 이미 게임이 끝났거나 컴퓨터의 턴이라면 if(finished || turn === 'X') return; // 이미 선택했던 칸이라면 if(e.target.textContent) return; e.target.textContent=turn; count++; console.log(e.target.textContent); // 승부가 났는가? if(checkWinner(i, j)){ $result.textContent=`${turn}님의 승리!`; finished=true; return; } // 9칸(모든 칸)을 선택했는가? else if(count==9){ $result.textContent=`무승부!`; finished=true; return; } // 턴 체인지 turn='X'; setTimeout(()=>{ computerChoice(); }, 500); } for(let i=0;i<3;i++){ const $tr=document.createElement('tr'); const cells=[]; for(let j=0;j<3;j++){ const $td=document.createElement('td'); cells.push($td); // 클릭 이벤트 $td.addEventListener('click', selectCol(i, j)); $tr.append($td); } rows.push(cells); $table.append($tr); } body.append($table); body.append($result);
강의와 다르게 코드를 짜봤는데 꿀잼이다.
시간복잡도도 괜찮고 코드길이는 더 짧고, 내가 스스로 만든 코드라 더욱 애착이 가는 이번 틱택토.
(그렇지만 html, css는 조현영님이 만들어놓은 코드 그대로...)
이상하게 css는 정이 잘 안간단말이지 ㅠ
아무튼 js도 나름 꿀잼언어같다.
css도 언제한번 날잡고 다시 쫙 훑어봐야겠다. 내가 디자인을 워낙 안따져서 그게 언제가 될지는 모르겠지만...
반응형
from http://kth990303.tistory.com/191 by ccl(A) rewrite - 2021-10-22 22:28:11