diff options
| -rw-r--r-- | index.html | 34 | ||||
| -rw-r--r-- | mines.css | 176 | ||||
| -rw-r--r-- | mines.js | 276 | 
3 files changed, 486 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..662b4ee --- /dev/null +++ b/index.html @@ -0,0 +1,34 @@ +<!Doctype HTML>
 +<html>
 +	<head>
 +		<meta charset="utf-8">
 +		
 +		<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
 +		<link rel="stylesheet" type="text/css" href="./mines.css"/>
 +		
 +		<script src="./mines.js"></script>
 +	</head>
 +	<body>
 +		<div class="selector">
 +			<label>Width: </label> <input id="x" min="4" value="6" type="number"></input>
 +			<br>
 +			<label>Height: </label> <input id="y" min="4" value="6" type="number"></input>
 +			<br>
 +			<label>Mines: </label> <input id="m" min="2" value="5" type="number"></input>
 +		</div>
 +		<br>
 +		<div class="game">
 +			<h1 id="mines">0</h1><button id="circle" onclick="game.reset()"></button><h1 id="time">0</h1>
 +			<br>
 +			<table>
 +				<tbody id="gtable"><tr><td class="wt">◉</td></tr></tbody>
 +			</table>
 +		</div>
 +		<script>
 +			var xIn = document.getElementById("x");
 +			var yIn = document.getElementById("y");
 +			var mIn = document.getElementById("m");
 +			var game = new Board();
 +		</script>
 +	</body>
 +</html>
\ No newline at end of file diff --git a/mines.css b/mines.css new file mode 100644 index 0000000..552a4e4 --- /dev/null +++ b/mines.css @@ -0,0 +1,176 @@ +*{
 +	font-family: 'Open Sans', sans-serif;
 +}
 +
 +body{
 +	text-align: center;
 +}
 +
 +div.selector, div.game{
 +	display: inline-block;
 +}
 +
 +div.selector{
 +	text-align: right;
 +}
 +
 +div.game{
 +	min-width: 25%;
 +	margin-top: 50px;
 +}
 +
 +input{
 +	padding: 5px;
 +	margin: 5px;
 +	background-color: #eee;
 +	border: none;
 +	border-radius: 5px;
 +	transition-duration: 0.2s;
 +}
 +
 +input:hover{
 +	background-color: #ccc;
 +}
 +
 +input:focus{
 +	background-color: #cef;
 +	border: none;
 +}
 +
 +input:active{
 +	background-color: #cef;
 +	border: none;
 +}
 +
 +button{
 +	padding: 5px;
 +	margin: 5px;
 +	background-color: #eee;
 +	border: none;
 +	border-radius: 5px;
 +	transition-duration: 0.2s;
 +}
 +
 +button:hover{
 +	background-color: #ccc;
 +}
 +
 +button:active{
 +	background-color: #cef;
 +	border: none;
 +}
 +
 +h1{
 +	width: calc(50% - 70px);
 +	
 +	display: inline;
 +	
 +	background-color: #eee;
 +	
 +	border-radius: 25%;
 +}
 +
 +h1#mines{
 +	float: left;
 +}
 +
 +h1#time{
 +	float: right;
 +}
 +
 +/* Table */
 +
 +table{
 +	display: inline-table;
 +	background-color: #ddd;
 +	border-radius: 10px;
 +	padding: 5px;
 +}
 +
 +td{
 +	width: 35px;
 +	height: 35px;
 +	
 +	margin: 5px;
 +	padding: 2px;
 +	
 +	background-color: #bbb;
 +	
 +	box-sizing: border-box;
 +	
 +	border-radius: 25%;
 +	
 +	transition-duration: 0.2s;
 +	
 +	cursor: default;
 +}
 +
 +td.wt:hover{
 +	background-color: #777;
 +}
 +
 +td.wt:active{
 +	background-color: #999;
 +}
 +
 +td.chkd{
 +	background-color: #888;
 +}
 +
 +/* Main button */
 +
 +button#circle{
 +	padding: 35px;
 +	border: none;
 +	border-radius: 50%;
 +	box-sizing: border-box;
 +}
 +
 +button#circle:active{
 +	border: none;
 +}
 +
 +button#circle.win{
 +	background-color: #0f4;
 +}
 +
 +button#circle.win:hover{
 +	background-color: #0d2;
 +}
 +
 +button#circle.lose{
 +	background-color: #f33;
 +}
 +
 +button#circle.lose:hover{
 +	background-color: #d11;
 +}
 +
 +button#circle.ingame{
 +	background-color: #fa0;
 +	animation: 1s infinite alternate shrink;
 +}
 +
 +button#circle.ingame:hover{
 +	background-color: #d80;
 +}
 +
 +button#circle.loading{
 +	background-color: #0af;
 +	animation: 1s infinite alternate shrink;
 +}
 +
 +button#circle.loading:hover{
 +	background-color: #08d;
 +}
 +
 +@keyframes shrink{
 +	from{
 +		padding: 35px;
 +		margin-top: 0px;
 +	}
 +	to{
 +		padding: 15px;
 +		margin-top: 20px
 +	}
 +}
\ No newline at end of file diff --git a/mines.js b/mines.js new file mode 100644 index 0000000..da0fa4d --- /dev/null +++ b/mines.js @@ -0,0 +1,276 @@ +var colors = ["blue", "limegreen", "orange", "red", "purple", "cyan", "gold", "black"];
 +
 +var mine = "\u25C9";
 +
 +function Board(){
 +	this.sMines = document.getElementById("mines");
 +	this.sTime = document.getElementById("time");
 +	
 +	this.circle = document.getElementById("circle");
 +	
 +	this.table = document.getElementById("gtable");
 +	this.table.parentElement.addEventListener("contextmenu", function(e){e.preventDefault();});
 +	
 +	this.mines = [[0]];
 +	this.mTotal = 0;
 +	this.mChecked = 0;
 +	
 +	this.boardDim = [1, 1];
 +	this.checked = 0;
 +	
 +	this.time = 0;
 +	this.clock = -1;
 +	
 +	this.running = false;
 +	this.started = false;
 +}
 +
 +Board.prototype = {
 +	
 +	//Second
 +	
 +	sec: function(){
 +		let c = parseInt(this.sTime.textContent);
 +		c++;
 +		this.sTime.textContent = c;
 +	},
 +	
 +	//Game states
 +	
 +	win: function(){
 +		this.running = false;
 +		clearInterval(this.clock);
 +		this.clock = -1;
 +		this.circle.className = "win";
 +		
 +		this.revealMines("#08d");
 +	},
 +	
 +	lose: function(x, y){
 +		this.running = false;
 +		clearInterval(this.clock);
 +		this.clock = -1;
 +		this.circle.className = "lose";
 +		
 +		this.revealMines("black");
 +		
 +		this.getMineEl(x, y).style.color = "red";
 +	},
 +	
 +	revealMines: function(color){
 +		let lp = this.mines.length;
 +		for(let i = 0; i < lp; i++){
 +			let lp2 = this.mines[i].length;
 +			for(let j = 0; j < lp2; j++){
 +				let e = this.getMineEl(this.mines[i][j], i);
 +				e.style.color = color;
 +				e.textContent = mine;
 +			}
 +		}
 +	},
 +	
 +	start: function(x, y){
 +		this.started = true;
 +		let flag = false;
 +		if(this.isMine(x, y)){
 +			for(let i = 0; i < this.boardDim[1] && !flag; i++){
 +				for(let j = 0; j < this.boardDim[0] && !flag; j++){
 +					if(!this.isMine(j, i)){
 +						this.mines[i].push(j);
 +						flag = true;
 +					}
 +				}
 +			}
 +			this.mines[y].splice(this.mines[y].indexOf(x), 1);
 +		}
 +	},
 +	
 +	//Event managers
 +	
 +	click: function(e){
 +		let el = e.target;
 +		var x = parseInt(el.getAttribute("x")), y = parseInt(el.getAttribute("y"));
 +		
 +		if(!this.running || el.textContent !== "" || el.classList.contains("chkd")) return;
 +		
 +		if(!this.started){
 +			this.start(x, y);
 +		}
 +		
 +		if(this.isMine(x, y)){
 +			this.lose(x, y);
 +			return;
 +		}
 +		
 +		this.check(x, y);
 +	},
 +	
 +	ctxMenu: function(e){
 +		let el = e.target;
 +		var x = parseInt(el.getAttribute("x")), y = parseInt(el.getAttribute("y"));
 +		
 +		if(el.classList.contains("chkd") || !this.running || !this.started) {
 +			e.preventDefault();
 +			return;
 +		}
 +		
 +		if(el.textContent == "!"){
 +			
 +			el.textContent = "?";
 +			this.mChecked--;
 +		}else if(el.textContent == "?"){
 +			
 +			el.textContent = "";
 +		}else{
 +			
 +			el.textContent = "!";
 +			this.mChecked++;
 +		}
 +		this.sMines.textContent = this.mTotal - this.mChecked;
 +		e.preventDefault();
 +	},
 +	
 +	//Recognizing the click
 +	
 +	isMine: function(x, y){
 +		if(y >= this.mines.length || y < 0) return false;
 +		return this.mines[y].includes(x);
 +	},
 +	
 +	isChecked: function(x, y){
 +		if(y >= this.boardDim[1] || y < 0) return true;
 +		if(x >= this.boardDim[0] || x < 0) return true;
 +		return this.table.children[y].children[x].className == "chkd";
 +	},
 +	
 +	numAround: function(x, y){
 +		let m = 0;let dx = x;
 +		if(this.isMine(dx, y+1)) m++;
 +		if(this.isMine(dx, y-1)) m++;
 +		dx = x+1;
 +		if(this.isMine(dx, y)) m++;
 +		if(this.isMine(dx, y+1)) m++;
 +		if(this.isMine(dx, y-1)) m++;
 +		dx = x-1;
 +		if(this.isMine(dx, y)) m++;
 +		if(this.isMine(dx, y+1)) m++;
 +		if(this.isMine(dx, y-1)) m++;
 +		return m;
 +	},
 +	
 +	getMineEl: function(x, y){
 +		return this.table.children[y].children[x];
 +	},
 +	
 +	check: function(x, y){
 +		if(!this.running) return;
 +		
 +		let n = this.numAround(x, y);
 +		let e = this.getMineEl(x, y);
 +		
 +		e.className = "chkd";
 +		
 +		if(n !== 0){
 +			
 +			e.style.color = colors[n-1];
 +			e.textContent = n;
 +		}else{
 +			
 +			this.findPath(x, y);
 +		}
 +		
 +		this.checked++;
 +		if(this.checked == (this.boardDim[0]*this.boardDim[1] - this.mTotal)) this.win();
 +	},
 +	
 +	findPath: function(x, y){
 +		let dx = x;
 +		if(!this.isChecked(dx, y+1)) this.check(dx, y+1);
 +		if(!this.isChecked(dx, y-1)) this.check(dx, y-1);
 +		dx = x+1;
 +		if(!this.isChecked(dx, y+1)) this.check(dx, y+1);
 +		if(!this.isChecked(dx, y-1)) this.check(dx, y-1);
 +		if(!this.isChecked(dx, y)) this.check(dx, y);
 +		dx = x-1;
 +		if(!this.isChecked(dx, y+1)) this.check(dx, y+1);
 +		if(!this.isChecked(dx, y-1)) this.check(dx, y-1);
 +		if(!this.isChecked(dx, y)) this.check(dx, y);
 +	},
 +	
 +	//Managing the board
 +	
 +	reset: function(){
 +		this.circle.className = "loading";
 +		
 +		let x = xIn.value;
 +		let y = yIn.value;
 +		let mines = mIn.value;
 +		
 +		if(mines >= x*y-1) {
 +			this.circle.className = "lose";
 +			return;
 +		}
 +		
 +		this.started = false;
 +		
 +		this.boardDim = [x, y];
 +		
 +		while(this.table.firstChild){
 +			this.table.firstChild.remove();
 +		}
 +		
 +		this.mTotal = mines;
 +		this.mChecked = 0;
 +		this.mines = [];
 +		this.checked = 0;
 +		this.sMines.textContent = mines;
 +		
 +		this.sTime.textContent = 0;
 +		if(this.clock !== -1) clearInterval(this.clock);
 +		this.clock = -1;
 +		
 +		let mRarity = x*y*0.8;
 +		
 +		for(let i = 0; i < y; i++){
 +			
 +			let row = document.createElement("tr");
 +			
 +			this.mines.push([]);
 +			
 +			for(let j = 0; j < x; j++){
 +				
 +				let cell = document.createElement("td");
 +				cell.setAttribute("x", j);
 +				cell.setAttribute("y", i);
 +				cell.classList = ["wt"];
 +				cell.addEventListener("click", this.click.bind(this));
 +				cell.addEventListener("contextmenu", this.ctxMenu.bind(this));
 +				row.appendChild(cell);
 +				
 +				if(mines > 0 && Math.floor(Math.random()*mRarity) == 0){
 +					this.mines[i].push(j);
 +					mines--;
 +				}
 +			}
 +			
 +			this.table.appendChild(row);
 +		}
 +		
 +		while(mines > 0){
 +			for(let i = 0; i < y; i++){
 +				if(mines <= 0) break;
 +				for(let j = 0; j < x; j++){
 +					if(mines <= 0) break;
 +					if(!this.isMine(j, i) && Math.floor(Math.random()*mRarity) == 0){
 +						this.mines[i].push(j);
 +						mines--;
 +					}
 +				}
 +			}
 +		}
 +		
 +		this.circle.className = "ingame";
 +		this.running = true;
 +		this.clock = setInterval(this.sec.bind(this), 1000);
 +	}
 +};
\ No newline at end of file  |