From f9713d5de71dc7ef201c9dd3859d245fea2d9891 Mon Sep 17 00:00:00 2001 From: Reimar Date: Fri, 16 Aug 2024 23:25:16 +0200 Subject: [PATCH] Initial commit --- index.html | 12 ++++ minesweeper.js | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 index.html create mode 100644 minesweeper.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..85e4d6b --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + Infinite Minesweeper + + + + + + + diff --git a/minesweeper.js b/minesweeper.js new file mode 100644 index 0000000..27045c4 --- /dev/null +++ b/minesweeper.js @@ -0,0 +1,183 @@ +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++; + } + + // TODO handle out of bounds to the left / top + + 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(); +