Skip to content

Instantly share code, notes, and snippets.

@yujiorama
Last active April 5, 2025 02:11
Show Gist options
  • Save yujiorama/32a565edcf968e6e4155f205275d234f to your computer and use it in GitHub Desktop.
Save yujiorama/32a565edcf968e6e4155f205275d234f to your computer and use it in GitHub Desktop.
my ms
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minesweeper</title>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<style>
body {
background-color: #c0c0c0;
font-family: 'Press Start 2P', cursive;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}
.controls {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
.controls label {
color: #333;
font-size: 0.8rem;
}
.minesweeper {
background: #808080;
padding: 15px;
border: 5px solid #ffffff;
box-shadow: inset -3px -3px #404040, inset 3px 3px #dfdfdf;
text-align: center;
position: relative;
}
.board {
display: inline-block;
background: #c0c0c0;
padding: 5px;
border: 2px solid #808080;
box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
}
.row {
display: flex;
}
.cell {
width: 30px;
height: 30px;
background: #c0c0c0;
border: 2px solid #808080;
box-shadow: inset -2px -2px #404040, inset 2px 2px #dfdfdf;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
cursor: pointer;
user-select: none;
transition: background-color 0.2s, transform 0.1s;
}
.cell:hover {
background-color: #b0b0b0;
transform: scale(1.05);
}
.cell.revealed {
background: #dfdfdf;
box-shadow: inset 2px 2px #808080, inset -2px -2px #ffffff;
}
.cell.flagged {
background: #c0c0c0;
color: red;
font-size: 1.2rem;
}
.info {
margin-top: 15px;
font-size: 0.9rem;
color: #555;
display: flex;
flex-direction: column;
align-items: center;
}
.info p {
margin: 5px 0;
}
#reset-button, #undo-button {
padding: 10px 20px;
font-family: 'Press Start 2P', cursive;
font-size: 0.7rem;
background-color: #c0c0c0;
border: 2px solid #808080;
box-shadow: 2px 2px 4px rgba(0,0,0,0.3);
cursor: pointer;
transition: background-color 0.2s, transform 0.1s;
margin-top: 10px;
}
#reset-button:hover, #undo-button:hover {
background-color: #b0b0b0;
transform: scale(1.05);
}
#message-box {
position: absolute;
top: -35px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border: 2px solid #808080;
border-radius: 5px;
font-size: 0.9rem;
z-index: 10;
opacity: 0;
transition: opacity 0.3s ease-in-out, top 0.3s ease-in-out;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
text-align: center;
min-width: 200px;
}
#message-box.show {
opacity: 1;
top: 10px;
}
#win-message {
position: absolute;
top: 20px;
background-color: rgba(255, 255, 255, 0.8);
padding: 15px;
border: 2px solid #808080;
border-radius: 5px;
font-size: 1rem;
animation: fadeIn 1s ease-in-out, pulse 2s infinite alternate;
z-index: 10;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes pulse {
from { transform: scale(1); }
to { transform: scale(1.1); }
}
</style>
</head>
<body>
<div class="minesweeper">
<div id="message-box"></div>
<h1 class="title">Minesweeper</h1>
<div id="board" class="board"></div>
<div class="controls">
<button id="reset-button" onclick="startGame()">Reset</button>
<button id="undo-button" onclick="undoMove()" disabled>Undo</button>
</div>
</div>
<div class="controls">
<label>Rows: <input type="number" id="rows" value="10" min="5" max="20"></label>
<label>Cols: <input type="number" id="cols" value="10" min="5" max="20"></label>
<label>Mines: <input type="number" id="mineRatio" value="15" min="5" max="50">%</label>
</div>
<div class="info">
<p>Left Click: Reveal Cell</p>
<p>Right Click: Toggle Flag</p>
</div>
<div id="win-message" style="display:none;">You Win!</div>
<script>
let rows, cols, mineRatio, board, firstClick;
let gameOver = false;
let messageBox;
let history = []; // 手順を保存する
function startGame() {
rows = parseInt(document.getElementById("rows").value);
cols = parseInt(document.getElementById("cols").value);
mineRatio = parseInt(document.getElementById("mineRatio").value) / 100;
firstClick = false;
gameOver = false;
document.getElementById("win-message").style.display = "none";
board = generateBoard(rows, cols, mineRatio);
renderBoard();
messageBox = document.getElementById("message-box");
messageBox.classList.remove("show");
history = []; // Reset history
document.getElementById("undo-button").disabled = true; // Disable undo button
}
function generateBoard(rows, cols, mineRatio) {
let board = Array.from({ length: rows }, () => Array(cols).fill(null).map(() => ({ mine: false, number: 0, revealed: false, flagged: false })));
let mines = Math.floor(rows * cols * mineRatio);
let minesPlaced = 0;
while (minesPlaced < mines) {
let r = Math.floor(Math.random() * rows);
let c = Math.floor(Math.random() * cols);
if (!board[r][c].mine) {
board[r][c].mine = true;
minesPlaced++;
}
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (board[r][c].mine) continue;
let count = 0;
for (let dr of [-1, 0, 1]) {
for (let dc of [-1, 0, 1]) {
let nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc].mine) count++;
}
}
board[r][c].number = count;
}
}
return board;
}
function revealCell(r, c) {
if (gameOver || board[r][c].revealed || board[r][c].flagged) return;
// Save current state for undo
history.push(board.map(row => row.map(cell => ({ ...cell }))));
document.getElementById("undo-button").disabled = false; // Enable undo button
if (!firstClick) {
firstClick = true;
if (board[r][c].mine) {
// Move mine on first click
let moved = false;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (!board[i][j].mine) {
board[i][j].mine = true;
board[r][c].mine = false;
moved = true;
break;
}
}
if (moved) break;
}
// Recalculate numbers
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (board[i][j].mine) continue;
let count = 0;
for (let dr of [-1, 0, 1]) {
for (let dc of [-1, 0, 1]) {
let nr = i + dr, nc = j + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc].mine) count++;
}
}
board[i][j].number = count;
}
}
}
}
if (board[r][c].mine) {
gameOver = true;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (board[i][j].mine) {
board[i][j].revealed = true;
}
}
}
renderBoard();
showMessage("Game Over!");
return;
}
board[r][c].revealed = true;
if (board[r][c].number === 0) {
for (let dr of [-1, 0, 1]) {
for (let dc of [-1, 0, 1]) {
let nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) revealCell(nr, nc);
}
}
}
renderBoard();
checkWin();
}
function renderBoard() {
const boardDiv = document.getElementById("board");
boardDiv.innerHTML = "";
board.forEach((row, r) => {
const rowDiv = document.createElement("div");
rowDiv.classList.add("row");
row.forEach((cell, c) => {
const cellDiv = document.createElement("div");
cellDiv.classList.add("cell");
if (cell.revealed) {
cellDiv.classList.add("revealed");
cellDiv.textContent = cell.mine ? "💣" : cell.number || "";
if (cell.mine) {
cellDiv.style.backgroundColor = '#ff4444';
}
}
if (cell.flagged) {
cellDiv.classList.add("flagged");
cellDiv.textContent = "🚩";
}
cellDiv.addEventListener("click", () => revealCell(r, c));
cellDiv.addEventListener("contextmenu", (e) => {
e.preventDefault();
if (!cell.revealed) {
board[r][c].flagged = !board[r][c].flagged;
renderBoard();
}
});
rowDiv.appendChild(cellDiv);
});
boardDiv.appendChild(rowDiv);
});
}
function checkWin() {
let revealedCount = 0;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (board[r][c].revealed && !board[r][c].mine) {
revealedCount++;
}
}
}
if (revealedCount === rows * cols - Math.floor(rows * cols * mineRatio)) {
gameOver = true;
showMessage("You Win!");
}
}
function showMessage(message) {
messageBox.textContent = message;
messageBox.classList.add("show");
setTimeout(() => {
messageBox.classList.remove("show");
}, 3000);
}
function undoMove() {
if (history.length > 0) {
board = history.pop();
gameOver = false; // Reset game over state
renderBoard();
if (history.length === 0) {
document.getElementById("undo-button").disabled = true;
}
}
}
startGame();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment