이차원 배열인 틱택토 게임을 만들고 같은 코드를 메서드로 줄여쓰는 법, 이벤트 버블링 등을 학습한다.
이차원 배열의 특성을 생각하여 순서도를 그린다.
컴퓨터와 번갈아가며 하는 게임의 특성을 생각한다.
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
width: 40px;
height: 40px;
text-align: center;
}
</style>
<body>
<!-- <table>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table> -->
<script>
const { body } = document;
const $table = document.createElement('table');
const $result = document.createElement('div');
const rows = [];
let turn = 'O';
const checkWinner = (target) => {
const rowIndex = target.parentNode.rowIndex;
const cellIndex = target.cellIndex;
//세칸 다 채워졌나?
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 checkWinnerAndDraw = (target) => {
const hasWinner = checkWinner(target);
if (hasWinner) {
$result.textContent = `${turn}님이 승리!`;
$table.removeEventListener('click', callback);
return;
}
//무승부 검사
const draw = rows.flat().every((cell) => cell.textContent);
if (draw) {
$result.textContent = `무승부`;
return;
}
if (turn === 'O') {
turn = 'X';
} else if (turn === 'X') {
turn = 'O';
};
};
let clickable = true;
const callback = (event) => {
if (!clickable) return;
//빈칸이 아니면
if (event.target.textContent !== '') {
console.log('빈칸이 아닙니다.');
return;
}
//빈칸이면
console.log('빈칸입니다.');
event.target.textContent = turn;
//승부 판단하기
checkWinnerAndDraw(event.target);
if (turn === 'X') {
clickable = false;
setTimeout(() => {
const emptyCells = rows.flat().filter((v) => !v.textContent);
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
randomCell.textContent = 'X';
checkWinnerAndDraw(event.target);
clickable = true;
}, 1000);
}
};
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);
$tr.append($td);
}
rows.push(cells);
$table.append($tr);
}
$table.addEventListener('click', callback);
body.append($table);
body.append($result);
</script>
</body>
이벤트가 부모태그를 따라서 올라가는 현상
event.currentTarget 을 써주면 이벤트를 연결해준 요소를 선택할 수 있다.
event.stopPropagation() 이벤트 버블링을 막아주는 메서드
every는 모두 조건이 성립해야 한다. 1차원 배열만 가능해서 2차원 배열은 rows.flat메서드로 펼쳐준 후에 사용한다.
some 은 every의 반대로 하나라도 조건이 성립하면 성립한다.