По правилам игры Сапёр, игра идёт на квадратном игровом поле, расчерченном на клетки. Игрок открывает клетку на игровом поле, компьютер подсчитывает сколько мин окружает эту клетку.

Количество соседних мин выводится на клетку, котрую открыл игрок. Если игрок нажал на клетку под которой установлена мина, игрок проиграл. Можно пометить флажком клетку под которой, возможно, скрывается мина. Игра заканчивается победой игрока, если игрок пометил все мины или открыл все клетки без мин. 

Клетка, вокруг которой нет мин, в восьми клетках вокруг неё 0 мин, в случае когда игрок её находит, просто закрашивается. То есть, в такую клетку 0 не ставится, кроме того, соседние с этой клеткой компьютер открывает сам. Так же компьютер поступит и с теми соседними клетками, вокруг которых, так же окажется 0 мин. 

Рис. 1. Так будет выглядеть мина на игровом поле, если игрок случайно заденет её. 

<html>
	<head>
		<style>
		</style>
	</head>
	<body>
		<script>
		</script>
	</body>
</html>

Mines01.html Шаблон html страницы.

В следующей версии программы, создаём контейнер canvas.

<html>
	<head>
		<style>
		</style>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<script>
		</script>
	</body>
</html>

Mines02.html

В следующей программе, сохраняем в переменной cnvs ссылку на объект canvas.

<html>
	<head>
		<style>
		</style>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<script>
			cnvs = document.getElementById('cnvs');
			console.log(cnvs);
		</script>
	</body>
</html>

Mines03.html

В следующей программе, переносим контейнер <script> из <body> в <head>.

<html>
	<head>
		<style>
		</style>
		<script>
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				console.log(cnvs);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines04.html

В следующей программе, задаём размер canvas.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 24;
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				console.log(cnvs);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines05.html

В следующей программе, сохраняем в переменной ctx ссылку на контекст объекта canvas.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 24;
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				ctx = cnvs.getContext('2d');
				console.log(ctx);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines06.html

В следующей программе, определяем как будет выглядеть клетка на игровом поле.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 24;
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				ctx.strokeRect(1, 1, size-3, size-3);
				ctx.strokeStyle = 'black';
				ctx.fillText(3, size/2, size-5);
				if(size>24){
					ctx.strokeText(3, size/2, size-5);
				}
				console.log(ctx);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines07.html

В следующей программе, выводим на экран игровое поле.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 24;
			function prn(){
				ctx.strokeStyle = 'black';
				ctx.fillText(3, size/2, size-5);
				if(size>24){
					ctx.strokeText(3, size/2, size-5);
				}
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				console.log(ctx);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines08.html

В следующей программе, создаём виртуальное игровое поле playArea (массив), наполняем его минами и перемешиваем.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 24;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function prn(){
				ctx.strokeStyle = 'black';
				ctx.fillText(3, size/2, size-5);
				if(size>24){
					ctx.strokeText(3, size/2, size-5);
				}
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				console.log(playArea);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines09.html

В следующей программе, выводим на экран мины.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				for(i=0; i<rowCol*rowCol; i++){
					if(playArea[i]==1){
						prn("🚩", i)
					}
				}
				console.log(playArea);
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines10.html

В следующей программе, создаём функцию play(event).

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function play(event){
				console.log(event)
				console.log(event.x)
				console.log(event.target.offsetLeft)
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				for(i=0; i<rowCol*rowCol; i++){
					if(playArea[i]==1){
						prn("🚩", i)
					}
				}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines11.html

В следующей программе, вычисляем координаты мыши в системе координат canvas.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function play(event){
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				console.log(mouseX, mouseY)
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				for(i=0; i<rowCol*rowCol; i++){
					if(playArea[i]==1){
						prn("🚩", i)
					}
				}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines12.html

В следующей программе, вычисляем номер клетки, номер строки и номер колонки в точке по которой кликнули мышью.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function play(event){
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				console.log(cell)
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				for(i=0; i<rowCol*rowCol; i++){
					if(playArea[i]==1){
						prn("🚩", i)
					}
				}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines13.html

В следующей программе, считаем мины окружающие клетку.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				quant += playArea[n-1];
				quant += playArea[n+1];
				quant += playArea[n-rowCol];
				quant += playArea[n-rowCol-1];
				quant += playArea[n-rowCol+1];
				quant += playArea[n+rowCol];
				quant += playArea[n+rowCol-1];
				quant += playArea[n+rowCol+1];
				return quant;
			}
			function play(event){
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				console.log(quantity(cell));
				prn(quantity(cell), cell);
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				for(i=0; i<rowCol*rowCol; i++){
					if(playArea[i]==1){
						prn("🚩", i)
					}
				}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines14.html

В следующей программе, убираем мины с экрана и обнаруживаем случай попадания на мину.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				quant += playArea[n-1];
				quant += playArea[n+1];
				quant += playArea[n-rowCol];
				quant += playArea[n-rowCol-1];
				quant += playArea[n-rowCol+1];
				quant += playArea[n+rowCol];
				quant += playArea[n+rowCol-1];
				quant += playArea[n+rowCol+1];
				return quant;
			}
			function play(event){
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(playArea[cell] == 1  || gameOwer){
					gameOwer = true;
					alert('Game Ower!');
					return;
				}
				console.log(quantity(cell));
				prn(quantity(cell), cell);
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				prn("🚩", 0)
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines15.html

В следующей программе, вместо символа "0" просто закрасим клетку каким нибудь цветом.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				quant += playArea[n-1];
				quant += playArea[n+1];
				quant += playArea[n-rowCol];
				quant += playArea[n-rowCol-1];
				quant += playArea[n-rowCol+1];
				quant += playArea[n+rowCol];
				quant += playArea[n+rowCol-1];
				quant += playArea[n+rowCol+1];
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(event){
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(playArea[cell] == 1  || gameOwer){
					gameOwer = true;
					alert('Game Ower!');
					return;
				}
				console.log(quantity(cell));
				prn(quantity(cell), cell);
				if(quantity(cell) == 0){
					filler(cell);
				}
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				prn("🚩", 0)
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines16.html

В следующей программе, выведем на клетку с миной изображение, например, "Андроида".

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				quant += playArea[n-1];
				quant += playArea[n+1];
				quant += playArea[n-rowCol];
				quant += playArea[n-rowCol-1];
				quant += playArea[n-rowCol+1];
				quant += playArea[n+rowCol];
				quant += playArea[n+rowCol-1];
				quant += playArea[n+rowCol+1];
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size, size, size);
					gameOwer = true;
					return;
				}
				prn(quantity(cell), cell);
				if(quantity(cell) == 0){
					filler(cell);
				}
			}
			window.onload = function draw(){
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
				prn("🚩", 0)
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
	</body>
</html>

Mines17.html

В следующей программе, добавить возможность поставить флаг на игровом поле.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				quant += playArea[n-1];
				quant += playArea[n+1];
				quant += playArea[n-rowCol];
				quant += playArea[n-rowCol-1];
				quant += playArea[n-rowCol+1];
				quant += playArea[n+rowCol];
				quant += playArea[n+rowCol-1];
				quant += playArea[n+rowCol+1];
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(btnFlag.checked){
					prn("🚩", cell);
					return;
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				prn(quantity(cell), cell);
				if(quantity(cell) == 0){
					filler(cell);
				}
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines18.html

В следующей программе, учтём ограничения, накладываемые на подсчёт мин, окружающих клетку расположенную на границах игрового поля.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				if(col(n)>0){quant += playArea[n-1];}
				if(col(n)<(rowCol-1)){quant += playArea[n+1];}
				if(row(n)>0){quant += playArea[n-rowCol];}
				if(row(n)>0 && col(n)>0){quant += playArea[n-rowCol-1];}
				if(row(n)>0 && col(n)<(rowCol-1)){quant += playArea[n-rowCol+1];}
				if(row(n)<(rowCol-1)){quant += playArea[n+rowCol];}
				if(row(n)<(rowCol-1) && col(n)>0){quant += playArea[n+rowCol-1];}
				if(row(n)<(rowCol-1) && col(n)<(rowCol-1)){quant += playArea[n+rowCol+1];}
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(btnFlag.checked){
					prn("🚩", cell);
					return;
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				prn(quantity(cell), cell);
				if(quantity(cell) == 0){
					filler(cell);
				}
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines19.html

 

Рис. 2.

В следующей программе, дадим игроку возможность снимать флажки.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			flags = [];
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				flags[i] = 0;
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				if(col(n)>0){quant += playArea[n-1];}
				if(col(n)<(rowCol-1)){quant += playArea[n+1];}
				if(row(n)>0){quant += playArea[n-rowCol];}
				if(row(n)>0 && col(n)>0){quant += playArea[n-rowCol-1];}
				if(row(n)>0 && col(n)<(rowCol-1)){quant += playArea[n-rowCol+1];}
				if(row(n)<(rowCol-1)){quant += playArea[n+rowCol];}
				if(row(n)<(rowCol-1) && col(n)>0){quant += playArea[n+rowCol-1];}
				if(row(n)<(rowCol-1) && col(n)<(rowCol-1)){quant += playArea[n+rowCol+1];}
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(btnFlag.checked){
					if(flags[cell] == 0){
					prn("🚩", cell);
					flags[cell] = 1;
					return;
					}
					else{
					prn(" ", cell);
					flags[cell] = 0;
					return;
					}
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				prn(quantity(cell), cell);
				if(quantity(cell) == 0){
					filler(cell);
				}
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", play, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines20.html

В следующей программе, разделим функцию play() на 2 части.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			flags = [];
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				flags[i] = 0;
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				if(col(n)>0){quant += playArea[n-1];}
				if(col(n)<(rowCol-1)){quant += playArea[n+1];}
				if(row(n)>0){quant += playArea[n-rowCol];}
				if(row(n)>0 && col(n)>0){quant += playArea[n-rowCol-1];}
				if(row(n)>0 && col(n)<(rowCol-1)){quant += playArea[n-rowCol+1];}
				if(row(n)<(rowCol-1)){quant += playArea[n+rowCol];}
				if(row(n)<(rowCol-1) && col(n)>0){quant += playArea[n+rowCol-1];}
				if(row(n)<(rowCol-1) && col(n)<(rowCol-1)){quant += playArea[n+rowCol+1];}
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(n){
				prn(quantity(n), n);
				if(quantity(n) == 0){
					filler(n);
				}
			}
			function miner(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(btnFlag.checked){
					if(flags[cell] == 0){
					prn("🚩", cell);
					flags[cell] = 1;
					return;
					}
					else{
					prn(" ", cell);
					flags[cell] = 0;
					return;
					}
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				play(cell);
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", miner, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines21.html

В следующей программе, создадим матрицу открытых клеток.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			matrix = [];
			flags = [];
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				matrix[i] = 0;
				flags[i] = 0;
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				if(col(n)>0){quant += playArea[n-1];}
				if(col(n)<(rowCol-1)){quant += playArea[n+1];}
				if(row(n)>0){quant += playArea[n-rowCol];}
				if(row(n)>0 && col(n)>0){quant += playArea[n-rowCol-1];}
				if(row(n)>0 && col(n)<(rowCol-1)){quant += playArea[n-rowCol+1];}
				if(row(n)<(rowCol-1)){quant += playArea[n+rowCol];}
				if(row(n)<(rowCol-1) && col(n)>0){quant += playArea[n+rowCol-1];}
				if(row(n)<(rowCol-1) && col(n)<(rowCol-1)){quant += playArea[n+rowCol+1];}
				return quant;
			}
			function filler(n){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
			}
			function play(n){
				if(matrix[n] == 1){
					return;
				}
				matrix[n] = 1;
				prn(quantity(n), n);
				if(quantity(n) == 0){
					filler(n);
				}
			}
			function miner(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(matrix[cell] == 1){
					return;
				}
				if(btnFlag.checked){
					if(flags[cell] == 0){
					prn("🚩", cell);
					flags[cell] = 1;
					return;
					}
					else{
					prn(" ", cell);
					flags[cell] = 0;
					return;
					}
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				play(cell);
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", miner, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines22.html

В следующей программе, компьютер сам будет открывать смежные пустые клетки.

<html>
	<head>
		<style>
			body {
				text-align:center
			}
		</style>
		<script>
			mine = new Image();
			mine.src = "mine.png";
			gameOwer = false;
			rowCol = 20;
			size = 28;
			delta = 6;
			matrix = [];
			flags = [];
			playArea = [];
			for(i=0; i<rowCol**2; i++){
				matrix[i] = 0;
				flags[i] = 0;
				playArea[i] = 0;
				if(i/6 - parseInt(i/6) == 0){
					playArea[i] = 1;
				}
			}
			playArea.sort(()=>Math.random()-0.5);
			function row(n){
				return parseInt(n / rowCol);
			}
			function col(n){
				return n % rowCol;
			}
			function prn(txt, n){
				ctx.clearRect(col(n)*size+2, row(n)*size+2, size-5, size-5);
				ctx.strokeStyle = 'black';
				ctx.fillStyle = 'black';
				ctx.fillText(txt, col(n)*size+size/2, row(n)*size+size-5);
				if(size>24){
					ctx.strokeText(txt, col(n)*size+size/2, row(n)*size+size-5);
				}
			}
			function quantity(n){
				quant = 0;
				if(col(n)>0){quant += playArea[n-1];}
				if(col(n)<(rowCol-1)){quant += playArea[n+1];}
				if(row(n)>0){quant += playArea[n-rowCol];}
				if(row(n)>0 && col(n)>0){quant += playArea[n-rowCol-1];}
				if(row(n)>0 && col(n)<(rowCol-1)){quant += playArea[n-rowCol+1];}
				if(row(n)<(rowCol-1)){quant += playArea[n+rowCol];}
				if(row(n)<(rowCol-1) && col(n)>0){quant += playArea[n+rowCol-1];}
				if(row(n)<(rowCol-1) && col(n)<(rowCol-1)){quant += playArea[n+rowCol+1];}
				return quant;
			}
			function filler(m){
				ctx.fillStyle = 'darkKhaki';
				ctx.fillRect(col(m)*size+2, row(m)*size+2, size-5, size-5);
				if(col(m)>0){play(m-1);}
				if(col(m)<(rowCol-1)){play(m+1);}
				if(row(m)>0){play(m-rowCol);}
				if(row(m)>0 && col(m)>0){play(m-rowCol-1);}
				if(row(m)>0 && col(m)<(rowCol-1)){play(m-rowCol+1);}
				if(row(m)<(rowCol-1)){play(m+rowCol);}
				if(row(m)<(rowCol-1) && col(m)>0){play(m+rowCol-1);}
				if(row(m)<(rowCol-1) && col(m)<(rowCol-1)){play(m+rowCol+1);}
			}
			function play(n){
				if(matrix[n] == 1){
					return;
				}
				matrix[n] = 1;
				prn(quantity(n), n);
				if(quantity(n) == 0){
					filler(n);
				}
			}
			function miner(event){
				if(gameOwer){
					alert('Game Ower!');
					return;
				}
				mouseX = event.x-event.target.offsetLeft;
				mouseY = event.y-event.target.offsetTop;
				cell = parseInt(mouseY / size) * rowCol + parseInt(mouseX / size);
				if(matrix[cell] == 1){
					return;
				}
				if(btnFlag.checked){
					if(flags[cell] == 0){
					prn("🚩", cell);
					flags[cell] = 1;
					return;
					}
					else{
					prn(" ", cell);
					flags[cell] = 0;
					return;
					}
				}
				if(playArea[cell] == 1){
					ctx.clearRect(col(cell)*size+2, row(cell)*size+2, size-5, size-5);
					ctx.textAlign = '';
					ctx.drawImage(mine, col(cell)*size, row(cell)*size-1, size, size);
					gameOwer = true;
					return;
				}
				play(cell);
			}
			window.onload = function draw(){
				btnFlag = document.getElementById('flag');
				cnvs = document.getElementById('cnvs');
				cnvs.width = rowCol*size;
				cnvs.height = rowCol*size;
				cnvs.addEventListener("mousedown", miner, false);
				ctx = cnvs.getContext('2d');
				ctx.strokeStyle = 'green';
				ctx.textAlign = 'center';
				ctx.font = (size-4)+'px sans-serif';
				for(m=0; m<rowCol; m++){
					for(n=0; n<rowCol; n++){
						ctx.strokeRect(n*size+1, m*size+1, size-3, size-3);
				}}
			}
		</script>
	</head>
	<body>
		<canvas id="cnvs"></canvas>
		<form>
			Ход
			<input type=radio name=btn checked>
			<input type=radio name=btn id="flag">
			Флаг
		</form>
	</body>
</html>

Mines23.html

Игра на Github

Литература: Drawing on Canvas

Emoji Unicode Tables