diff --git a/Projects/Minesweeper-game/img/flag.png b/Projects/Minesweeper-game/img/flag.png new file mode 100644 index 000000000..3dbe16c0b Binary files /dev/null and b/Projects/Minesweeper-game/img/flag.png differ diff --git a/Projects/Minesweeper-game/img/mine.png b/Projects/Minesweeper-game/img/mine.png new file mode 100644 index 000000000..d6397be89 Binary files /dev/null and b/Projects/Minesweeper-game/img/mine.png differ diff --git a/Projects/Minesweeper-game/index.html b/Projects/Minesweeper-game/index.html new file mode 100644 index 000000000..b4e40ecbe --- /dev/null +++ b/Projects/Minesweeper-game/index.html @@ -0,0 +1,15 @@ + + + + + + Minesweeper + + + +

Minesweeper

+
Time: 0
+
+ + + diff --git a/Projects/Minesweeper-game/script.js b/Projects/Minesweeper-game/script.js new file mode 100644 index 000000000..15e6c7d35 --- /dev/null +++ b/Projects/Minesweeper-game/script.js @@ -0,0 +1,174 @@ +const rows = 10; +const cols = 10; +const minesCount = 20; +let grid = []; +let minePositions = []; +let timer = 0; +let timerInterval; + +function startTimer() { + timer = 0; + clearInterval(timerInterval); + updateTimerDisplay(0, 0); + timerInterval = setInterval(() => { + timer++; + const minutes = Math.floor(timer / 60); + const seconds = timer % 60; + updateTimerDisplay(minutes, seconds); + }, 1000); +} + +function updateTimerDisplay(minutes, seconds) { + const formattedMinutes = minutes.toString().padStart(2, '0'); + const formattedSeconds = seconds.toString().padStart(2, '0'); + document.getElementById('timer').textContent = `Time: ${formattedMinutes}:${formattedSeconds}`; +} + + +function initGame() { + const container = document.getElementById('game-container'); + container.style.gridTemplateRows = `repeat(${rows}, auto)`; + container.style.gridTemplateColumns = `repeat(${cols}, auto)`; + + startTimer(); + + grid = Array(rows).fill().map(() => Array(cols).fill({})); + container.innerHTML = ''; + + minePositions = []; + while (minePositions.length < minesCount) { + const r = Math.floor(Math.random() * rows); + const c = Math.floor(Math.random() * cols); + if (!minePositions.some(([x, y]) => x === r && y === c)) { + minePositions.push([r, c]); + grid[r][c] = { mine: true, revealed: false, flag: false }; + } + } + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!grid[r][c].mine) { + const adjacentMines = countAdjacentMines(r, c); + grid[r][c] = { mine: false, revealed: false, flag: false, adjacentMines }; + } + } + } + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + const cell = document.createElement('div'); + cell.classList.add('cell'); + cell.dataset.row = r; + cell.dataset.col = c; + cell.addEventListener('click', () => revealCell(r, c)); + cell.addEventListener('contextmenu', (e) => { + e.preventDefault(); + toggleFlag(r, c); + }); + container.appendChild(cell); + } + } + +} + +function countAdjacentMines(r, c) { + const directions = [ + [-1, -1], [-1, 0], [-1, 1], + [0, -1], [0, 1], + [1, -1], [1, 0], [1, 1], + ]; + return directions.reduce((count, [dr, dc]) => { + const nr = r + dr; + const nc = c + dc; + if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc]?.mine) { + count++; + } + return count; + }, 0); +} + +function revealCell(r, c) { + if (grid[r][c].revealed || grid[r][c].flag) return; + + const cell = document.querySelector(`[data-row='${r}'][data-col='${c}']`); + grid[r][c].revealed = true; + + if (grid[r][c].mine) { + cell.classList.add('mine'); + cell.innerHTML = `Mine`; + alert('Game Over! You hit a mine. 💣'); + clearInterval(timerInterval); + return initGame(); + } + + cell.classList.add('revealed'); + if (grid[r][c].adjacentMines > 0) { + cell.textContent = grid[r][c].adjacentMines; + } else { + const directions = [ + [-1, -1], [-1, 0], [-1, 1], + [0, -1], [0, 1], + [1, -1], [1, 0], [1, 1], + ]; + directions.forEach(([dr, dc]) => { + const nr = r + dr; + const nc = c + dc; + if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) { + revealCell(nr, nc); + } + }); + } +} + +function toggleFlag(r, c) { + if (grid[r][c].revealed) return; + + const cell = document.querySelector(`[data-row='${r}'][data-col='${c}']`); + grid[r][c].flag = !grid[r][c].flag; + cell.classList.toggle('flag'); + cell.innerHTML = grid[r][c].flag + ? `Flag` + : ''; +} + +function finishGame(win) { + clearInterval(timerInterval); + isGameOver = true; + const message = win + ? `Congratulations! You won the game in ${formatTime(timer)}! 🎉` + : "Game Over! You hit a mine. 💣"; + + showEndMessage(message); + } + + function formatTime(totalSeconds) { + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + const formattedMinutes = minutes.toString().padStart(2, '0'); + const formattedSeconds = seconds.toString().padStart(2, '0'); + return `${formattedMinutes}:${formattedSeconds}`; + } + + function showEndMessage(message) { + const messageContainer = document.createElement("div"); + messageContainer.id = "end-message"; + messageContainer.textContent = message; + document.body.appendChild(messageContainer); + + // Add styles for the message + messageContainer.style.position = "fixed"; + messageContainer.style.top = "50%"; + messageContainer.style.left = "50%"; + messageContainer.style.transform = "translate(-50%, -50%)"; + messageContainer.style.backgroundColor = "rgba(0, 0, 0, 0.8)"; + messageContainer.style.color = "#fff"; + messageContainer.style.padding = "20px"; + messageContainer.style.borderRadius = "10px"; + messageContainer.style.textAlign = "center"; + messageContainer.style.fontSize = "18px"; + messageContainer.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)"; + messageContainer.style.zIndex = "1000"; + } + +// Start the game +initGame(); diff --git a/Projects/Minesweeper-game/styles.css b/Projects/Minesweeper-game/styles.css new file mode 100644 index 000000000..b404dcf58 --- /dev/null +++ b/Projects/Minesweeper-game/styles.css @@ -0,0 +1,88 @@ +body { + font-family: Arial, sans-serif; + text-align: center; + margin: 0; + padding: 0; + background-color: #f8f9fa; + } + + h1 { + margin: 20px 0 10px; + } + + #timer { + font-size: 18px; + margin-bottom: 10px; + } + + #game-container { + display: grid; + justify-content: center; + align-content: center; + gap: 0; + margin: 20px auto; + background-color: #333; + padding: 0; + } + + + .cell { + width: 30px; /* Adjust size to your preference */ + height: 30px; + background-color: #ddd; + border: 1px solid #aaa; + display: flex; + justify-content: center; + align-items: center; + font-size: 16px; + cursor: pointer; + transition: all 0.2s ease-in-out; + user-select: none; + } + + .cell:hover { + transform: scale(1.1); + background-color: #c0c0c0; + } + + .cell.revealed { + background-color: #f5f5f5; + border: 1px solid #ccc; + cursor: default; + } + + .cell.mine img, + .cell.flag img { + width: 20px; + height: 20px; + } + + .cell.mine img, + .cell.flag img { + width: 20px; + height: 20px; + } + + .cell.mine { + background-color: #ff4d4d; + animation: shake 0.5s; + } + + .cell.flag { + background-color: #f9e79f; + } + + @keyframes shake { + 0% { transform: translate(1px, 1px) rotate(0deg); } + 10% { transform: translate(-1px, -2px) rotate(-1deg); } + 20% { transform: translate(-3px, 0px) rotate(1deg); } + 30% { transform: translate(3px, 2px) rotate(0deg); } + 40% { transform: translate(1px, -1px) rotate(1deg); } + 50% { transform: translate(-1px, 2px) rotate(-1deg); } + 60% { transform: translate(-3px, 1px) rotate(0deg); } + 70% { transform: translate(3px, 1px) rotate(-1deg); } + 80% { transform: translate(-1px, -1px) rotate(1deg); } + 90% { transform: translate(1px, 2px) rotate(0deg); } + 100% { transform: translate(1px, -2px) rotate(-1deg); } + } + \ No newline at end of file