Agora já podemos criar nosso jogo. Como detalhei a teoria no tópico anterior, não vou me alongar muito nos detalhes teóricos da implementação. Caso gere alguma dúvida podem perguntar, e a parte teórica mesmo ainda iremos ver:
Primeiro, irei criar um dicionário com as posições possíveis de jogada em nosso tabuleiro:
posicoes = {
'pos1': 1,
'pos2': 2,
'pos3': 3,
'pos4': 4,
'pos5': 5,
'pos6': 6,
'pos7': 7,
'pos8': 8,
'pos9': 9
}
Em seguida, irei criar uma função que printa um tabuleiro em nossa tela, recebendo vários prints em sequência. Essa função receberá como argumento o nosso dicionário criado para conseguir desenhar no tabuleiro as posições disponíveis para jogar. Em Python, é prática comum declarar as funções no início do programa. O programa só lerá a função quando ela for chamada, por isso, enquanto o programa não chama a função ela fica lá guardadinha pra ser usada mais tarde:
def mostra_tabuleiro(**posicoes):
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos1'], posicoes['pos2'], posicoes['pos3']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos4'], posicoes['pos5'], posicoes['pos6']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos7'], posicoes['pos8'], posicoes['pos9']))
print(' | | ')
posicoes = {
'pos1': 1,
'pos2': 2,
'pos3': 3,
'pos4': 4,
'pos5': 5,
'pos6': 6,
'pos7': 7,
'pos8': 8,
'pos9': 9
}
Caso eu chame nossa função:
>>> mostra_tabuleiro()
| |
1 | 2 | 3
| |
-------|-------|-------
| |
4 | 5 | 6
| |
-------|-------|-------
| |
7 | 8 | 9
| |
Pronto, temos um tabuleiro de jogo da velha. Agora preciso criar a lógica para pedir jogadas do usuário.
Irei criar uma função para pedir as jogadas do usuário e uma lista de possíveis jogadas disponíveis. Sempre que um número for selecionado, esse número será excluído dessa lista. Dessa forma eu barro a possibilidade de jogadas repetidas, então nossa função receberá como argumento a lista de palpites possíveis e caso o palpite já tenha sido dado, o programa pedirá novamente uma jogada para o usuário:
def pede_jogada(lista_palpites):
print('-=-'*15)
while True:
jogada = input('Digite uma posição no tabuleiro para jogar: ')
if jogada.isdigit():
jogada = int(jogada)
if jogada in lista_palpites:
break
else:
print('Você digitou um número já pedido, tente novamente')
else:
print('Você não digitou um número válido, tente novamente')
print('-=-'*15)
return jogada
lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Explicando cada parte do código:
O primeiro print é somente para criar um estilo textual agradável para a jogada do usuário.
Em seguida temos um laço "while" que recebe a lógica da função. Primeiro, pedimos uma jogada e atribuímos o resultado à variável "jogada". Lembrando que por padrão qualquer input do usuário vem como string. Então eu uso a função nativa de strings do Python "isdigit" para averiguar se o que o usuário digitou foi um número ou um texto. Exemplos da função isdigit:
In [26]: '15'.isdigit()
Out[26]: True
In [27]: 'ola'.isdigit()
Out[27]: False
Caso o usuário tenha digitado algo errado, algo que não seja um número inteiro, o programa solicitará novamente o input correto do usuário. Caso o input seja realmente um número, transformamos a string numérica em um inteiro usando o comando int(jogada).
Em seguida eu averiguo se a jogada é válida, ou seja, se o número digitado está dentro da lista de possíveis números da nossa lista_palpites. Caso a jogada seja válida, interrompo o laço while com um break e o código da função segue em frente. Caso não, o programa pede novamente um número válido para o usuário. Por fim a função me retorna a jogada do usuário.
Até o momento temos:
def mostra_tabuleiro(**posicoes):
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos1'], posicoes['pos2'], posicoes['pos3']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos4'], posicoes['pos5'], posicoes['pos6']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos7'], posicoes['pos8'], posicoes['pos9']))
print(' | | ')
def pede_jogada(lista_palpites):
print('-=-'*15)
while True:
jogada = input('Digite uma posição no tabuleiro para jogar: ')
if jogada.isdigit():
jogada = int(jogada)
if jogada in lista_palpites:
break
else:
print('Você digitou um número já pedido, tente novamente')
else:
print('Você não digitou um número, tente novamente')
print('-=-'*15)
return jogada
posicoes = {
'pos1': 1,
'pos2': 2,
'pos3': 3,
'pos4': 4,
'pos5': 5,
'pos6': 6,
'pos7': 7,
'pos8': 8,
'pos9': 9
}
lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
mostra_tabuleiro(**posicoes)
jogada = pede_jogada(lista_palpites)
Sendo a variável "jogada" o retorno da nossa função "pede_jogada".
Caso rodemos esse código, o terminal retorna:
| |
1 | 2 | 3
| |
-------|-------|-------
| |
4 | 5 | 6
| |
-------|-------|-------
| |
7 | 8 | 9
| |
-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-
Digite uma posição no tabuleiro para jogar: 3
-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-
Agora precisamos eliminar da nossa lista de palpites o número palpitado, que no caso do exemplo acima foi o número 3. Com um comando simples eu posso fazer isso:
# Se minha lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# E se eu palpitei o número 3, eu preciso eliminar o número 3
# Para eliminar o número, irei acessá-lo pelo índice, que no caso da lista
# é o índice 2. Logicamente, qualquer índice da lista é seu número - 1.
# Então posso eliminar o 3 acessando o índice 2, ou 3 - 1 = 2:
# Portanto, a lógica para eliminar números repetidos é:
lista_palpites[jogada - 1] = 'X'
# Dessa forma, nossa lista ficará assim:
lista_palpites = [1, 2, 'X', 4, 5, 6, 7, 8, 9]
Então, incluiremos esse comando em nosso programa:
(...)
lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
mostra_tabuleiro(**posicoes)
jogada = pede_jogada(lista_palpites)
lista_palpites[jogada - 1] = 'X'
Agora eu preciso varrer meu tabuleiro e substituir os números por strings 'X' e 'O'. Irei criar uma função exclusivamente para isso. Mas o jogo da velha é jogado por dois jogadores, então preciso incluir uma lógica para que as jogadas sejam alternadas, e quando um jogador jogar a string seja 'X' e quando o outro jogar a string seja 'O'.
Uma das formas que pensei foi criar um contador de jogada, que a cada jogada válida é acrescido de um número. Então, caso a jogada seja um número ímpar, o tabuleiro é escrito com um 'O' e caso seja uma jogada par o tabuleiro é escrito com um 'X'. Portanto, irei criar um contador de jogadas e passá-lo como argumento da função que escreve em nosso tabuleiro. Essa função receberá a jogada, o número de jogadas até agora e o dicionário das posições, já que é esse dicionário que desenha os números em nosso tabuleiro, então eu preciso trocar seus números por strings 'X' e 'O':
def averigua_jogada(jogada, numero_jogadas, **posicoes):
for key, value in posicoes.items():
if jogada == value:
if numero_jogadas % 2 == 0:
posicoes[key] = 'X'
else:
posicoes[key] = 'O'
return posicoes
contador_jogadas = 0
Explicando, eu basicamente receberei a jogada, o contador de jogadas (numero_jogadas) e o dicionário das posições válidas. Então irei varrer esse dicionário procurando a posição em que a jogada seja igual ao número selecionado, então nesse caso irei trocar o número por um 'X' caso seja uma jogada par ou por um 'O' caso seja uma jogada ímpar.
Nosso código até agora está assim:
def mostra_tabuleiro(**posicoes):
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos1'], posicoes['pos2'], posicoes['pos3']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos4'], posicoes['pos5'], posicoes['pos6']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos7'], posicoes['pos8'], posicoes['pos9']))
print(' | | ')
def pede_jogada(lista_palpites):
print('-=-'*15)
while True:
jogada = input('Digite uma posição no tabuleiro para jogar: ')
if jogada.isdigit():
jogada = int(jogada)
if jogada in lista_palpites:
break
else:
print('Você digitou um número já pedido, tente novamente')
else:
print('Você não digitou um número, tente novamente')
print('-=-'*15)
return jogada
def averigua_jogada(jogada, numero_jogadas, **posicoes):
for key, value in posicoes.items():
if jogada == value:
if numero_jogadas % 2 == 0:
posicoes[key] = 'X'
else:
posicoes[key] = 'O'
return posicoes
posicoes = {
'pos1': 1,
'pos2': 2,
'pos3': 3,
'pos4': 4,
'pos5': 5,
'pos6': 6,
'pos7': 7,
'pos8': 8,
'pos9': 9
}
lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
contador_jogadas = 0
mostra_tabuleiro(**posicoes)
jogada = pede_jogada(lista_palpites)
lista_palpites[jogada - 1] = 'X'
posicoes = averigua_jogada(jogada, contador_jogadas, **posicoes)
Até o momento ele printa um tabuleiro, pede uma jogada, vê se a jogada é válida, exclui a possibilidade de se jogar esse palpite novamente e escreve no tabuleiro. Caso desenhemos um tabuleiro depois de todos esses comandos teremos algo como isso:
| |
1 | 2 | 3
| |
-------|-------|-------
| |
4 | 5 | 6
| |
-------|-------|-------
| |
7 | 8 | 9
| |
-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-
Digite uma posição no tabuleiro para jogar: 3
-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-
| |
1 | 2 | X
| |
-------|-------|-------
| |
4 | 5 | 6
| |
-------|-------|-------
| |
7 | 8 | 9
| |
Ou seja, a lógica está funcionando. Mas até o momento só um jogador pode jogar. Preciso criar um novo laço while para fazer meu programa rodar até acharmos um vendedor, e nesse laço incluir uma ferramenta de soma das jogadas para alternar a escrita no tabuleiro. Então:
while True:
mostra_tabuleiro(**posicoes)
jogada = pede_jogada(lista_palpites)
lista_palpites[jogada - 1] = 'X'
posicoes = averigua_jogada(jogada, contador_jogadas, **posicoes)?
contador_jogadas += 1
Até o momento o programa está assim:

Ou seja, eu testei todas as possibilidades possíveis, preenchi meu tabuleiro e o jogo não terminou, continuou me pedindo jogadas. Preciso criar uma condição de parada do meu jogo. Irei criar uma função para isso. Ela deve listar todas as possibilidades de fim de jogo e retornar algo quando o jogo finalizar:
def procura_vencedor(**posicoes):
possibilidade_1 = posicoes['pos1'] == posicoes['pos4'] == posicoes['pos7']
possibilidade_2 = posicoes['pos1'] == posicoes['pos2'] == posicoes['pos3']
possibilidade_3 = posicoes['pos1'] == posicoes['pos5'] == posicoes['pos9']
possibilidade_4 = posicoes['pos2'] == posicoes['pos5'] == posicoes['pos8']
possibilidade_5 = posicoes['pos3'] == posicoes['pos6'] == posicoes['pos9']
possibilidade_6 = posicoes['pos4'] == posicoes['pos5'] == posicoes['pos6']
possibilidade_7 = posicoes['pos7'] == posicoes['pos8'] == posicoes['pos9']
possibilidade_8 = posicoes['pos3'] == posicoes['pos5'] == posicoes['pos7']
lista_possibilidades = [possibilidade_1,
possibilidade_2,
possibilidade_3,
possibilidade_4,
possibilidade_5,
possibilidade_6,
possibilidade_7,
possibilidade_8]
for possibilidade in lista_possibilidades:
if possibilidade == True:
print('Temos um vencedor! Parabéns!')
return True
Acima, listei em variáveis todas as possibilidades de fim de jogo, que é quando os valores das linhas, colunas ou diagonais são iguais. Depois criei uma lista com todas essas possibilidades e por fim na função há um laço "for" que varre todas as possibilidades. Caso qualquer uma delas seja verdadeira, ou seja, caso tenhamos uma linha preenchida com todos os valores iguais, o programa manda uma mensagem para o vencedor e a função retorna o booleano True.
Caso esteja confuso essa parte, explicando mais em miúdos:
# Enquanto ninguém vence ainda, as possibilidades são todas iguals a False e a lista_possibilidades é assim:
lista_possibilidades = [False, False, False, False, False, False, False, False]
# Caso qualquer possibilidade seja obedecida, por exemplo, a possibilidade 7:
# Na 7, o vencedor preencheu as posições 7, 8 e 9, ou seja, preencheu a terceira coluna
# Então posicoes['pos7'] é igual a posicoes['pos8'] que é igual a posicoes['pos9']
# Dessa forma, possibilidade_7 = True
Por fim, precisamos adicionar uma condição de parada para o jogo, que é quando a função procura_vencedor traz um resultado True:
if procura_vencedor(**posicoes):
mostra_tabuleiro(**posicoes)
break
Por fim, nosso código completo:
def mostra_tabuleiro(**posicoes):
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos1'], posicoes['pos2'], posicoes['pos3']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos4'], posicoes['pos5'], posicoes['pos6']))
print(' | | ')
print('-------|-------|-------')
print(' | | ')
print(' {} | {} | {} '.format(posicoes['pos7'], posicoes['pos8'], posicoes['pos9']))
print(' | | ')
def pede_jogada(lista_palpites):
print('-=-'*15)
while True:
jogada = input('Digite uma posição no tabuleiro para jogar: ')
if jogada.isdigit():
jogada = int(jogada)
if jogada in lista_palpites:
break
else:
print('Você digitou um número já pedido, tente novamente')
else:
print('Você não digitou um número válido, tente novamente')
print('-=-'*15)
return jogada
def averigua_jogada(jogada, numero_jogadas, **posicoes):
for key, value in posicoes.items():
if jogada == value:
if numero_jogadas % 2 == 0:
posicoes[key] = 'X'
else:
posicoes[key] = 'O'
return posicoes
def procura_vencedor(**posicoes):
possibilidade_1 = posicoes['pos1'] == posicoes['pos4'] == posicoes['pos7']
possibilidade_2 = posicoes['pos1'] == posicoes['pos2'] == posicoes['pos3']
possibilidade_3 = posicoes['pos1'] == posicoes['pos5'] == posicoes['pos9']
possibilidade_4 = posicoes['pos2'] == posicoes['pos5'] == posicoes['pos8']
possibilidade_5 = posicoes['pos3'] == posicoes['pos6'] == posicoes['pos9']
possibilidade_6 = posicoes['pos4'] == posicoes['pos5'] == posicoes['pos6']
possibilidade_7 = posicoes['pos7'] == posicoes['pos8'] == posicoes['pos9']
possibilidade_8 = posicoes['pos3'] == posicoes['pos5'] == posicoes['pos7']
lista_possibilidades = [possibilidade_1,
possibilidade_2,
possibilidade_3,
possibilidade_4,
possibilidade_5,
possibilidade_6,
possibilidade_7,
possibilidade_8]
for possibilidade in lista_possibilidades:
if possibilidade == True:
print('Temos um vencedor! Parabéns!')
return True
posicoes = {
'pos1': 1,
'pos2': 2,
'pos3': 3,
'pos4': 4,
'pos5': 5,
'pos6': 6,
'pos7': 7,
'pos8': 8,
'pos9': 9
}
lista_palpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]
contador_jogadas = 0
while True:
mostra_tabuleiro(**posicoes)
jogada = pede_jogada(lista_palpites)
lista_palpites[jogada - 1] = 'X'
posicoes = averigua_jogada(jogada, contador_jogadas, **posicoes)
if procura_vencedor(**posicoes):
mostra_tabuleiro(**posicoes)
break
contador_jogadas += 1
E nosso jogo rodando:

Dá pra embelezar mais nosso jogo, dá pra criar uma melhor de 3, mas a lógica é essa. Vocês até já podem brincar de jogo da velha com alguém agora haha