infinite-minesweeper/minesweeper.js
2024-08-16 23:26:58 +02:00

182 lines
4.9 KiB
JavaScript

var board = [];
const canvas = document.getElementById("minesweeper");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const context = canvas.getContext("2d");
let scrollX = 0, scrollY = 0;
const CELL_SIZE = 20;
const STROKE_SIZE = 2;
const MINE_CHANCE = 0.2;
class Cell {
constructor(isRevealed, isMine, isFlagged) {
this.isRevealed = isRevealed;
this.isMine = isMine;
this.isFlagged = isFlagged;
}
}
// Initialize board
for (let x = 0; x < Math.floor(window.innerWidth / CELL_SIZE) + 1; x++) {
board.push([]);
for (let y = 0; y < Math.floor(window.innerHeight / CELL_SIZE) + 1; y++) {
board[x].push(new Cell(false, Math.random() < MINE_CHANCE, false));
}
}
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(-scrollX, -scrollY);
for (let x = 0; x < board.length; x++) {
for (let y = 0; y < board[x].length; y++) {
const cell = board[x][y];
context.fillStyle = cell.isRevealed ? "#AAA" : "#BDBDBD";
context.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
context.fillStyle = cell.isRevealed ? "#424242" : "#EEE";
context.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE - STROKE_SIZE, STROKE_SIZE);
context.fillRect(x * CELL_SIZE, y * CELL_SIZE, STROKE_SIZE, CELL_SIZE - STROKE_SIZE);
context.fillStyle = cell.isRevealed ? "#EEE" : "#424242";
context.fillRect(x * CELL_SIZE + CELL_SIZE - STROKE_SIZE, y * CELL_SIZE + STROKE_SIZE, STROKE_SIZE, CELL_SIZE - STROKE_SIZE);
context.fillRect(x * CELL_SIZE + STROKE_SIZE, y * CELL_SIZE + CELL_SIZE - STROKE_SIZE, CELL_SIZE - STROKE_SIZE, STROKE_SIZE);
if (cell.isRevealed) {
if (cell.isMine) {
context.fillStyle = "black";
context.beginPath();
context.arc(x * CELL_SIZE + CELL_SIZE / 2, y * CELL_SIZE + CELL_SIZE / 2, CELL_SIZE / 3, 0, 2 * Math.PI);
context.fill();
} else if (getCellNumber(x, y) > 0) {
context.font = "18px monospace";
context.textAlign = "center";
context.fillStyle = ["#0000ff", "#00ff00", "#ff0000", "#010280", "#7e0000", "#027f80", "#000000", "#808080"][getCellNumber(x, y) - 1];
context.fillText(getCellNumber(x, y), x * CELL_SIZE + CELL_SIZE / 2, y * CELL_SIZE + CELL_SIZE * 0.8);
}
}
}
}
context.setTransform(1, 0, 0, 1, 0, 0);
}
function screenCoordsToBoardCoords(x, y) {
return {
x: Math.floor((x - scrollX) / CELL_SIZE),
y: Math.floor((y - scrollY) / CELL_SIZE),
};
}
function createColumnAtRight() {
const newArr = [];
for (let i = 0; i < board[0].length; i++) {
newArr.push(new Cell(false, Math.random() < MINE_CHANCE, false));
}
board.push(newArr);
}
function createColumnAtLeft() {
const newArr = [];
for (let i = 0; i < board[0].length; i++) {
newArr.push(new Cell(false, Math.random() < MINE_CHANCE, false));
}
board.unshift(newArr);
scrollX += CELL_SIZE;
}
function createRowAtBottom() {
for (let i = 0; i < board.length; i++) {
board[i].push(new Cell(false, Math.random() < MINE_CHANCE, false));
}
}
function createRowAtTop() {
for (let i = 0; i < board.length; i++) {
board[i].unshift(new Cell(false, Math.random() < MINE_CHANCE, false));
}
scrollY += CELL_SIZE;
}
function getCellsAround(x, y) {
if (x + 1 >= board.length) {
createColumnAtRight();
}
if (y + 1 >= board[0].length) {
createRowAtBottom();
}
if (x <= 0) {
createColumnAtLeft();
x++;
}
if (y <= 0) {
createRowAtTop();
y++;
}
return [
[x - 1, y - 1],
[x, y - 1],
[x + 1, y - 1],
[x - 1, y],
[x + 1, y],
[x - 1, y + 1],
[x, y + 1],
[x + 1, y + 1],
];
}
function getCellNumber(x, y) {
return getCellsAround(x, y)
.reduce((acc, coords) => acc += board[coords[0]][coords[1]].isMine ? 1 : 0, 0);
}
function revealCell(x, y) {
board[x][y].isRevealed = true;
if (getCellNumber(x, y) === 0) {
getCellsAround(x, y, false).forEach(coords => {
const cell = board[coords[0]][coords[1]];
if (!cell.isRevealed && getCellNumber(x, y) === 0)
revealCell(coords[0], coords[1]);
});
}
}
window.addEventListener("mousedown", event => {
const { x, y } = screenCoordsToBoardCoords(event.pageX + scrollX * 2, event.pageY + scrollY * 2);
revealCell(x, y);
draw();
});
window.addEventListener("wheel", event => {
if (event.shiftKey) {
scrollX += event.deltaY;
} else {
scrollX += event.deltaX;
scrollY += event.deltaY;
}
// TODO create new rows/columns on scroll
draw();
});
draw();