ArtMinesweeper

Preview image for Minesweeper
Minesweeper

This project is powered by p5.js and originates from this Minesweeper tutorial.

Live example here

Preview of Minesweeper


cell.js

	
	class Cell {
		constructor(x, y, size) {
			this.x = x;
			this.y = y;
			this.size = size;
			this.rect = {
				'topLeft': createVector((this.x * this.size), (this.y * this.size)),
				'bottomRight': createVector(((this.x + 1) * this.size), ((this.y + 1) * this.size))
			};
			this.neighbors = [];
			this.neighbor_bees = 0;
			
			this.revealed = false;
			this.bee = false;
		}
		
		countNeighbors() {
			if(this.bee) {
				return;
			}
			
			let lower_x = (this.x - 1);
			let upper_x = (this.x + 1);
			
			let lower_y = (this.y - 1);
			let upper_y = (this.y + 1);
			
			
			// row above
			for(let yy = (this.y - 1); yy <= (this.y + 1); yy++) {
				if((yy < 0) || (yy >= grid.length)) {
					continue;
				}
				
				for(let xx = (this.x - 1); xx <= (this.x + 1); xx++) {
					if((xx < 0) || (xx >= grid[ yy ].length)) {
						continue;
					}
					
					this.neighbors.push(createVector(xx, yy));
					
					if(grid[ yy ][ xx ].bee) {
						this.neighbor_bees++;
					}
				}
			}
		}

		contains(px, py) {
			return ((this.rect.topLeft.x < px) && (this.rect.topLeft.y < py) && (this.rect.bottomRight.x >= px) && (this.rect.bottomRight.y >= py));
		}

		reveal() {
			if(this.revealed) {
				return;
			}
			
			this.revealed = true;
			
			if(!this.neighbor_bees) {
				for(let i = 0; i < this.neighbors.length; i++) {
					let vec = this.neighbors[ i ];
					
					grid[ vec.y ][ vec.x ].reveal();
				}
			}
		}

		draw() {
			push();
			
			translate(this.rect.topLeft.x, this.rect.topLeft.y);
			
			if(this.revealed) {
				if(this.bee) {
					fill(255);
				} else {
					fill(200);
				}
			} else {
				fill(255);
				rect(0, 0, this.size, this.size);
			}
			
			stroke(0);
			rect(0, 0, this.size, this.size);
			
			if(this.revealed) {
				let rect_half = (this.size / 2);
				
				if(this.bee) {
					// draw bee
					push();
					
					translate(rect_half, rect_half);
					
					ellipseMode(CENTER);
					strokeWeight(3);
					stroke(0);
					fill("#fff01f");
					ellipse(0, 0, rect_half);
					
					pop();
				} else if(this.neighbor_bees > 0) {
					// draw neighbor tally
					push();
					
					//textAlign(LEFT);
					
					let text_height = (this.size * 0.66);
					
					textSize(text_height);//textSize(text_height);
					
					let text_width = textWidth(this.neighbor_bees);
					
					fill(0);
					text(this.neighbor_bees, (rect_half - (text_width / 2)), (rect_half + (text_height * 0.4)));
					
					pop();
				}
			}
			
			pop();
		}
		
		setBee() {
			if(this.bee) {
				return false;
			}
			
			this.bee = true;
			
			return true;
		}
	}
	

index.html

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
	
	<title>p5.js - Minesweeper</title>
	
	<script src="lib/p5.min.js"></script>
	<!-- <script src="lib/p5.dom.min.js"></script> -->
	<!-- <script src="lib/p5.sound.min.js"></script> -->
	
	<script src="cell.js"></script>
	
	<script src="sketch.js"></script>
</head>
	<body>
		
	</body>
</html>

sketch.js

	
	let grid = [];
	
	function setup() {
		let num_cols = 10;
		let num_rows = 12;
		let cell_size = 32;
		
		let game_width = ((num_cols * cell_size) + 1);
		let game_height = ((num_rows * cell_size) + 1);
		
		createCanvas(game_width, game_height);
		
		for(let y = 0; y < num_rows; y++) {
			grid[ y ] = [];
			
			for(let x = 0; x < num_cols; x++) {
				grid[ y ][ x ] = new Cell(x, y, cell_size);
			}
		}
		
		// add bees
		let num_bees = floor(random(ceil((num_cols / 2)), num_cols));
		let num_bees_added = 0;
		
		while(num_bees_added < num_bees) {
			let randX = floor(random(0, (num_cols - 1)));
			let randY = floor(random(0, (num_rows - 1)));
			
			if(grid[ randY ][ randX ].setBee()) {
				num_bees_added += 1;
			}
		}
		
		// count neighbors
		for(let y = 0; y < num_rows; y++) {
			for(let x = 0; x < num_cols; x++) {
				grid[ y ][ x ].countNeighbors();
			}
		}
	}
	
	function gameLost() {
		for(let cell_row in grid) {
			for(let cell_col in grid[ cell_row ]) {
				let cell = grid[ cell_row ][ cell_col ];
				
				cell.revealed = true;
			}
		}
		
		alert("Sorry, you lost!");
	}
	
	function gameWon() {
		for(let cell_row in grid) {
			for(let cell_col in grid[ cell_row ]) {
				let cell = grid[ cell_row ][ cell_col ];
				
				cell.revealed = true;
			}
		}
		
		alert("You won!");
	}
	
	function checkGameWon() {
		let num_remaining = 0;
		
		for(let cell_row in grid) {
			for(let cell_col in grid[ cell_row ]) {
				let cell = grid[ cell_row ][ cell_col ];
				
				if(!cell.bee && !cell.revealed) {
					num_remaining++;
				}
			}
		}
		
		if(num_remaining == 0) {
			gameWon();
		}
	}
	
	function draw() {
		background(255);
		
		for(let cell_row in grid) {
			for(let cell_col in grid[ cell_row ]) {
				let cell = grid[ cell_row ][ cell_col ];
				
				cell.draw();
			}
		}
	}
	
	function mousePressed() {
		for(let cell_row in grid) {
			for(let cell_col in grid[ cell_row ]) {
				let cell = grid[ cell_row ][ cell_col ];
				
				if(cell.contains(mouseX, mouseY)) {
					cell.reveal();
					
					if(cell.bee) {
						gameLost();
					} else {
						checkGameWon();
					}
				}
			}
		}
	}
	
pyxol © 2023
built with React + Next.js