KTX시간표

<style> .minesweeper-game { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #93c5fd 100%); padding: 20px; margin: 0 -10px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); max-width: 768px; margin-left: auto; margin-right: auto; } .minesweeper-title { text-align: center; font-size: 2.5rem; color: #1e40af; margin-bottom: 10px; font-weight: bold; text-shadow: 2px 2px 4px rgba(0,0,0,0.1); } .minesweeper-title-line { width: 100px; height: 3px; background: linear-gradient(to right, #60a5fa, #2563eb); margin: 0 auto 20px; border-radius: 2px; } .minesweeper-controls { background: rgba(255, 255, 255, 0.8); border-radius: 15px; padding: 20px; margin-bottom: 20px; display: flex; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap; box-shadow: 0 5px 15px rgba(0,0,0,0.1); } .minesweeper-difficulty { display: flex; flex-direction: column; align-items: center; } .minesweeper-difficulty-label { color: #1d4ed8; font-weight: 600; margin-bottom: 8px; } .minesweeper-select { padding: 8px 15px; border: 2px solid #93c5fd; border-radius: 8px; background: white; color: #1d4ed8; font-weight: 500; outline: none; cursor: pointer; } .minesweeper-select:focus { border-color: #3b82f6; } .minesweeper-info { display: flex; gap: 15px; align-items: center; } .minesweeper-info-item { background: #dbeafe; padding: 12px 16px; border-radius: 10px; text-align: center; border: 1px solid #bfdbfe; display: flex; flex-direction: column; align-items: center; } .minesweeper-info-icon { font-size: 1.5rem; margin-bottom: 5px; } .minesweeper-info-value { color: #1e40af; font-weight: bold; font-size: 1.2rem; } .minesweeper-info-label { color: #2563eb; font-size: 0.8rem; } .minesweeper-btn { padding: 12px 24px; background: linear-gradient(to right, #3b82f6, #2563eb); color: white; border: none; border-radius: 10px; cursor: pointer; font-weight: bold; font-size: 1rem; transition: all 0.2s; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .minesweeper-btn:hover { background: linear-gradient(to right, #2563eb, #1d4ed8); transform: translateY(-1px); box-shadow: 0 6px 8px rgba(0,0,0,0.15); } .minesweeper-status { text-align: center; margin: 20px 0; } .minesweeper-status-box { display: inline-block; padding: 15px 30px; border-radius: 15px; font-weight: bold; box-shadow: 0 5px 15px rgba(0,0,0,0.1); } .minesweeper-status-title { font-size: 1.5rem; margin-bottom: 5px; } .minesweeper-status-subtitle { font-size: 1rem; } .status-ready { background: linear-gradient(to right, #3b82f6, #2563eb); color: white; } .status-won { background: linear-gradient(to right, #10b981, #059669); color: white; } .status-lost { background: linear-gradient(to right, #ef4444, #dc2626); color: white; } .minesweeper-board-container { display: flex; justify-content: center; margin: 20px 0; overflow-x: auto; } .minesweeper-board-wrapper { background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.15); } .minesweeper-board { background: #1e40af; padding: 8px; border-radius: 10px; display: grid; gap: 2px; } .minesweeper-cell { width: 28px; height: 28px; border: 1px solid #93c5fd; font-size: 0.8rem; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; user-select: none; transition: all 0.15s; border-radius: 3px; } .cell-hidden { background: linear-gradient(135deg, #bfdbfe, #93c5fd); } .cell-hidden:hover { background: linear-gradient(135deg, #93c5fd, #60a5fa); transform: scale(1.05); } .cell-flagged { background: linear-gradient(135deg, #60a5fa, #3b82f6); color: white; } .cell-revealed { background: linear-gradient(135deg, #f8fafc, #e2e8f0); } .cell-mine { background: linear-gradient(135deg, #ef4444, #dc2626); color: white; } .cell-number-1 { color: #1d4ed8; } .cell-number-2 { color: #059669; } .cell-number-3 { color: #dc2626; } .cell-number-4 { color: #7c3aed; } .cell-number-5 { color: #ea580c; } .cell-number-6 { color: #db2777; } .cell-number-7 { color: #374151; } .cell-number-8 { color: #6b7280; } @media (max-width: 768px) { .minesweeper-title { font-size: 2rem; } .minesweeper-controls { flex-direction: column; gap: 15px; } .minesweeper-info { justify-content: center; } .minesweeper-cell { width: 24px; height: 24px; font-size: 0.7rem; } } </style> <div class="minesweeper-game"> <h1 class="minesweeper-title">지뢰찾기</h1> <div class="minesweeper-title-line"></div> <div class="minesweeper-controls"> <div class="minesweeper-difficulty"> <label class="minesweeper-difficulty-label">난이도</label> <select id="minesweeper-difficulty" class="minesweeper-select"> <option value="beginner">초급 (9×9, 지뢰 10개)</option> <option value="intermediate">중급 (16×16, 지뢰 40개)</option> <option value="expert">고급 (16×30, 지뢰 99개)</option> </select> </div> <div class="minesweeper-info"> <div class="minesweeper-info-item"> <div class="minesweeper-info-icon">💣</div> <div class="minesweeper-info-value" id="minesweeper-mines-count">10</div> <div class="minesweeper-info-label">지뢰</div> </div> <div class="minesweeper-info-item"> <div class="minesweeper-info-icon">⏱️</div> <div class="minesweeper-info-value" id="minesweeper-timer">0</div> <div class="minesweeper-info-label">초</div> </div> </div> <button class="minesweeper-btn" onclick="minesweeperInitGame()">새 게임</button> </div> <div class="minesweeper-status"> <div id="minesweeper-status" class="minesweeper-status-box status-ready"> <div class="minesweeper-status-title">초급 준비완료!</div> <div class="minesweeper-status-subtitle">셀을 클릭해서 게임을 시작하세요</div> </div> </div> <div class="minesweeper-board-container"> <div class="minesweeper-board-wrapper"> <div id="minesweeper-board" class="minesweeper-board"></div> </div> </div> </div> <script> var minesweeperGame = { difficulty: 'beginner', board: [], gameStatus: 'ready', flagCount: 0, timer: 0, firstClick: true, timerInterval: null, difficulties: { beginner: { rows: 9, cols: 9, mines: 10, name: '초급' }, intermediate: { rows: 16, cols: 16, mines: 40, name: '중급' }, expert: { rows: 16, cols: 30, mines: 99, name: '고급' } }, createEmptyBoard: function() { var config = this.difficulties[this.difficulty]; var board = []; for (var i = 0; i < config.rows; i++) { var row = []; for (var j = 0; j < config.cols; j++) { row.push({ isMine: false, isRevealed: false, isFlagged: false, neighborCount: 0 }); } board.push(row); } return board; }, placeMines: function(board, safeRow, safeCol) { var config = this.difficulties[this.difficulty]; var minesPlaced = 0; while (minesPlaced < config.mines) { var row = Math.floor(Math.random() * config.rows); var col = Math.floor(Math.random() * config.cols); var isSafeZone = Math.abs(row - safeRow) <= 1 && Math.abs(col - safeCol) <= 1; if (!board[row][col].isMine && !isSafeZone) { board[row][col].isMine = true; minesPlaced++; } } for (var r = 0; r < config.rows; r++) { for (var c = 0; c < config.cols; c++) { if (!board[r][c].isMine) { var count = 0; for (var dr = -1; dr <= 1; dr++) { for (var dc = -1; dc <= 1; dc++) { var nr = r + dr; var nc = c + dc; if (nr >= 0 && nr < config.rows && nc >= 0 && nc < config.cols && board[nr][nc].isMine) { count++; } } } board[r][c].neighborCount = count; } } } }, revealArea: function(board, startRow, startCol) { var config = this.difficulties[this.difficulty]; var stack = [[startRow, startCol]]; var visited = {}; while (stack.length > 0) { var pos = stack.pop(); var row = pos[0]; var col = pos[1]; var key = row + '-' + col; if (row < 0 || row >= config.rows || col < 0 || col >= config.cols || visited[key]) continue; if (board[row][col].isRevealed || board[row][col].isFlagged) continue; visited[key] = true; board[row][col].isRevealed = true; if (board[row][col].neighborCount === 0) { for (var dr = -1; dr <= 1; dr++) { for (var dc = -1; dc <= 1; dc++) { stack.push([row + dr, col + dc]); } } } } }, checkWin: function() { var config = this.difficulties[this.difficulty]; var revealed = 0; for (var r = 0; r < config.rows; r++) { for (var c = 0; c < config.cols; c++) { if (this.board[r][c].isRevealed && !this.board[r][c].isMine) { revealed++; } } } return revealed === (config.rows * config.cols - config.mines); }, startTimer: function() { var self = this; if (this.timerInterval) clearInterval(this.timerInterval); this.timerInterval = setInterval(function() { self.timer++; document.getElementById('minesweeper-timer').textContent = self.timer; }, 1000); }, stopTimer: function() { if (this.timerInterval) { clearInterval(this.timerInterval); this.timerInterval = null; } }, handleCellClick: function(row, col) { if (this.gameStatus === 'won' || this.gameStatus === 'lost') return; if (this.board[row][col].isRevealed || this.board[row][col].isFlagged) return; if (this.firstClick) { this.placeMines(this.board, row, col); this.firstClick = false; this.gameStatus = 'playing'; this.startTimer(); } if (this.board[row][col].isMine) { var config = this.difficulties[this.difficulty]; for (var r = 0; r < config.rows; r++) { for (var c = 0; c < config.cols; c++) { if (this.board[r][c].isMine) { this.board[r][c].isRevealed = true; } } } this.gameStatus = 'lost'; this.stopTimer(); this.updateStatus(); this.renderBoard(); return; } if (this.board[row][col].neighborCount === 0) { this.revealArea(this.board, row, col); } else { this.board[row][col].isRevealed = true; } if (this.checkWin()) { this.gameStatus = 'won'; this.stopTimer(); this.updateStatus(); } this.renderBoard(); }, handleRightClick: function(e, row, col) { e.preventDefault(); if (this.gameStatus === 'won' || this.gameStatus === 'lost') return; if (this.board[row][col].isRevealed) return; if (this.board[row][col].isFlagged) { this.board[row][col].isFlagged = false; this.flagCount--; } else { this.board[row][col].isFlagged = true; this.flagCount++; } this.updateMinesCount(); this.renderBoard(); }, renderBoard: function() { var boardElement = document.getElementById('minesweeper-board'); var config = this.difficulties[this.difficulty]; boardElement.style.gridTemplateColumns = 'repeat(' + config.cols + ', 1fr)'; boardElement.innerHTML = ''; for (var r = 0; r < config.rows; r++) { for (var c = 0; c < config.cols; c++) { var cell = this.board[r][c]; var cellElement = document.createElement('button'); cellElement.className = 'minesweeper-cell'; if (cell.isFlagged) { cellElement.textContent = '🚩'; cellElement.className += ' cell-flagged'; } else if (cell.isRevealed) { if (cell.isMine) { cellElement.textContent = '💣'; cellElement.className += ' cell-mine'; } else { cellElement.className += ' cell-revealed'; if (cell.neighborCount > 0) { cellElement.textContent = cell.neighborCount; cellElement.className += ' cell-number-' + cell.neighborCount; } } } else { cellElement.className += ' cell-hidden'; } var self = this; cellElement.setAttribute('data-row', r); cellElement.setAttribute('data-col', c); cellElement.onclick = function() { var row = parseInt(this.getAttribute('data-row')); var col = parseInt(this.getAttribute('data-col')); self.handleCellClick(row, col); }; cellElement.oncontextmenu = function(e) { var row = parseInt(this.getAttribute('data-row')); var col = parseInt(this.getAttribute('data-col')); self.handleRightClick(e, row, col); }; boardElement.appendChild(cellElement); } } }, updateStatus: function() { var statusElement = document.getElementById('minesweeper-status'); var difficultyName = this.difficulties[this.difficulty].name; statusElement.className = 'minesweeper-status-box'; if (this.gameStatus === 'won') { statusElement.className += ' status-won'; statusElement.innerHTML = '<div class="minesweeper-status-title">🎉 축하합니다! 승리! 🎉</div><div class="minesweeper-status-subtitle">시간: ' + this.timer + '초</div>'; } else if (this.gameStatus === 'lost') { statusElement.className += ' status-lost'; statusElement.innerHTML = '<div class="minesweeper-status-title">💥 게임 오버! 💥</div><div class="minesweeper-status-subtitle">다시 시도해보세요!</div>'; } else if (this.gameStatus === 'ready') { statusElement.className += ' status-ready'; statusElement.innerHTML = '<div class="minesweeper-status-title">🚀 ' + difficultyName + ' 준비완료!</div><div class="minesweeper-status-subtitle">셀을 클릭해서 게임을 시작하세요</div>'; } }, updateMinesCount: function() { var remainingMines = this.difficulties[this.difficulty].mines - this.flagCount; document.getElementById('minesweeper-mines-count').textContent = remainingMines; } }; function minesweeperInitGame() { minesweeperGame.stopTimer(); minesweeperGame.board = minesweeperGame.createEmptyBoard(); minesweeperGame.gameStatus = 'ready'; minesweeperGame.flagCount = 0; minesweeperGame.timer = 0; minesweeperGame.firstClick = true; document.getElementById('minesweeper-timer').textContent = '0'; minesweeperGame.updateMinesCount(); minesweeperGame.updateStatus(); minesweeperGame.renderBoard(); } document.addEventListener('DOMContentLoaded', function() { minesweeperInitGame(); document.getElementById('minesweeper-difficulty').addEventListener('change', function(e) { minesweeperGame.difficulty = e.target.value; minesweeperInitGame(); }); }); </script>