Código html do jogo
Crie um arquivo chamado index.htm<!doctype html>
<html>
<meta charset=UTF-8>
<meta name=viewport content='width=device-width'>
<link rel="stylesheet" href="styles.css">
<title>MineSweeper</title>
<body>
<h1>MineSweeper</h1>
<div id="mines" data-mines=""></div>
<div id="grid"></div>
<div id="text"></div><br>
<button id="reset">Reset</button>
<footer><div></div></footer>
</body>
<script src=script.js></script>
</html>
O arquivo css
body {
background-color: #cacaca;
text-align: center;
margin: 30px;
font-family: "Segoe Ui";
}
h1 {
background-color: #101010;
padding: 20px;
font-family: "Courier";
text-transform: uppercase;
color: #ffffff;
text-align: center;
}
footer {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
}
footer div {
margin:30px;
background-color: #101010;
padding: 30px;
}
#grid {
margin-top: 12px;
margin-bottom: 20px;
display: grid;
justify-content: center;
grid-template-columns: repeat(3, 30px);
grid-template-rows: repeat(3, 30px);
}
#mines {
color: #555555;
font-weight: bold;
margin-bottom: 20px;
}
#reset {
padding: 10px;
}
.cell {
background-color: #999999;
font-size: 0;
border: 1px solid #222222;
border-radius: 4px;
padding: 8px;
}
.visible {
font-size: 16px;
background-color: #bbbbbb;
outline: none;
box-shadow: inset 0px 0px 5px #c1c1c1;
}
.flag {
background-color: #444444;
}
.visible.mine {
background-color: #ffffff;
}
O arquivo js
Na função resetBoard vai o código que desenha o jogo.const grid = document.getElementById("grid");
var gameOver = false;
var resetBoard = function() {
document.getElementById('text').innerHTML = '';
grid.style.setProperty('grid-template-columns', 'repeat(10, 30px)');
grid.style.setProperty('grid-template-rows', 'repeat(10, 30px)');
grid.innerHTML = '';
for (var i = 0; i < 100; i++) {
const cell = document.createElement("button");
cell.className = 'cell';
grid.appendChild(cell);
}
cells = grid.getElementsByClassName("cell");
for (var i = 0; i < cells.length; i++) {
cells[i].className = 'cell';
cells[i].innerHTML = '';
cells[i].addEventListener('click', clickCell, false);
cells[i].oncontextmenu = clickFlag;
}
gameOver = false;
placeMines();
placeNums();
};
As duas últimas linhas de dentro da função resetBoard chamam funções que colocam as bombas e os números no tabuleiro.placeMines e placeNums são funções que serão descritas nesse tutorial.
O código abaixo deve estar no final do arquivo javascript. Ele vincula o botão com a função que desenha o tabuleiro.
Na linha seguinte o código chama/invoca ela (resetBoard).
document.getElementById('reset').addEventListener('click', resetBoard);
resetBoard();
getImmediateNeighbors
Essa função retorna as minas que existem nas adjacências.var getImmediateNeighbors = function(cell) {
const i = [...cells].indexOf(cell);
let topRow = true;
let bottomRow = false;
const neighbors = [];
if (i > 9) {
topRow = false;
neighbors.push(cells[i-10]);
}
if (i < 90) {
neighbors.push(cells[i+10]);
}
else bottomRow = true;
if (i % 10 != 0) {
neighbors.push(cells[i-1]);
if (!topRow) neighbors.push(cells[i-11]);
if (!bottomRow) neighbors.push(cells[i+9]);
}
if (i % 10 != 9) {
neighbors.push(cells[i+1]);
if (!topRow) neighbors.push(cells[i-9]);
if (!bottomRow) neighbors.push(cells[i+11]);
}
return neighbors;
};
placeMines & placeNums
A função placeMines distribui 20 minas pela grid.var placeMines = function() {
const cells = document.getElementsByClassName("cell");
const minesI = [];
// Get unique random indexes to place the mines
mines_count = 20;
const mines_text = document.getElementById("mines");
mines_text.setAttribute("data-mines", mines_count);
mines_text.innerHTML = mines_count + " mines left";
hidden = 100;
while (minesI.length < mines_count) {
var I = Math.floor(Math.random() * cells.length);
if (minesI.indexOf(I) === -1) minesI.push(I);
}
// Set the cells with mines according to the indexes in the minesI array
for (var i = 0; i < minesI.length; i++) {
cells[minesI[i]].classList.add("mine");
cells[minesI[i]].innerHTML = "X";
}
};
A função placeNums exibe a quantidade de bombas nas adjacências.
var placeNums = function() {
for (var i = 0; i < cells.length; i++) {
if (cells[i].classList.contains('mine')) continue;
let neighbors = getImmediateNeighbors(cells[i]);
let count = 0;
for (var j = 0; j < neighbors.length; j++) {
count += neighbors[j].classList.contains('mine');
}
cells[i].innerHTML = count > 0 ? count : '';
}
};
clickFlag & clickCell
A função resetBoard atribui a chamada da função clickCell ao evento 'click' nas células/botões.var clickCell = function() {
if (gameOver) return;
if (this.classList.contains('visible')) return;
if (this.classList.contains('flag')) return;
this.classList.add('visible');
hidden = hidden - 1;
if (this.classList.contains('mine')) {
document.getElementById('text').innerHTML = "Game Over";
gameOver = true;
return;
}
if (hidden === mines_count) {
document.getElementById('text').innerHTML = "You Won !";
gameOver = true;
return;
}
if (this.childNodes.length === 0) {
let neighbors = getImmediateNeighbors(this);
for (var i = 0; i < neighbors.length; i++) {
neighbors[i].click();
}
}
};
A função resetBoard atribui a chamada da função clickFlag ao evento 'right click' nas células/botões. (cells[i].oncontextmenu=clickFlag)
var clickFlag = function() {
if (gameOver) return;
if (this.classList.contains('visible')) return;
mines_text = document.getElementById("mines");
const mines_count = Number(mines_text.getAttribute("data-mines"));
if (this.classList.contains('flag')) {
this.classList.remove('flag');
mines_text.setAttribute("data-mines", mines_count + 1);
mines_text.innerHTML = (mines_count + 1) + " mines left";
}
else {
this.classList.add('flag');
mines_text.setAttribute("data-mines", mines_count - 1);
mines_text.innerHTML = (mines_count - 1) + " mines left";
}
return false;
};
Teste
Antes de colocarmos essa página no app é preciso confirmar que ela está funcionando legal.Android Studio
Inicie um novo projeto.Uma 'activity em branco' com o package name sendo campo.minado.
A pasta 'res'
Acesse a pasta do projetoEncontre dentro dela a pasta 'res' e delete todas as pastas que estão dentro
Crie uma pasta chamada drawable e coloque dentro um 'png' que vai ser o icone do app.
Crie uma pasta raw (também dentro da /res/) e coloque dentro da /res/raw/ o arquivo html, o arquivo css e o arquivo js.
O arquivo manifest
O arquivo manifest é um arquivo de configuração.É preciso setar (no manifest) o ícone, o 'tema' e rótulo
android:icon="@drawable/icon"
android:theme="@android:style/Theme.Light.NoTitleBar"
android:label="Campo Minado"
Compilando
Já é possível gerar um app mas por enquanto ele ainda não exibe os arquivos htmlArquivo código java
Falta incluir (no MainActivity) o código java que coloca a página no apppackage tutorial.campominado;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView gameView;
gameView=new WebView(this);
gameView.getSettings().setJavaScriptEnabled(true);
gameView.loadUrl("file:///android_res/raw/index.htm");
setContentView(gameView);
}
}