Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Projects/Minesweeper-game/img/flag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Projects/Minesweeper-game/img/mine.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions Projects/Minesweeper-game/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minesweeper</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Minesweeper</h1>
<div id="timer">Time: 0</div>
<div id="game-container"></div>
<script src="script.js"></script>
</body>
</html>
174 changes: 174 additions & 0 deletions Projects/Minesweeper-game/script.js
Original file line number Diff line number Diff line change
@@ -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 = `<img src="img/mine.png" alt="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
? `<img src="img/flag.png" alt="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();
88 changes: 88 additions & 0 deletions Projects/Minesweeper-game/styles.css
Original file line number Diff line number Diff line change
@@ -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); }
}