xxxxxxxxxx
309
// -------------------- CELL CLASS --------------------
class Cell {
constructor(row, col, type) {
this.row = row;
this.col = col;
this.type = type; // EMPTY, number 1-8, or BOMB
// handles "visiting" cells logic
this.flagged = false
this.visited = false
// handles cell display logic
this.bgcolor = color(255)
this.txtcolor = color(0)
this.size = width / SIZE
}
toString() {
return str(this.type);
}
showCell() {
// "creates" visual square for displaying cell
let x = this.col * this.size + this.size / 2
let y = this.row * this.size + this.size / 2
let txtBuffer = this.size / 7
rectMode(CENTER)
fill(this.bgcolor)
rect(x, y, this.size, this.size)
textAlign(CENTER)
fill(this.txtcolor)
textSize(1.5 * this.size / txtBuffer)
if (this.flagged) {
text(FLAG, x, y + txtBuffer)
} else {
text(this.type, x, y + txtBuffer)
}
}
}
// --------------- DIFFICULTY SETTINGS ----------------
let EASY = 0.05
let MEDIUM = 0.15
let HARD = 0.23
// MINESWEEPER BOARD: SIZExSIZE
let SIZE;
let MGRID;
let difficulty;
// TYPES
let EMPTY = ' ';
let BOMB = 'B';
// CONSTS
let FLAG = 'F';
// GAME LOGIC VARIABLES
let gameEnded = false
let playerWon = false
function setup() {
createCanvas(400, 400);
// GAME SETTINGS
SIZE = 15
difficulty = MEDIUM
// Create grid with bombs, then fill in with nums
MGRID = createInitialGrid(SIZE);
fillGrid()
// Draw background ONCE
background(90);
drawGridLines();
// For debugging
printGrid(MGRID);
}
function draw() {
// If player won
if(checkWon()) {
playerWon = true
resetScreen(true)
}
}
// ------------------ CREATE GRID FUNCTIONS --------------------
function createInitialGrid(size) {
// First iteration: randomly place bombs
let res = []
for (i = 0; i < size; i++) {
res[i] = []
for (j = 0; j < size; j++) {
if (random() < difficulty) {
res[i][j] = new Cell(i, j, BOMB)
} else {
res[i][j] = new Cell(i, j, EMPTY)
}
}
}
return res
}
function fillGrid() {
// Second iteration: for each cell, count bombs around if its not a bomb
for (h = 0; h < SIZE; h++) {
for (k = 0; k < SIZE; k++) {
// only fill in if its not a bomb!
if (MGRID[h][k].type != BOMB) {
bombcount = bombs_around(MGRID[h][k])
MGRID[h][k] = new Cell(h, k, bombcount)
}
}
}
}
// returns number of bombs around a cell
function bombs_around(cell) {
row = cell.row
col = cell.col
count = 0
// UP, DOWN, LEFT, RIGHT
if (row - 1 >= 0) {
if (MGRID[row - 1][col].type == BOMB) {
count++;
}
// TOP LEFT DIAGONAL
if (col - 1 >= 0) {
if (MGRID[row - 1][col - 1].type == BOMB) {
count++
}
}
// TOP RIGHT DIAGONAL
if (col + 1 < SIZE) {
if (MGRID[row - 1][col + 1].type == BOMB) {
count++
}
}
}
if (row + 1 < SIZE) {
if (MGRID[row + 1][col].type === BOMB) {
count++
}
// BOTTOM LEFT DIAGONAL
if (col - 1 >= 0) {
if (MGRID[row + 1][col - 1].type == BOMB) {
count++
}
}
// BOTTOM RIGHT DIAGONAL
if (col + 1 < SIZE) {
if (MGRID[row + 1][col + 1].type == BOMB) {
count++
}
}
}
if (col - 1 >= 0) {
if (MGRID[row][col - 1].type == BOMB) {
count++
}
}
if (col + 1 < SIZE) {
if (MGRID[row][col + 1].type == BOMB) {
count++
}
}
if (count == 0) {
return EMPTY
} else {
return count
}
}
// -------------------- DRAW GRID FUNCTIONS --------------------
function printGrid(grid) {
res = ''
for (i = 0; i < grid.length; i++) {
for (j = 0; j < grid[0].length; j++) {
res += str(grid[i][j]) + ' '
}
res += '\n'
}
print(res)
}
function drawGridLines() {
let weight = 10 / SIZE
strokeWeight(weight)
// draw horizontal lines
for (i = 1; i < MGRID.length; i++) {
let y = i * height / MGRID.length
line(0, y, width, y)
}
// draw vertical lines
for (i = 1; i < MGRID[0].length; i++) {
let x = i * width / MGRID[0].length
line(x, 0, x, height)
}
}
// -------------------- UPDATE GRID FUNCTIONS ------------------
function visitCell(cell) {
if (!cell.visited && !cell.flagged) {
cell.visited = true
cell.showCell()
// if it was a bomb, end game
if (cell.type == BOMB) {
resetScreen(false)
// if it was EMPTY, recursively vists ORTHOGONAL cells
} else if (cell.type == EMPTY) {
row = cell.row
col = cell.col
// TOP
if (row - 1 >= 0) {
curr = MGRID[row - 1][col]
if (curr.type != BOMB) {
visitCell(curr)
}
}
// BOTTOM
if (row + 1 < SIZE) {
curr = MGRID[row + 1][col]
if (curr.type != BOMB) {
visitCell(curr)
}
}
// LEFT
if (col - 1 >= 0) {
curr = MGRID[row][col - 1]
if (curr.type != BOMB) {
visitCell(curr)
}
}
// RIGHT
if (col + 1 < SIZE) {
curr = MGRID[row][col + 1]
if (curr.type != BOMB) {
visitCell(curr)
}
}
}
}
}
// ---------------------- GAME SCREEN LOGIC --------------------
function checkWon() {
// Return TRUE iff player has revealed all non-bomb location
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
// return false only if not bomb but hasnt been visited
cell = MGRID[i][j]
if(cell.type != BOMB && !cell.visited) {
return false
}
}
}
return true
}
function resetScreen(playerWon) {
gameEnded = true
screen_text = "GAME OVER\n"
if(playerWon) {
screen_text += "You Win!\n"
} else{
screen_text += "You Lose!\n"
}
screen_text += "Press r to reset game"
// show square background
rectWidth = (4/5)*width
rectHeight = rectWidth/2
fill(0)
rectMode(CENTER)
rect(width/2, height/1.8, rectWidth, rectHeight)
//show reset text
textAlign(CENTER)
textSize(20)
fill(255)
text(screen_text, width / 2, height / 2)
}
function resetGame() {
setup()
}
// --------------------- USER FUNCTIONALITY --------------------
function keyPressed() {
if(gameEnded) {
if(keyCode == 82 && gameEnded) {
resetGame()
}
}
}
function mouseClicked() {
let row = int(map(mouseY, 0, height, 0, MGRID.length))
let col = int(map(mouseX, 0, width, 0, MGRID[0].length))
let cell = MGRID[row][col]
visitCell(cell)
}