Desenvolvendo um Jogo da Velha / Parte 2
Vamos continuar com nosso Jogo da Velha e aprender mais um pouco sobre a API do JavaScript e praticar mais programação.
Na primeira parte nós vimos como podemos utilizar as matrizes para representar nosso tabuleiro e como exibi-lo na tela, mas ainda faltou uma forma interagir com o tabuleiro fazendo as jogadas. Então nesta parte vamos focar em utilizar os recursos do Javascript para adicionar interação com o nosso jogo. Para isso vamos ter que alterar nosso código, refatorar, para adicionar essa interação.
Melhorando nosso código
Vamos começar mudando a forma como declaramos o nosso tabuleiro. Ao invés de atribuir o valor que representa a posição vazia do nosso tabuleiro para cada uma de suas posições, vamos criar um objeto literal de Javascript chamado VAZIO
com a propriedade simbolo
com o valor "_"
(underline), apenas por motivos estéticos:
var VAZIO = {
simbolo : "_"
};
Para quem não se recorda, um objeto literal em Javascript é uma variável que pode conter outras propriedades, atributos, e para acessarmos cada uma de suas propriedades precisamos passar o nome do objeto seguido de um ponto e em seguida o nome da propriedade, como por exemplo, VAZIO.simbolo
.
Para saber mais sobre objetos literais em Javascript: Mozilla Developer Network - Objetos Literais
E então vamos apenas atribuir o objeto VAZIO
para cada uma das posições do tabuleiro, dessa forma:
var VAZIO = {
simbolo : "_"
};
var tabuleiro = [
[VAZIO,VAZIO,VAZIO],
[VAZIO,VAZIO,VAZIO],
[VAZIO,VAZIO,VAZIO]
];
Assim fica mais fácil entender que estamos criando um tabuleiro e definindo que cada posição dele está VAZIO
.
Por enquanto nosso tabuleiro estará sendo mostrado dessa forma, mas logo iremos resolver isso, não se preocupe.
Continuando, as funções desenharTabuleiro()
e novaLinha()
estão utilizando a função document.write()
e isso vai ser um problema... O problema em utilizar o document.write()
é que ao utilizar esta função depois da página ter terminado de carregar ela imediatamente invoca a função document.open()
que apaga todo o conteúdo do nosso arquivo HTML, incluindo o nosso código com as variáveis e funções. É uma nova página em branco.
Para evitar isso vamos utilizar as funções do Javascript para modificar o conteúdo da página sem utilizar a função document.write()
.
Vamos começar modificando nossa função novaLinha()
. Precisamos remover o document.write("<br>")
e para criar o elemento vamos utilizar a função document.createElement()
. A função createElement()
cria um elemento HTML com o texto que for passado em seu parâmetro, que no caso da nossa função novaLinha()
será "br"
, e como resultados teremos um elemento que vamos atribuir para uma variável chamada br
. Não é necessário adicionar os sinais "<>"
, apenas o texto "br"
dentro das aspas:
var novaLinha = function() {
var br = document.createElement("br");
}
Temos o elemento criado e guardado dentro da variável, mas ainda precisamos adicioná-lo ao nosso documento e para isso precisamos apenas utilizar a função appendChild()
:
var novaLinha = function() {
var br = document.createElement("br");
document.body.appendChild(br);
}
Assim teremos o mesmo resultado que o document.write("<br>")
de antes.
Para a função desenharTabuleiro()
iremos fazer a mesma coisa, mas já pensando na interação do jogador com o tabuleiro vamos criar botões para as posições do tabuleiro. Então ao invés de "br"
vamos criar um "button"
da mesma forma que antes:
var desenharTabuleiro = function(){
for(var linha = 0; linha < 3; linha++) {
for(var coluna = 0; coluna < 3; coluna++) {
var button = document.createElement("button");
document.body.appendChild(button);
}
novaLinha();
}
}
Se atualizarmos a nossa página vamos ver que o tabuleiro foi desenhado com os botões, mas que não existe nenhum texto dentro deles. É até dificl de ver que são botões. haha
Para adicionar texto aos botões precisamos modificar a propriedade button.textContent
. Lembra do objeto VAZIO
que criamos la atrás com a propriedade VAZIO.simbolo
? Ele foi atribuido para todos os espaços do tabuleiro, então todos os espaços do tabuleiro possuem a propriedade simbolo
. Então vamos atribuir o simbolo
presente em cada espaço do tabuleiro para o button.textContent
:
var desenharTabuleiro = function(){
for(var linha = 0; linha < 3; linha++) {
for(var coluna = 0; coluna < 3; coluna++) {
var button = document.createElement("button");
//Aqui atribuimos apenas o simbolo
button.textContent = tabuleiro[linha][coluna].simbolo;
document.body.appendChild(button);
}
novaLinha();
}
}
Já temos um resultado muito melhor.
Agora para organizar o código vamos extrair toda a criação do botão para uma nova função chamada criarBotaoTabuleiro
passando a linha
e coluna
dos for
como parâmetro.
var criarBotaoTabuleiro = function(linha, coluna){
var button = document.createElement("button");
button.textContent = tabuleiro[linha][coluna].simbolo;
document.body.appendChild(button);
}
var desenharTabuleiro = function(){
for(var linha = 0; linha < 3; linha++) {
for(var coluna = 0; coluna < 3; coluna++) {
criarBotaoTabuleiro(linha, coluna);
}
novaLinha();
}
}
Extrair trechos de código que possuem uma responsabilidade para funções com nomes intuitivos facilita a manutenção do código. No futuro caso você queira modificar a forma como criamos os botões do tabuleiro fica fácil encontrar onde eles são criados.
A extração de métodos incentiva boas práticas, enfatizando métodos discretos e reutilizaveis, incentiva o código autodescritivo onde os nomes dos métodos são descritivos e dispensam comentários, incentiva a criação de métodos com uma unica responsabilidade e reduz a duplicação de código. Fonte: Microsoft Developer Network
Fazendo jogadas
Agora podemos criar uma forma de fazer as jogadas ao clicar em cada um dos botões que colocamos na tela, mas para fazermos uma jogada precisamos dos jogadores e uma forma de saber quem é o jogador atual.
Para os jogadores vamos criar mais dois objetos literais parecidos com o nosso objeto VAZIO
que criamos antes:
var jogadorX = {
simbolo: 'X'
}
var jogadorO = {
simbolo: 'O'
}
E para representar o jogador atual vamos criar mais uma variável chamada jogadorAtual
e atribuir o primeiro jogador, que nesse caso será o jogadorX
:
var jogadorAtual = jogadorX;
Então agora que temos os jogadores e sabemos qual jogador fará a jogada podemos criar a nossa função para fazer as jogadas.
Para fazer as jogadas vamos criar uma função chamada fazerJogada()
passando a posição da matriz bidimensional, e por isso iremos passar a linha
e coluna
como parâmetro para essa função:
var fazerJogada = function(linha, coluna) {
}
E para fazer a jogada vamos apenas atribuir o conteúdo da nossa variável jogadorAtual, que contém o objeto que representa o jogador, para a posição do tabuleiro[linha][coluna]
, onde a linha
e a coluna
são os parâmetros da função:
var fazerJogada = function (linha, coluna) {
tabuleiro[linha][coluna] = jogadorAtual;
}
Agora temos a função que atribui o jogadorAtual
para a posição do tabuleiro, mas não estamos verificando se a posição que foi escolhida já está preenchida por outro jogador. Uma das regras do jogo da velha é que os jogadores só podem fazer jogadas nas posições vazias do tabuleiro.
Para resolver isso é necessário um if
, uma condicional, para verificar se a posição do tabuleiro escolhida está vazia antes de efetuar a jogada e caso não esteja, else
, podemos alertar os jogadores:
var fazerJogada = function (linha, coluna) {
if (tabuleiro[linha][coluna] === VAZIO) {
tabuleiro[linha][coluna] = jogadorAtual;
} else {
alert("Jogada Inválida");
}
}
Mas também precisamos alterar o jogadorAtual
depois que o jogador anterior fizer uma jogada válida. O jogadorO
também precisa jogar. Quando ele fizermos uma jogada válida temos que alterar o objeto de jogadorAtual
para o símbolo do próximo jogador. Vamos utilizar mais um if
para verificar qual o jogadorAtual
e atribuir o objeto oposto para ele:
var fazerJogada = function (linha, coluna) {
if (tabuleiro[linha][coluna] === VAZIO) {
tabuleiro[linha][coluna] = jogadorAtual;
if(jogadorAtual === jogadorX){
jogadorAtual = jogadorO;
} else {
jogadorAtual = jogadorX;
}
} else {
alert("Jogada Inválida");
}
}
Por questão de organização vamos extrair esse if
que criamos para uma nova função chamada proximoJogador
:
var proximoJogador = function() {
if(jogadorAtual === jogadorX){
jogadorAtual = jogadorO;
} else {
jogadorAtual = jogadorX;
}
}
var fazerJogada = function (linha, coluna) {
if (tabuleiro[linha][coluna] === VAZIO) {
tabuleiro[linha][coluna] = jogadorAtual;
proximoJogador();
} else {
alert("Jogada Inválida");
}
}
Mas tem mais uma coisinha que nossa função fazerJogada(linha,coluna)
pode fazer que irá automatizar o nosso. Podemos chamar a função desenharTabuleiro()
dentro dela para que sempre quando fizermos uma jogada válida desenhar o tabuleiro na tela:
var fazerJogada = function (linha, coluna) {
if (tabuleiro[linha][coluna] === VAZIO) {
tabuleiro[linha][coluna] = jogadorAtual;
desenharTabuleiro();
proximoJogador();
} else {
alert("Jogada Inválida");
}
}
A função fazerJogada(linha, coluna)
é quem controla a mudança de estado do nosso jogo. Agora precisamos colocar ela para funcionar ao clicar nos botões. Para cada um dos botões a função deve ser chamada com os parâmetros da linha
e da coluna
referente a posição do botão clicado. Para isso vamos até a função criarBotaoTabuleiro(linha, coluna)
e vamos atribuir uma função para a propriedade button.onclick
, dessa forma:
var criaBotaoTabuleiro = function(linha, coluna){
var button = document.createElement("button");
button.textContent = tabuleiro[linha][coluna].simbolo;
button.onclick = function() {
}
document.body.appendChild(button);
}
E dentro dessa função só precisamos chamar a função fazerJogada(linha, coluna)
:
button.onclick = function () {
fazerJogada(linha,coluna);
}
Sempre que clicarmos em um dos botões a função que atribuímos ao button.onclick
será chamada e consequentemente a nossa função fazerJogada(linha, coluna)
.
O
onclick
é um evento dos elementos criados no HTML que quando clicado aciona a função que foi atribuído para ele. Para saber mais: Mozzila Developer Network - GlobalEventHandlers.onclick
Mas ainda temos um pequeno probleminha. BUG. Sempre que clicamos em um dos botões a função desenharTabuleiro()
cria novos botões na tela sem apagar os antigos e eles vão se acumulando.
Para resolver isso vamos apenas excluir todo o conteúdo de document.body.innerHTML
atribuindo ""
(espaço vazio) na primeira linha da função desenharTabuleiro()
:
var desenharTabuleiro = function(){
document.body.innerHTML = "";
for(var linha = 0; linha < 3; linha++) {
for(var coluna = 0; coluna < 3; coluna++) {
criaBotaoTabuleiro(linha, coluna);
}
novaLinha();
}
}
E para manter a organização do nosso código vamos extrair esse trecho para uma função chamada limpaTela
:
var limparTela = function () {
document.body.innerHTML = "";
}
var desenharTabuleiro = function(){
limparTela();
for(var linha = 0; linha < 3; linha++) {
for(var coluna = 0; coluna < 3; coluna++) {
criaBotaoTabuleiro(linha, coluna);
}
novaLinha();
}
}
Conclusão
O nosso jogo da velha está bem melhor agora. Mas ainda falta adicionar uma forma de verificar quem venceu o jogo ou se empatou, mas isso vamos deixar para a próxima parte.
Nesta segunda parte do nosso jogo da velha nós aprendemos um pouco sobre como criar objetos literais no Javascript, como utilizar a API do Javascript para adicionar elementos na página e como adicionar evento de click
para esses elementos pela propriedade onclick
.
Gostou dessa segunda parte? Deixe sua sugestão nos comentários e se ficou interessado em aprender mais, dá uma olhada nos cursos de Lógica de Programação e Java e Orientação a Objetos aqui na Triadworks!
You might also be interested in these articles...
Desenvolvedor na TriadWorks - Email