카테고리 없음
[JavaScript] 브라우저에서 동작하는 지뢰찾기 만들기 - 심화편
teamnova
2023. 10. 3. 12:00
728x90
저번 글에 이어서 기능을 추가해보았습니다.
https://stickode.tistory.com/930
1. 난이도 설정 추가
2. 타이머 추가
3. 남은 지뢰의 수 표시
4. 게임 관련 ui 정렬
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>지뢰찾기</title>
<!-- 게임 보드 스타일 -->
<style>
.board button {
width: 30px;
height: 30px;
font-size: 16px;
}
.flagged {
background-color: yellow;
font-weight: bold;
color: red;
}
#timer {
font-size: 20px;
margin-bottom: 10px;
}
.game-container {
display: flex;
align-items: start;
}
.game-controls {
margin-left: 20px; /* 보드와 게임 관련 UI 간 간격 */
display: flex;
flex-direction: column;
justify-content: space-between;
width: 150px; /* 원하는 너비로 조정 가능 */
}
</style>
</head>
<body><!-- 게임 보드와 관련 UI 묶기 -->
<div class="game-container">
<div class="board"></div>
<div class="game-controls">
<div>
남은 지뢰: <span id="remainingMines"></span>
</div>
<div>
<select id="difficulty">
<option value="beginner">초보</option>
<option value="intermediate">중급</option>
<option value="expert">고급</option>
</select>
</div>
<div>
<button id="startGame">게임 시작</button>
<button id="pauseGame">일시정지</button><br>
<span id="timer">0</span>초
</div>
</div>
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const board = document.querySelector('.board');// 게임 보드 선택
const timerElement = document.getElementById('timer');
let timerInterval;
let startTime;
let isPaused = false;
let pausedTime = 0;
const difficulties = {
beginner: {rows: 10, cols: 10, mines: 10},
intermediate: {rows: 16, cols: 16, mines: 40},
expert: {rows: 24, cols: 24, mines: 99}
};
let ROWS = difficulties.beginner.rows;
let COLS = difficulties.beginner.cols;
let MINES = difficulties.beginner.mines;
let minePositions = [];
// 게임 시작 버튼 이벤트 리스너 추가
const startButton = document.getElementById('startGame');
startButton.addEventListener('click', startGame);
// 게임 일시정지 버튼 이벤트 리스너 추가
const pauseButton = document.getElementById('pauseGame');
pauseButton.addEventListener('click', pauseGame);
let flaggedCount = 0; // 현재까지 깃발 표시한 칸의 수
const remainingMinesElement = document.getElementById('remainingMines');
function updateRemainingMines() {
remainingMinesElement.textContent = MINES - flaggedCount;
}
initializeGame();
function startGame() {
if (timerInterval) clearInterval(timerInterval); // 기존 타이머 초기화
if (isPaused) {
startTime = new Date().getTime() - pausedTime;
isPaused = false;
} else {
initializeGame();
startTime = new Date().getTime();
}
timerElement.textContent = '0';
startTimer();
}
function startTimer() {
timerInterval = setInterval(() => {
const currentTime = new Date().getTime();
const difference = isPaused ? pausedTime : Math.floor((currentTime - startTime) / 1000);
timerElement.textContent = difference.toString();
}, 1000);
}
function pauseGame() {
if (!timerInterval) return;
clearInterval(timerInterval);
pausedTime = new Date().getTime() - startTime;
isPaused = true;
}
function initializeGame() {
const selectedDifficulty = document.getElementById('difficulty').value;
ROWS = difficulties[selectedDifficulty].rows;
COLS = difficulties[selectedDifficulty].cols;
MINES = difficulties[selectedDifficulty].mines;
initializeBoard();
placeMines();
flaggedCount = 0; // 게임 초기화시 깃발 카운트도 초기화
updateRemainingMines(); // 남은 지뢰 수 초기화
}
function initializeBoard() {
board.innerHTML = '';
for (let i = 0; i < ROWS; i++) {
let row = document.createElement('div');
for (let j = 0; j < COLS; j++) {
let cell = document.createElement('button');
cell.setAttribute('data-row', i);
cell.setAttribute('data-col', j);
cell.addEventListener('click', onCellClick);
cell.addEventListener('contextmenu', onCellRightClick);
row.appendChild(cell);
}
board.appendChild(row);
}
}
function placeMines() {
minePositions = [];
while (minePositions.length < MINES) {
let position = {
row: Math.floor(Math.random() * ROWS),
col: Math.floor(Math.random() * COLS)
};
if (!minePositions.some(pos => pos.row === position.row && pos.col === position.col)) {
minePositions.push(position);
}
}
}
function onCellClick(event) {
const row = parseInt(event.target.getAttribute('data-row'));
const col = parseInt(event.target.getAttribute('data-col'));
const cell = event.target;
if (cell.classList.contains('flagged')) return;
if (isMine(row, col)) {
revealAllCells();
clearInterval(timerInterval);
setTimeout(() => {
alert('게임이 끝났습니다.');
initializeGame();
}, 50);
} else {
revealCell(row, col);
}
}
function onCellRightClick(event) {
event.preventDefault();
const cell = event.target;
if (cell.disabled) return;
if (cell.classList.contains('flagged')) {
cell.classList.remove('flagged');
cell.textContent = '';
flaggedCount--;
} else {
cell.classList.add('flagged');
cell.textContent = '🚩';
flaggedCount++;
}
updateRemainingMines(); // 깃발 표시나 제거 후, 남은 지뢰 수 업데이트
}
function isMine(row, col) {
return minePositions.some(pos => pos.row === row && pos.col === col);
}
function revealCell(row, col) {
let minesAround = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
if (i !== 0 || j !== 0) {
if (isMine(row + i, col + j)) {
minesAround++;
}
}
}
}
const cell = board.children[row].children[col];
cell.textContent = minesAround > 0 ? minesAround : '';
cell.disabled = true;
}
function revealAllCells() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
const cell = board.children[i].children[j];
if (isMine(i, j)) {
cell.textContent = '💣';
cell.style.backgroundColor = 'red';
} else {
const minesAround = countMinesAround(i, j);
cell.textContent = minesAround > 0 ? minesAround : '';
}
cell.disabled = true;
}
}
}
function countMinesAround(row, col) {
let minesAround = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
if (i !== 0 || j !== 0) {
if (isMine(row + i, col + j)) {
minesAround++;
}
}
}
}
return minesAround;
}
});
</script>