Como fazer um Jogo da Velha em Javascript, HTML e CSS

Se há algo que sempre gostei de fazer ao aprender uma linguagem de programação nova é escrever algum joguinho para testar os meus conhecimentos. Cada vez temos mais provas de que a gamificação é uma ótima ferramenta de aprendizagem!

O Jogo da Velha é um clássico que desafia os seus conhecimentos de uma linguagem sem fazer você quebrar demais a cabeça. Por isso, hoje vou te ensinar como fazer um jogo da velha em Javascript, usando também HTML e CSS.

Como fazer um jogo da velha em javascript

A ferramenta que usei para fazer este programa foi o Gedit, um editor de texto para Linux, mas para criar seu jogo da velha em javascript você pode usar qualquer outro editor de texto, como o Sublime, Notepad++ ou até o bom e velho Bloco de Notas.

Criando pastas e estruturando diretórios

Para começar, crie uma pasta chamada “Jogo da Velha”. 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

Código HTML e CSS para o Jogo da Velha

Para conseguir focar no Javascript, vou deixar os códigos de HTML e CSS disponíveis sem entrar a fundo neles.

Caso você queria aprender mais sobre isso, confira o nosso Curso de HTML e CSS.

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.

<htmllang="pt-br"><head><title>Jogo da Velhatitle><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"><s```cript>
    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, crie um arquivo de texto vazio e salve-o como “velha.js” dentro da pasta scripts. Depois de fazer isso, a sua árvore de diretórios deve estar mais ou menos assim:

.

└── 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.

Lógica Javascript para o Jogo da Velha

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. Por exemplo: de quem é a vez, se alguém venceu a partida, 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 3 coisas: 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.

Adicionando interatividade ao Jogo da Velha Javascript

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:

  • Preenche 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.

Definindo funções sortearJogador(), trocarJogador() e vitoria()

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. O conceito aqui é, basicamente, aquele de 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, sendo que 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.

O jogo está pronto, e agora?

Ok, se tudo estiver certo, você deve ter um bom e velho jogo da velha rodando no seu navegador. O próximo passo, como diz o lema da Platzi, é Nunca Parar de Aprender!

Confira os cursos da programação que temos na plataforma. Eu acho que você pode se interessar especialmente por esses aqui:

Pode ver o código completo do Jogo da Velha em Javascript na minha página do Github.

Postagens Relacionadas

Hoje em dia não é preciso querer entrar na carreira de programação para procurar saber como aprender HTML e CSS. Afinal, com a transformação
Seja você um empreendedor que está tentando promover seu negócio, um iniciante em Marketing que quer aprender de tudo um pouco ou um profissional
Não existe uma resposta exata para quem se pergunta quanto tempo demora para aprender inglês, mas conhecer um pouco sobre como nosso cérebro funciona
Apesar de terem sido subestimadas por muito tempo, hoje as competências comportamentais têm conquistado cada vez mais a atenção de recrutadores e empresas, que