자바스크립트 틱택토

banhogu·2023년 5월 22일
0
<!DOCTYPE html>
<html>

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

        td {
            border: 1px solid black;
            width: 40px;
            height: 40px;
            text-align: center;
        }
    </style>
</head>

<body>

    <script>
        const { body } = document
        let $table = document.createElement('table')
        let $result = document.createElement('div')
        let turn = 'O'
        let rows = []
        let clickable = true
        let checkwinner = (event) => {
            // let rowindex = event.parentNode.rowindex 유사배열 형태로 나옴. not 배열. 배열로 만들고 싶으면 Array.from(유사배열)
            // let cellundex = target.cellindex
            let rowindex
            let cellindex
            let winner = false
            rows.forEach((rowel, ri) => {
                rowel.forEach((cellel, ci) => {
                    if (cellel === event) {
                        rowindex = ri  // 세로
                        cellindex = ci
                    }
                })
            })
            if (
                rows[rowindex][0].textContent === turn &&
                rows[rowindex][1].textContent === turn &&
                rows[rowindex][2].textContent
            ) { winner = true }
            else if (
                rows[0][cellindex].textContent === turn &&
                rows[1][cellindex].textContent === turn &&
                rows[2][cellindex].textContent
            ) { winner = true }
            else if (
                rows[0][0].textContent === turn &&
                rows[1][1].textContent === turn &&
                rows[2][2].textContent
            ) { winner = true }
            else if (
                rows[0][2].textContent === turn &&
                rows[1][1].textContent === turn &&
                rows[2][0].textContent
            ) { winner = true }
            if (turn === 'O') {

                turn = 'X'

            }
            return winner
        }

        let checkdraw = (event) => {
            // rows = 2차원 배열인데 rows.flat() 하면 1차원 배열로 펴진다. 
            // every로 응용하면 rows.flat().every((td)=>td.textContent) - td의 텍스트 컨텐트가 모두 차 있으면 true 즉 무승부
            // some은 every와 반대. 하나라도.

            let draw = true;
            rows.forEach((rowel, ridx) => {
                rowel.forEach((cellel, cidx) => {
                    if (!cellel.textContent) {
                        draw = false
                    }
                })
            })
            return draw
        }

        // let clear = (event) => {
        //     event.target.textContent = ''
        // }

        let changeturn = (event) => {
            if (clickable === false) {
                return
            }
            if (event.target.textContent !== '') { return }

            event.target.textContent = turn

            if (checkwinner(event.target)) {
                $table.removeEventListener('click', changeturn)
                return $result.textContent = `${turn} 님의 승리입니다`
            }
            if (checkdraw(event.target)) {
                return $result.textContent = `무승부입니다`
            }
            clickable = false
            if (turn === 'X') { //컴퓨터의 턴
                let empty = rows.flat().filter((a) => !a.textContent) //배열형태로 리턴
                let random = empty[Math.floor(Math.random() * empty.length)]
                clickable = false
                setTimeout(() => {
                    clickable = true
                    random.textContent = 'X'
                    if (checkwinner(random)) {
                        $table.removeEventListener('click', changeturn)
                        return $result.textContent = `${turn} 님의 승리입니다`
                    }
                    if (checkdraw(random)) {
                        return $result.textContent = `무승부입니다`
                    }
                    clickable = true

                }, 1000);

            }
        }

        for (let i = 0; i < 3; i++) {
            let $tr = document.createElement('tr')
            let cells = []
            for (let j = 0; j < 3; j++) {
                let $td = document.createElement('td')
                $tr.appendChild($td)
                cells.push($td)
            }
            $table.appendChild($tr)
            rows.push(cells)
        }
        body.appendChild($table)
        body.appendChild($result)
        $table.addEventListener('click', changeturn)

    </script>
</body>

</html>

이벤트 버블링으로 table에 이벤트 리스너를 걸어 td전체에 이벤트를 먹였다
구조분해할당을 이용해 코드를 쪼금이나마 축소시켯다.
코드를 짜며 항상 html 데이터와 (보여지는) js데이터를 일치 시켜야 된다고 느꼇다. 추가로 턴을 누구 먼저 할것인지 입력받아서 게임 시작 할 것인지, 승리 또는 무승부시 자동으로 테이블 데이터가 지워지며 새게임 시작하는 기능을 추가 하면 좋을것 같다.

profile
@banhogu

0개의 댓글