Covil Do Dev

Jogo da velha em Python

Aprenda a criar um jogo da velha simples em Python. Aplique conceitos do Python estruturando e construindo a lógica do jogo.

Lindomar Rodrigues

Atualizado

Construiremos um jogo da velha para dois jogadores, que será jogado pela linha de comando.

Inicialmente, construiremos um tabuleiro vazio e depois receberemos e interpretaremos informações das entradas dos jogadores.

Após isso verificaremos se a entrada é possível e não fere as regras do jogo, como marcar um local já preenchido, por exemplo.

Dado a entrada válida, verificaremos a condição de vitória e declararemos o jogador vencedor, ou se todo o tabuleiro for preenchido e ninguém ganhar, declararemos o resultado como “Empate”, ou como chamamos na minha região: “Velha”.

ad

Conhecendo o jogo da velha

O jogo da velha é uma “brincadeira” milenar, também conhecido por jogo do galo ou tic-tac-toe.

Alguns historiadores de jogos(sim, isso existe) dizem que existem registros de tabuleiros 3 × 3 do jogo esculpidos em pedra ainda no Antigo Egito.

A versão mais aceita é que o jogo adquiriu esse nome quando era jogado por senhoras idosas nas cortes europeias que já não tinham a visão tão boa para bordar, porém, isto não é confirmado.

Para mais detalhes e mais versões do jogo veja este artigo.

Regras

  1. O jogo da velha é jogado em um tabuleiro 3 × 3 por dois jogadores, que alternadamente colocam as marcas X e 0 em um dos nove espaços da grade. No exemplo a seguir, o primeiro jogador (X) ganha o jogo em sete etapas:
Jogo do Tic-tac-toe, vencido por X
  1. Não existe uma regra universalmente aceita sobre quem joga primeiro, mas neste artigo a convenção de que X joga primeiro é utilizada.

  2. Os jogadores se revezam colocando suas marcas em quadrados vazios.

  3. O jogador que conseguir colocar três de suas marcas em uma linha horizontal, vertical ou diagonal é o vencedor.

  4. Quando todos os 9 quadrados estiverem marcados, o jogo termina. Se nenhum jogador tiver 3 marcas consecutivas, o jogo termina empatado.

Construindo o jogo

Construiremos o jogo utilizando Python, portanto é necessário instala-lo na sua máquina.

Este é um projeto simples, porém você necessita conhecer alguns conceitos básicos da linguagem:

Inicialmente criaremos uma classe chamada “JogoDaVelha”, inicialmente vazia.

class JogoDaVela:

  def _init__():
    ...

Tabuleiro

Para representar o tabuleiro utilizaremos um dicionário.

Primeiro, veremos como utilizaremos um dicionário para criar nosso tabuleiro de jogo.

Um dicionário é um tipo de dado primitivo em Python que armazena dados no formato “chave: valor”.

Para representar o tabuleiro criaremos um dicionário com 9 chaves, e cada chave representará um bloco no tabuleiro e seu valor correspondente representará a jogada feita por um jogador.

O tabuleiro é numerado como o teclado numérico do teclado.

O tabuleiro é numerado como o teclado numérico do teclado.

Criaremos um método para exibir o tabuleiro.

class JogoDaVela:
  tabuleiro =  {'7': ' ' , '8': ' ' , '9': ' ',
                '4': ' ' , '5': ' ' , '6': ' ',
                '1': ' ' , '2': ' ' , '3': ' '}

  def _init__():
    ...

  def exibirTabuleiro(self):
    print("┌───┬───┬───┐")
    print(f"│ {self.tabuleiro['7']}{self.tabuleiro['8']}{self.tabuleiro['9']} │")
    print("├───┼───┼───┤")
    print(f"│ {self.tabuleiro['4']}{self.tabuleiro['5']}{self.tabuleiro['6']} │")
    print("├───┼───┼───┤")
    print(f"│ {self.tabuleiro['1']}{self.tabuleiro['2']}{self.tabuleiro['3']} │")
    print("└───┴───┴───┘")

Instanciaremos a classe JogoDaVela na variável jogo, depois exibiremos o tabuleiro apenas para verificar se tudo está como desejado.

jogo = JogoDaVela()

jogo.exibirTabuleiro()

A saída será como isto:

┌───┬───┬───┐
│   │   │   │
├───┼───┼───┤
│   │   │   │
├───┼───┼───┤
│   │   │   │
└───┴───┴───┘

Verificando se a jogada é válida

Definiremos uma variável para o jogador responsável pelo próximo turno.

Também adicionaremos um parâmetro na função __init__ para definir o jogador inicial, que por padrão será o X.

class JogoDaVela:
  ...

  turno = None

  def __init__(self, jogador_inicial="X"):
    self.turno = jogador_inicial

  ...

Criaremos um método para verificar se a jogada é válida.

class JogoDaVela:
  ...
  
  def verificarJogada(self, jogada):
    if jogada in self.tabuleiro.keys():
      if self.tabuleiro[jogada] == " ":
        return True
    return False
   
  ...

Na primeira condicional é verificado se a jogada é uma das nove posições possíveis no tabuleiro e na segunda verifica se a posição ainda está vazia.

Você pode estar se perguntando: por que utilizar duas condicionais e não apenas uma com o operador and como no exemplo abaixo?

class JogoDaVela:
  ...
  
  def verificarJogada(self, jogada):
    if jogada in self.tabuleiro.keys() and self.tabuleiro[jogada] == " ":
      return True
    return False
  
  ...

A resposta é simples, se fizer dessa maneira, caso a chave jogada não esteja no dicionário tabuleiro um erro ocorrerá.

Verificando o resultado do jogo

Agora criaremos um método que irá verificar o estado do tabuleiro, se já temos um vencedor ou se podemos declarar um empate.

Para isto, basta verificar se algum jogador preencheu 3 casas consecutivas.

class JogoDaVela:
  ...

  def verificarTabuleiro(self):
      # Verificações das 3 verticais
      if self.tabuleiro['7'] == self.tabuleiro['4'] == self.tabuleiro['1'] != ' ':
          return self.tabuleiro['7']
      elif self.tabuleiro['8'] == self.tabuleiro['5'] == self.tabuleiro['2'] != ' ':
          return self.tabuleiro['8']
      elif self.tabuleiro['9'] == self.tabuleiro['6'] == self.tabuleiro['3'] != ' ':
          return self.tabuleiro['9']


      # Verificações das 3 horizontais
      elif self.tabuleiro['7'] == self.tabuleiro['8'] == self.tabuleiro['9'] != ' ':
          return self.tabuleiro['7']
      elif self.tabuleiro['4'] == self.tabuleiro['5'] == self.tabuleiro['6'] != ' ':
          return self.tabuleiro['8']
      elif self.tabuleiro['1'] == self.tabuleiro['2'] == self.tabuleiro['3'] != ' ':
          return self.tabuleiro['1']

      # Verificações das 2 diagonais
      elif self.tabuleiro['7'] == self.tabuleiro['5'] == self.tabuleiro['3'] != ' ':
          return self.tabuleiro['7']
      elif self.tabuleiro['1'] == self.tabuleiro['5'] == self.tabuleiro['9'] != ' ':
          return self.tabuleiro['1']

      # Verificando empate
      if [*self.tabuleiro.values()].count(' ') == 0:
          return "empate"
      else:
          return [*self.tabuleiro.values()].count(' ')
  
  ...

Caso algum jogador tenha preenchido 3 casas consecutivas é retornado o vencedor.

Caso a condição acima não ocorra, e caso todas as casas já estejam ocupadas(a quantidade de casas vazias seja igual a zero), é retornado empate.

Se nem uma das duas condições forem verdadeiras, é retornado a quantidade de casas que ainda faltam serem preenchidas.

Montando o jogo

Agora com os métodos essenciais já definidos, criaremos o método jogar que será responsável pela comunicação com os jogadores, lendo as jogadas e fazendo as chamadas para os métodos já definidos.

class JogoDaVela:
  ...
  
  def jogar(self):
    
    while True:
      self.exibirTabuleiro()

      print(f"Turno do {self.turno}, qual sua jogada?")

      # Enquanto o jogador não fizer uma jogada válida
      while True:
        jogada = input("Jogada: ")

        if self.verificarJogada(jogada): # Se a jogada for válida...
          break # Encerra o loop
        else:
          print(f"jogado do {self.turno} inválida, jogue novamente.")
      
      self.tabuleiro[jogada] = self.turno

      estado = self.verificarTabuleiro()

      if estado == "X":
        print("X é o vencedor!!!")
        break

      elif estado == "O":
        print("O é o vencedor!!!")
        break

      if estado == "empate":
        print("EMPATE!!!")
        break

      # Troca o jogador do próximo turno
      self.turno = "X" if self.turno == "O" else "O"
      
  ...

Em cada iteração é exibido o tabuleiro, após isso ocorre a leitura da jogada, temos a então a verificação do estado do tabuleiro, caso o jogo ainda não esteja finalizado é iniciado um novo turno alternando o jogador responsável pela jogada.

Conclusão

Para construir esse jogo é necessário apenas um conhecimento básico de Python.

Caso tenha dificuldade em entender o tabuleiro recomendo esse artigo sobre dicionários.

Caso tenha dificuldade em entender o loop de execução do jogo, recomendo esse artigo sobre iteração(for e while).

Caso queira ver outras formas de exibir informações com o usuário, recomendo esse artigo sobre a função print.

Abaixo temos o código completo caso não tenha conseguido acompanhar todas as etapas durante o artigo.

class JogoDaVela:
    tabuleiro = {'7': ' ', '8': ' ', '9': ' ', '4': ' ', '5': ' ', '6': ' ', '1': ' ', '2': ' ', '3': ' '}
    turno = None

    def __init__(self, jogador_inicial="X"):
        self.turno = jogador_inicial

    def exibir_tabuleiro(self):
        print("┌───┬───┬───┐")
        print(f"│ {self.tabuleiro['7']}{self.tabuleiro['8']}{self.tabuleiro['9']} │")
        print("├───┼───┼───┤")
        print(f"│ {self.tabuleiro['4']}{self.tabuleiro['5']}{self.tabuleiro['6']} │")
        print("├───┼───┼───┤")
        print(f"│ {self.tabuleiro['1']}{self.tabuleiro['2']}{self.tabuleiro['3']} │")
        print("└───┴───┴───┘")

    def verificar_jogada(self, jogada):
        if jogada in self.tabuleiro.keys():
            if self.tabuleiro[jogada] == " ":
                return True
        return False

    def verificar_tabuleiro(self):
        # Verificações das 3 verticais
        if self.tabuleiro['7'] == self.tabuleiro['4'] == self.tabuleiro['1'] != ' ':
            return self.tabuleiro['7']
        elif self.tabuleiro['8'] == self.tabuleiro['5'] == self.tabuleiro['2'] != ' ':
            return self.tabuleiro['8']
        elif self.tabuleiro['9'] == self.tabuleiro['6'] == self.tabuleiro['3'] != ' ':
            return self.tabuleiro['9']


        # Verificações das 3 horizontais
        elif self.tabuleiro['7'] == self.tabuleiro['8'] == self.tabuleiro['9'] != ' ':
            return self.tabuleiro['7']
        elif self.tabuleiro['4'] == self.tabuleiro['5'] == self.tabuleiro['6'] != ' ':
            return self.tabuleiro['8']
        elif self.tabuleiro['1'] == self.tabuleiro['2'] == self.tabuleiro['3'] != ' ':
            return self.tabuleiro['1']

        # Verificações das 2 diagonais
        elif self.tabuleiro['7'] == self.tabuleiro['5'] == self.tabuleiro['3'] != ' ':
            return self.tabuleiro['7']
        elif self.tabuleiro['1'] == self.tabuleiro['5'] == self.tabuleiro['9'] != ' ':
            return self.tabuleiro['1']

        # Verificando empate
        if [*self.tabuleiro.values()].count(' ') == 0:
            return "empate"
        else:
            return [*self.tabuleiro.values()].count(' ')

    def jogar(self):

        while True:
            self.exibir_tabuleiro()

            print(f"Turno do {self.turno}, qual sua jogada?")

            # Enquanto o jogador não fizer uma jogada válida
            while True:
                jogada = input("Jogada: ")

                if self.verificar_jogada(jogada):  # Se a jogada for válida...
                    break  # Encerra o loop
                else:
                    print(f"jogado do {self.turno} inválida, jogue novamente.")

            self.tabuleiro[jogada] = self.turno

            estado = self.verificar_tabuleiro()

            if estado == "X":
                print("X é o vencedor!!!")
                break

            elif estado == "O":
                print("O é o vencedor!!!")
                break

            if estado == "empate":
                print("EMPATE!!!")
                break

            # Troca o jogador do próximo turno
            self.turno = "X" if self.turno == "O" else "O"

        self.exibir_tabuleiro()


jogo = JogoDaVela()

jogo.jogar()

Obrigado por visitar o blog e por ler esse artigo, se tive qualquer dúvida, ideia ou sugestão, não hesite em entrar em contato pelo meu e-mail: lindomar@covildodev.com.br