MineSwipper



Code View

                    
    <div id="wrapper">
        <h1>MineSwipper</h1>
        <input id="hor" type="number" placeholder="가로" value="10">
        <input id="ver" type="number" placeholder="세로" value="10">
        <input id="mine" type="number" placeholder="지뢰" value="20">
        <button id="exec">Start</button>
        <table id="table">
            <--지뢰부분-->
            <thead></thead>
            <tbody></tbody>
        </table>
    </div>
                    
                
                    
        #wrapper {
            width: 100%;
            text-align: center;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
        }

        h1 {
            font: normal 1.75em "Larsseit";
            color: #252525;
            text-align: center;
            padding: 50px 0 30px;
        }

        #table {
            border-collapse: collapse;
            display: block;
            text-align: center;
            margin: 30px 0;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
        }

        td {
            width: 20px;
            height: 20px;
            line-height: 20px;
            border: solid 1px #252525;
            text-align: center;
            background: #c9c9c9;
            font: normal "Larsseit";
        }

        td.opened {
            background: #fff;
        }

        td.flag {
            background: #252525;
            color: #fff;
        }

        td.question {
            background: #999;
        }

        td.bomb {
            color: transparent;
        }

        input {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            width: 80px;
            background-color: #252525;
            border: none;
            color: #fff;
            padding: 5px 0 5px 8px;
            box-sizing: border-box;
            margin-right: 5px;
        }

        /*input 초기화*/
        input[type="number"]::-webkit-outer-spin-button,
        input[type="number"]::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }

        #exec {
            width: 80px;
            background-color: #252525;
            border: none;
            color: #fff;
            padding: 5px;
            box-sizing: border-box;
        }

        .result {
            margin-top: 20px;
            font: normal 1.25em "Larsseit";
        }
                    
                
                    
        let table = document.querySelector('#table');
        let tbody = document.querySelector('#table tbody');
        let result = document.createElement('div');
        result.classList.add('result');
        table.appendChild(result);
        let dataset = [];
        let stop = false;
        let openedBlock = 0;
        let codeTable = {
            openBk: -1,
            question: -2,
            flag: -3,
            flagBomb: -4,
            quesBomb: -5,
            bomb: 1,
            default: 0,
        }

        document.querySelector('#exec').addEventListener('click', function() {
            // 초기화
            tbody.innerHTML = '';
            result.textContent = '';
            dataset = [];
            stop = false;
            openedBlock = 0;

            let hor = parseInt(document.querySelector('#hor').value);
            let ver = parseInt(document.querySelector('#ver').value);
            let mine = parseInt(document.querySelector('#mine').value);

            // bomb 테이블 만들기 
            for (let i = 0; i < ver; i += 1) {
                let arr = [];
                let tr = document.createElement('tr'); //line 
                dataset.push(arr);
                for (let j = 0; j < hor; j += 1) {
                    arr.push(codeTable.default);
                    let td = document.createElement('td'); //block
                    td.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        if (stop) {
                            return;
                        }
                        let parentTr = e.currentTarget.parentNode;
                        let parentBody = e.currentTarget.parentNode.parentNode;
                        let block = Array.prototype.indexOf.call(parentTr.children, e.currentTarget);
                        let line = Array.prototype.indexOf.call(parentBody.children, parentTr);
                        if (e.currentTarget.textContent === '' || e.currentTarget.textContent === '×') {
                            e.currentTarget.textContent = '⚑';
                            e.currentTarget.classList.remove('bomb');
                            e.currentTarget.classList.add('flag');
                            if (dataset[line][block] === codeTable.bomb) {
                                dataset[line][block] = codeTable.flagBomb;
                            } else {
                                dataset[line][block] = codeTable.flag;
                            }
                        } else if (e.currentTarget.textContent === '⚑') {
                            e.currentTarget.textContent = '?';
                            e.currentTarget.classList.remove('flag');
                            e.currentTarget.classList.add('question');
                            if (dataset[line][block] === codeTable.flagBomb) {
                                dataset[line][block] = codeTable.questionBomb;
                            } else {
                                dataset[line][block] = codeTable.question;
                            }
                        } else if (e.currentTarget.textContent === '?') {
                            e.currentTarget.classList.remove('question');
                            if (dataset[line][block] === codeTable.bomb || dataset[line][block] === codeTable.flagBomb || dataset[line][block] === codeTable.questionBomb) {
                                e.currentTarget.textContent = '×';
                                e.currentTarget.classList.add('bomb');
                                dataset[line][block] = codeTable.bomb;
                            } else {
                                e.currentTarget.textContent = '';
                                dataset[line][block] = codeTable.default;
                            }
                        }
                    });
                    td.addEventListener('click', function(e) {
                        if (stop) {
                            return;
                        }
                        let parentTr = e.currentTarget.parentNode;
                        let parentBody = e.currentTarget.parentNode.parentNode;
                        let block = Array.prototype.indexOf.call(parentTr.children, e.currentTarget);
                        let line = Array.prototype.indexOf.call(parentBody.children, parentTr);
                        if ([codeTable.openBk, codeTable.flag, codeTable.flagBomb, codeTable.questionBomb, codeTable.question].includes(dataset[line][block])) {
                            return;
                        }
                        // 클릭했을때
                        e.currentTarget.classList.add('opened');
                        openedBlock += 1;

                        if (dataset[line][block] === codeTable.bomb) { //bomb클릭
                            e.currentTarget.textContent = '💣';
                            result.textContent = 'Failed';
                            stop = true;
                        } else { // bomb가 아닌 경우 주변 bomb 개수
                            let nearBy = [
                                dataset[line][block - 1], dataset[line][block + 1],
                            ];
                            if (dataset[line - 1]) {
                                nearBy = nearBy.concat(dataset[line - 1][block - 1], dataset[line - 1][block], dataset[line - 1][block + 1]);
                            }
                            if (dataset[line + 1]) {
                                nearBy = nearBy.concat(dataset[line + 1][block - 1], dataset[line + 1][block], dataset[line + 1][block + 1]);
                            }

                            let numOfNearby = nearBy.filter(function(v) {
                                return [codeTable.bomb, codeTable.flagBomb, codeTable.quesBomb].includes(v);
                            }).length;
                            //거짓인값 : false, '', 0 , null, undefined, NaN
                            e.currentTarget.textContent = numOfNearby || '';
                            dataset[line][block] = codeTable.openBk;

                            if (numOfNearby === 0) {
                                //주변 8칸 동시 오픈 (재귀함수)
                                let nearbyBlock = [];
                                if (tbody.children[line - 1]) {
                                    nearbyBlock = nearbyBlock.concat([
                                        tbody.children[line - 1].children[block - 1],
                                        tbody.children[line - 1].children[block],
                                        tbody.children[line - 1].children[block + 1],
                                    ]);
                                }
                                nearbyBlock = nearbyBlock.concat([
                                    tbody.children[line].children[block - 1],
                                    tbody.children[line].children[block + 1],
                                ]);
                                if (tbody.children[line + 1]) {
                                    nearbyBlock = nearbyBlock.concat([
                                        tbody.children[line + 1].children[block - 1],
                                        tbody.children[line + 1].children[block],
                                        tbody.children[line + 1].children[block + 1],
                                    ]);
                                }
                                nearbyBlock.filter(function(v) {
                                    return !!v;
                                }).forEach(function(nextBlock) {
                                    let parentTr = nextBlock.parentNode;
                                    let parentBody = nextBlock.parentNode.parentNode;
                                    let nextBB = Array.prototype.indexOf.call(parentTr.children, nextBlock);
                                    let nextBL = Array.prototype.indexOf.call(parentBody.children, parentTr);
                                    if (dataset[nextBL][nextBB] !== codeTable.openBk) {
                                        nextBlock.click();
                                    }
                                });
                            }
                            if (openedBlock === hor * ver - mine) {
                                result.textContent = 'Success!';
                                stop = true;
                            }
                        }
                    });
                    tr.appendChild(td); //line > block
                }
                tbody.appendChild(tr);
            }

            // bomb 제작
            let numbers = Array(hor * ver).fill().map(function(elem, index) {
                return index; //1~100
            });
            let shuffle = [];
            while (numbers.length > hor * ver - mine) {
                let shiftValue = numbers.splice(Math.floor(Math.random() * numbers.length), 1)[0];
                shuffle.push(shiftValue);
            }

            // bomb심기
            for (let k = 0; k < shuffle.length; k++) {
                let col = Math.floor(shuffle[k] / ver);
                let row = shuffle[k] % ver;
                //        tbody.children[col].children[row].textContent = '×';
                dataset[col][row] = codeTable.bomb;
            }
        });