3

Criando o jogo da velha com JavaScript

6544Pontos

hace 2 años

Curso de Introdução ao JavaScript
Curso de Introdução ao JavaScript

Curso de Introdução ao JavaScript

Domine o JavaScript, a linguagem mais versátil e exigida de hoje. Você trabalhará em mais de 20 projetos para entender e construir com JavaScript do zero.

Se há algo que sempre gostei de fazer ao aprender uma linguagem de programação nova é escrever algum joguinho para testar os meus conhecimentos. E o Jogo da Velha é um clássico que desafia os seus conhecimentos de uma linguagem sem fazer você quebrar demais a cabeça.

A ferramenta que usei para fazer este programa foi o Gedit, um editor de texto para Linux, mas pode usar qualquer outro como o Sublime, Notepad++ ou até o bom e velho Bloco de Notas. 😃

Para começar, crie uma pasta chamada “Jogo da Velha”. E dentro desta pasta, crie outras duas, uma chamada “css” e a outra chamada “scripts”. A sua estrutura de diretórios deve ficar assim:

.
└── Jogo da Velha
├── css
└── scripts

Como o tutorial trata apenas de JavaScript, vou deixar o código HTML e CSS disponíveis sem entrar a fundo neles:

Abra o bloco de notas, ou o editor de sua preferência e salve o arquivo a seguir como “index.html” na raiz da pasta Jogo da Velha.

<!DOCTYPE html><htmllang="pt-br"><head><title>Jogo da Velha</title><metacharset="UTF-8"><linkrel="stylesheet"href="css/main.css"></head><body><h1>Jogador <spanid="jogador"></span></h1><main><div><inputtype="button"value="_"><inputtype="button"value="_"><inputtype="button"value="_"></div><div><inputtype="button"value="_"><inputtype="button"value="_"><inputtype="button"value="_"></div><div><inputtype="button"value="_"><inputtype="button"value="_"><inputtype="button"value="_"></div></main><inputtype="button"value="Reiniciar"id="reiniciar"><scriptsrc="scripts/velha.js">&lt;s```cript&gt;
    </body></html>

Em seguida, faça um novo arquivo com o código CSS a seguir chamado “main.css” e salve-o dentro da pasta “css”

body {
        background-color: #AAA;
        text-align: center;
        font-family: Verdana, Helvetica, sans-serif;
        font-size: 1.3em;
    }

    input {
        background-color: white;
        font-size: 6vw;
        width: 12vw;
        height:12vw;
        margin: 0;
        color: white;
    }

    #jogador {
        display: inline;
    }

    #reiniciar {
        margin-top: 2%;
        width: 10vw;
        height:6vw;
        font-size: 1em;
        color: black;
    }

Por último, crieumarquivodetextovazioesalve-ocomovelha.jsdentrodapastascripts. Depoisdefazerisso, asua árvoredediretóriosdeveestarmaisoumenosassim:

.
└── JogodaVelha
    ├── css
    │   └── main.css
    ├── index.html
    └── scripts
        └── velha.js

Se você abrir o arquivo index.html no seu navegador, poderá ver como está a nossa interface de usuário.

  • A Label do Jogador, o quadrado pontilhado no topo, é uma tag span com id “jogador” e será responsável por mostrar se é a vez do jogador “X” ou “O”.
  • Cada um dos quadradinhos brancos do nosso tabuleiro, a nossa “casa”, é formado por tags input de tipo botão. Ao clicar nela, será marcado X ou O, de acordo com a vez do jogador atual, indicada pelo Label do Jogador.
  • O botão reiniciar, formado pelo tag input de tipo botão, serve para limpar todas as casas e reiniciar a partida.

Agora podemos começar a escrever a nossa lógica no arquivo “velha.js” dentro da pasta scripts. No nosso código JavaScript, precisaremos referenciar esses objetos para poder interagir com eles e fazer com que reajam aos cliques ou mudanças de estado no código, vamos começar pegando estes elementos do HTML:

//Obtendo os elementos do DOM com que vamos interagir

const casas = document.getElementsByTagName('input'); //pega a lista de casas do tabuleiro do jogo
const b_reiniciar = document.getElementById('reiniciar'); //pega o botão de reiniciar
const label_jogador = document.getElementById('jogador'); //pegar o label do jogador que usaremos para mostrar qual jogador tem a vez

Tudo bastante simples até agora, não? Usamos os métodos document.getElementById para pegar o botão de reiniciar e o label do jogador, e o método getElementsByTagName para obter todos os input presentes no HTML.

Interessante notar que, entre as posições 0 e 8, temos as casas do tabuleiro e, na posição 9, teríamos o botão de reiniciar porque também se trata de um input. Usei uma variável separada para o botão de reiniciar para deixar o código um pouco mais fácil de entender, mas é bom lembrar, na hora de usar a constante casas, de usar apenas os valores entre 0 e 8 nos loops, para não pôr a lógica errada dentro do botão de reiniciar.

Agora que temos os elementos HTML, seria útil criar variáveis que indicam o estado do jogo como de quem é a vez e se alguém venceu a partidar, e, caso sim, quem é este vencedor.

//Definindo variáveis de estado do jogovar jogador = '_'; //Define o jogador atual (_ = jogador indefinido; X = jogador X, O = jogador O)var vencedor = '_'; //Define se há um vencedor ou não (_ = indefinido; X = jogador X, O = jogador O) 


    sortearJogador(); //Escolhe aleatoriamento o jogador inicial

O símbolo ‘_’ vai ser usado no programa tanto para definir que nenhum jogador tem a vez, que ninguém venceu a partida ainda ou que uma casa está vazia. Este símbolo é arbitrário e poderia ter sido qualquer outro. Ele, na verdade, é mostrado dentro das casas do tabuleiro pelo app, mas fiz uma lógica para que toda a vez que este caractere aparecesse, que a fonte ficasse da mesma cor do fundo de forma a ficar invisível.

Poderíamos ter também criado um vetor que guardasse o estado das jogadas, mas optei por ler os valores armazenados na variável casas diretamente.

E, quanto ao método sortearJogador(), vamos definir ele depois. Mas ele sorteia qual jogador vai começar a partida.

Agora que temos os elementos do DOM e as variáveis de estado, podemos adicionar interatividade ao nosso jogo. Um bom começo seria usando o método addEventListener() para agregar um método que executa quando os botões, formados pelas casas e botão de reiniciar, forem pressionados.

//Define a resposta ao evento de clique nas casas do "tabuleiro"for(var i=0;i<9;i++) {
        casas[i].addEventListener('click', (event) => {
            //se a casa estiver vazia e ninguém tiver vencido a partidaif( (event.target.value=='_') && (vencedor=='_')) {
                event.target.value=jogador; //preenche a casa com X ou Oevent.target.style.color='black'; //torna o valor da casa visível

                trocarJogador(); //função que troca a vez do jogador, a ser definida depois

                vencedor = vitoria(); //Executa a função vitoria() que defineremos depois, ela retorna o vencedor da partida, caso exista.//se o vencedor existe, imprimeif(vencedor!='_') {
                    label_jogador.innerText=`${vencedor} venceu!`;
                
                }
            }
        });
    }

O código pode parecer um pouco grande, mas é bem simples: ele adiciona uma lógica em cada botão da casa. Se a casa estiver vazio e ainda não houver um vencedor ele:

  • Preencha a posição com o jogador atual.
  • Troca a vez para a do próximo jogador.
  • Atualiza a variável vencedor caso uma condição de vitória seja alcançada.
  • Se um jogador tiver vencido, imprime uma mensagem dizendo quem ganhou.

Interessante notar que o botão da casa não reage se já estiver preenchida ou se já houver um vencedor, ou seja, o jogo já estiver ganho por alguém.

//Define a resposta ao evento de clique no botão Reiniciar
    b_reiniciar.addEventListener('click', (event) => {
        for(var i=0;i<9;i++) {
            casas[i].value='_'; //Limpa todas as casas
            casas[i].style.color='white'; //Torna o valor _ invisível
            casas[i].style.backgroundColor='white'; //Torna o fundo branco
        }

        vencedor = '_'; //Reseta o vencedor

        sortearJogador(); //Escolhe aleatoriamente qual jogador irá começar
    });

O botão de reiniciar apenas reseta os valores de todas as variáveis e elementos HTML para os seus valores iniciais e permite que seja jogada uma nova partida.

Agora tudo o que falta é definir as funções sortearJogador(), trocarJogador() e vitoria(). Vamos inserir no nosso código estes métodos:

//Usa uma função que decide aleatoriamente o jogador a fazer a primeira jogadavar sortearJogador = function() {
        if(Math.floor(Math.random() * 2)==0) {
            jogador = "O"; //define o jogador O como atual
            label_jogador.innerText="O"; //exibe na página qual é o jogador atual
            label_jogador.style.color='#F00'; //deixa o texto na cor vermelha
        }else{
            jogador = "X";//define o jogador X como atual
            label_jogador.innerText="X"; //exibe na página qual é o jogador atual
            label_jogador.style.color='#00F'; //deixa o texto na cor azul
        }
    }

    sortearJogador();

Talvez você não saiba o que a função (Math.floor(Math.random() * 2) faça, mas, basicamente, ele faz um cara ou coroa, retornando hora o número 0, hora o número 1. Dependendo de qual lado da moeda cair, ele atualiza as variáveis para colocar X ou O como jogador inicial.

//Alterna a vez entre os jogadores X e Y
    var trocarJogador = function() {
        if(jogador=='X') {
            jogador='O';
            label_jogador.innerText='O';
            label_jogador.style.color='#F00';
        
        }else{
            jogador='X';
            label_jogador.innerText='X';
            label_jogador.style.color='#00F';
        }
    }

A função trocarJogador() faz quase a mesma coisa que a sortearJogador(). A diferença é que: a primeira define o jogador atual baseado na sorte e a segunda define a vez do jogador baseado em quem fez a última jogada.

Agora só falta a função vitoria():

//Verifica se uma condição de vitória foi atingida e colore a linha da vitória
    var vitoria = function() {
        if((casas[0].value==casas[1].value) && (casas[1].value==casas[2].value) && casas[0].value!='_' ) {
            casas[0].style.backgroundColor='#0F0';
            casas[1].style.backgroundColor='#0F0';
            casas[2].style.backgroundColor='#0F0';

            return casas[0].value;

        }elseif((casas[3].value==casas[4].value) && (casas[4].value==casas[5].value) && casas[3].value!='_' ) {
            casas[3].style.backgroundColor='#0F0';
            casas[4].style.backgroundColor='#0F0';
            casas[5].style.backgroundColor='#0F0';

            return casas[3].value;

        }elseif((casas[6].value==casas[7].value) && (casas[7].value==casas[8].value) && casas[6].value!='_' ) {
            casas[6].style.backgroundColor='#0F0';
            casas[7].style.backgroundColor='#0F0';
            casas[8].style.backgroundColor='#0F0';

            return casas[6].value;

        }elseif((casas[0].value==casas[3].value) && (casas[3].value==casas[6].value) && casas[0].value!='_' ) {
            casas[0].style.backgroundColor='#0F0';
            casas[3].style.backgroundColor='#0F0';
            casas[6].style.backgroundColor='#0F0';

            return casas[0].value;

        }elseif((casas[1].value==casas[4].value) && (casas[4].value==casas[7].value) && casas[1].value!='_' ) {
            casas[1].style.backgroundColor='#0F0';
            casas[4].style.backgroundColor='#0F0';
            casas[7].style.backgroundColor='#0F0';

            return casas[1].value;

        }elseif((casas[2].value==casas[5].value) && (casas[5].value==casas[8].value) && casas[2].value!='_' ) {
            casas[2].style.backgroundColor='#0F0';
            casas[5].style.backgroundColor='#0F0';
            casas[8].style.backgroundColor='#0F0';

            return casas[2].value;
        }elseif((casas[0].value==casas[4].value) && (casas[4].value==casas[8].value) && casas[0].value!='_' ) {
            casas[0].style.backgroundColor='#0F0';
            casas[4].style.backgroundColor='#0F0';
            casas[8].style.backgroundColor='#0F0';

            return casas[0].value;

        }elseif((casas[2].value==casas[4].value) && (casas[4].value==casas[6].value) && casas[2].value!='_' ) {
            casas[2].style.backgroundColor='#0F0';
            casas[4].style.backgroundColor='#0F0';
            casas[6].style.backgroundColor='#0F0';

            return casas[2].value;
        }

        return'_';
    }

É uma função bem grande, mas se você notar, ela faz a mesma coisa várias vezes. Ela vai checando as diferentes linhas: as horizontais, as verticais e as diagonais uma por uma. Quando é encontrada uma combinação em que todos os elementos sejam igual e não estejam vazios, o fundo das casas que formam a linha são coloridas de verde-claro e é retornado o jogador que preencheu aquela linha, ou seja, o nosso vencedor. Se nenhuma linha satisfizer essas condições, é retornado ‘_’, o nosso jogador indefinido.

Ok, se tudo estiver certo, você deve ter um bom e velho jogo da velha rodando no seu navegador. Pode ver o código completo na minha página do Github. Também pode acessar o jogo online clicando aqui!

Curso de Introdução ao JavaScript
Curso de Introdução ao JavaScript

Curso de Introdução ao JavaScript

Domine o JavaScript, a linguagem mais versátil e exigida de hoje. Você trabalhará em mais de 20 projetos para entender e construir com JavaScript do zero.
Rodrigo Davy
Rodrigo Davy
RodrigoDavy

6544Pontos

hace 2 años

Todas as suas entradas
Escreva o seu comentário
+ 2
1

E como posso colocar o código de que ninguém venceu? Eu to me batendo faz umas horas, e ainda não achei a resposta.