Play again, not "clean" board - Old Python game

Asked

Viewed 398 times

0

I have a problem with this code, it is an old game for college, it is working normal, but in the part I put to play again, when user type yes, it does not Zera the board, and gets the markings of the previous match. How do I get him to clear the markers, reset the board?

print('Bem Vindo ao Jogo da Velha! Vamos começar!')

print('-=-'*15)


def tabuleiro(**posicao):


    print('  {}  |  {}  |  {}  '.format(posicao['pos1'], posicao['pos2'], posicao['pos3']))
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(posicao['pos4'], posicao['pos5'], posicao['pos6']))
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(posicao['pos7'], posicao['pos8'], posicao['pos9']))


contar_jogadas = 0
def pedir_jogada(lista_totalpalpites):

    print('-=-'*15)
    while True:
        jogada = input('Digite uma posição no tabuleiro para jogar: ')

        if jogada.isdigit():
            jogada = int(jogada)
            if jogada in lista_totalpalpites:
                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 verifica_jogada(jogada, numero_jogadas, **posicao): 

    for key, value in posicao.items():
        if jogada == value:
            if numero_jogadas % 2 == 0:
                    posicao[key] = 'X'
            else:
                    posicao[key] = 'O'
    return posicao



def procurar_vencedor(**posicao):

    possiveis_1 = posicao['pos1'] == posicao['pos4'] == posicao['pos7']
    possiveis_2 = posicao['pos1'] == posicao['pos2'] == posicao['pos3']
    possiveis_3 = posicao['pos1'] == posicao['pos5'] == posicao['pos9']
    possiveis_4 = posicao['pos2'] == posicao['pos5'] == posicao['pos8']
    possiveis_5 = posicao['pos3'] == posicao['pos6'] == posicao['pos9']
    possiveis_6 = posicao['pos4'] == posicao['pos5'] == posicao['pos6']
    possiveis_7 = posicao['pos7'] == posicao['pos8'] == posicao['pos9']
    possiveis_8 = posicao['pos3'] == posicao['pos5'] == posicao['pos7']


lista_possiveis = [possiveis_1, possiveis_2, possiveis_3, possiveis_4, possiveis_5, possiveis_6, possiveis_7, possiveis_8]


    for possiveis in lista_possiveis:
        if possiveis == True:
            print('Temos um vencedor! Parabéns!')
            return True
        elif contar_jogadas == 8:
            print('Deu velha! Ninguém ganhou.')
            return True



posicao = 
{
    'pos1': 1,
    'pos2': 2,
    'pos3': 3,
    'pos4': 4,
    'pos5': 5,
    'pos6': 6,
    'pos7': 7,
    'pos8': 8,
    'pos9': 9
}


lista_totalpalpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]



def denovo():
    jogar_denovo = input('''
Deseja jogar novamente?
Digite S para SIM ou N para NÃO.
''')

    if jogar_denovo.upper() == 'S':
        print('Bem Vindo ao Jogo da Velha! Vamos começar!')
        print('-=-'*15)
    elif jogar_denovo.upper() == 'N':
        print('Até logo!')
    else:
        denovo()


while True:

    tabuleiro(**posicao)
    jogada = pedir_jogada(lista_totalpalpites)
    lista_totalpalpites[jogada - 1] = 'X'
    posicao = verifica_jogada(jogada, contar_jogadas, **posicao)
    if procurar_vencedor(**posicao): 
        tabuleiro(**posicao)
        denovo()

    contar_jogadas += 1

2 answers

3

Can greatly simplify code and improve/correct various details:

Choose the appropriate data structure

For the board, you have created a dictionary with the keys "pos1", "pos2", etc. Whenever you have a dictionary whose keys are "something 1", "something 2", etc., it is a sign that probably You should use a list, not a dictionary. Lists have sequential numerical positions by definition, and using dictionaries in this case does not bring any advantage and only complicates the code randomly.

It may sound like a stupid detail, but choosing the right data structure is halfway towards a better program. Know what structures the language makes available (and mainly, how they work) and use the most suitable for each case.

The only "complication" is that the indices of a string start with zero, but get used to it, because that’s how languages work ("pretty much everything" in programming starts from zero).

Give better names

You called the board posicao, but the variable should be called tabuleiro (or else posicoes, plural), because it is not one position, rather the set of all positions (i.e., it is the board).

It may sound like a stupid detail, too, but giving better names helps a lot when programming. In the code below you will see that I changed other names too.

Validate if a number has been entered

Do not use isdigit(), because there are several characters for which isdigit() returns True, but error when converting to number with int(). An example is the ² (SUPERSCRIPT TWO), and there are several others (see full list here).

"Ah, but it’s just an exercise, the user will always enter valid numbers."

If so, just convert to int direct, without having to test whether it is digit (i.e., isdigit() would also not be necessary in this case). If the user is going to enter something, be prepared to receive "anything" and only proceed if you are sure that the data is valid.

The most guaranteed way is simply to convert to int, and capture the ValueError to see if there was a mistake.

There are other details to tidy up, such as:

  • do not call the function denovo() within itself. Despite "working", you are making a recursive call, and there may be a stack overflow if the user does not type either "S" or "N" for many times in a row (see here an example - scroll to the bottom of the page and see the error of stack overflow). Use a loop simple and ready.
  • put all repetitive tasks into function (even the print('-=-'*15), that despite being a single line, repeats itself several times, so if you want to change it, you will have to change in several places; already using a function, you only change in one place and that’s it)
  • do not need to pass the parameters with unpack (that is, with the asterisks before: funcao(**valor) is not necessary in your case - see here an example of where it would be necessary)
  • it is also interesting to check if the chosen position is valid, because the user can type 100, and when trying to access position 100 of the board, will give error
  • has other little details that you can see in the following code
def mostrar_separador():
    print('-=-' * 15)

def criar_tabuleiro(): # cria um tabuleiro vazio
    return list(range(1, 10)) # lista com os números entre 1 e 9

def mostrar_tabuleiro(tabuleiro):
    print('  {}  |  {}  |  {}  '.format(*tabuleiro[:3]))  # mostra as 3 primeiras posições
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(*tabuleiro[3:6])) # mostra da quarta à sexta posição
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(*tabuleiro[6:]))  # mostra as 3 últimas posições

def pedir_jogada(tabuleiro, jogador):
    mostrar_separador()
    while True:
        try: # não use isdigit(), capture o ValueError
            print(f'jogador atual: {jogador}') # incluí esta mensagem para facilitar um pouco
            jogada = int(input('Digite uma posição no tabuleiro para jogar: '))
            if jogada <= 0 or jogada > len(tabuleiro): # verifica se o valor não está fora dos limites do tabuleiro
                print(f'Posição inválida: {jogada}')
            elif jogada in tabuleiro:
                mostrar_separador()
                return jogada # retorna direto, não precisa do break
            else: 
                print('Você digitou um número já pedido, tente novamente')
        except ValueError:
            print('Você não digitou um número válido, tente novamente')

def jogo_terminou(tabuleiro):
    posicoes_vencedoras = [
        [0, 1, 2], [3, 4, 5], [6, 7, 8], # horizontal
        [0, 3, 6], [1, 4, 7], [2, 5, 8], # vertical
        [0, 4, 8], [2, 4, 6] # diagonal
    ]
    # verifica todas as combinações de posições vencedoras
    for pos1, pos2, pos3 in posicoes_vencedoras:
        if tabuleiro[pos1] == tabuleiro[pos2] == tabuleiro[pos3]:
            print(f'Temos um vencedor: {tabuleiro[pos1]}! Parabéns!') # mudei a mensagem para mostrar quem ganhou
            # se já encontrei um vencedor, posso retornar direto (não precisa continuar verificando as outras combinações)
            return True

    # não tem vencedor, verifica se todas as posições estão ocupadas (não preciso mais do contador de jogadas)
    if all(posicao in ('X', 'O') for posicao in tabuleiro):
        print('Deu velha! Ninguém ganhou.')
        return True

    # jogo ainda não terminou
    return False


import sys

def verificar_jogar_novamente(): # mudei o nome "denovo" para algo mais significativo
    while True: # use um loop em vez de chamar a função dentro dela mesma
        jogar_denovo = input('''
Deseja jogar novamente?
Digite S para SIM ou N para NÃO.
''').upper() # já transforma em maiúscula aqui

        if jogar_denovo == 'S':
            mostrar_separador()
            break # sai do while
        elif jogar_denovo == 'N':
            print('Até logo!')
            sys.exit() # sai do programa
        else: # incluí uma mensagem a mais para ajudar o usuário
            print('Você deve digitar "S" ou "N"')

def dados_iniciais(): # o jogo começa com o jogador X e tabuleiro vazio
    print('Bem Vindo ao Jogo da Velha! Vamos começar!')
    return ('X', criar_tabuleiro())

jogador, tabuleiro = dados_iniciais()
while True:
    mostrar_tabuleiro(tabuleiro)

    # como o tabuleiro agora é uma lista, posso simplesmente marcar a jogada mudando-o diretamente
    # e ele substitui a lista_totalpalpites, que se torna redundante
    jogada = pedir_jogada(tabuleiro, jogador)
    tabuleiro[jogada - 1] = jogador
    jogador = 'O' if jogador == 'X' else 'X' # troca o jogador de X para O ou vice-versa

    if jogo_terminou(tabuleiro): 
        mostrar_tabuleiro(tabuleiro)
        verificar_jogar_novamente()
        # reinicio o tabuleiro
        jogador, tabuleiro = dados_iniciais()

I used sys.exit() to exit the program. The problem is that it actually exits, that is, if there were any other code after the while True, he would not be executed.

Another option is to change the function verificar_jogar_novamente to return True or False, indicating whether the game should continue or not, and then I check it in the code:

def jogar_novamente(): # mudei o nome para "jogar_novamente"
    while True: # use um loop em vez de chamar a função dentro dela mesma
        jogar_denovo = input('''
Deseja jogar novamente?
Digite S para SIM ou N para NÃO.
''').upper() # já transforma em maiúscula aqui

        if jogar_denovo == 'S':
            mostrar_separador()
            return True # o jogo deve continuar
        elif jogar_denovo == 'N':
            print('Até logo!')
            return False # o jogo não deve continuar
        else: # incluí uma mensagem a mais para ajudar o usuário
            print('Você deve digitar "S" ou "N"')

...
jogador, tabuleiro = dados_iniciais()
while True:
    mostrar_tabuleiro(tabuleiro)

    # como o tabuleiro agora é uma lista, posso simplesmente marcar a jogada mudando-o diretamente
    # e ele substitui a lista_totalpalpites, que se torna redundante
    jogada = pedir_jogada(tabuleiro, jogador)
    tabuleiro[jogada - 1] = jogador
    jogador = 'O' if jogador == 'X' else 'X' # troca o jogador de X para O ou vice-versa

    if jogo_terminou(tabuleiro): 
        mostrar_tabuleiro(tabuleiro)
        if not jogar_novamente(): # se não é para jogar novamente, sai do while
            break # sai do while True
        # é para jogar novamente, reinicio o tabuleiro
        jogador, tabuleiro = dados_iniciais()

So he comes out of the while True, but does not terminate the program (i.e., if it had any code after the while, he would be executed, which would not occur with sys.exit()).

1

One option is to create a function that returns the empty board.


You have the following snippet that initializes the empty board:

posicao = 
{
    'pos1': 1,
    'pos2': 2,
    'pos3': 3,
    'pos4': 4,
    'pos5': 5,
    'pos6': 6,
    'pos7': 7,
    'pos8': 8,
    'pos9': 9
}

And also what creates the hunches:

lista_totalpalpites = [1, 2, 3, 4, 5, 6, 7, 8, 9]

We then create a function that returns this value from the empty board:

def tabuleiroVazio():
  return {
      'pos1': 1,
      'pos2': 2,
      'pos3': 3,
      'pos4': 4,
      'pos5': 5,
      'pos6': 6,
      'pos7': 7,
      'pos8': 8,
      'pos9': 9
  }

And also one that returns empty guesses:

def palpitesVazios():
  return [1, 2, 3, 4, 5, 6, 7, 8, 9]

We then start to initialize the variable posicao with the return of the function tabuleiroVazio:

posicao = tabuleiroVazio()

And the lista_totalpalpites with the palpitesVazios:

lista_totalpalpites = palpitesVazios()

Now in the excerpt you check the end of the game, you call again the function tabuleiroVazio and the palpitesVazios:

if procurar_vencedor(**posicao): 
    posicao = tabuleiroVazio()
    lista_totalpalpites = palpitesVazios()
    tabuleiro(**posicao)
    denovo()

Also, realize that even if you choose not to play again, the game continues, because your while True there’s no break, there’s no way out of the loop.

We can change the function denovo to return a Boolean and based on it do the break of while:

def denovo():
    jogar_denovo = input('''
Deseja jogar novamente?
Digite S para SIM ou N para NÃO.
''')

    if jogar_denovo.upper() == 'S':
        print('Bem Vindo ao Jogo da Velha! Vamos começar!')
        print('-=-'*15)
        return True
    elif jogar_denovo.upper() == 'N':
        print('Até logo!')
        return False
    else:
        return denovo()

If then she returns False, means that we should not follow in the loop and the game is ended:

if not denovo():
  break

Your code will then be more or less as follows:

print('Bem Vindo ao Jogo da Velha! Vamos começar!')

print('-=-'*15)

def tabuleiro(**posicao):
    print('  {}  |  {}  |  {}  '.format(posicao['pos1'], posicao['pos2'], posicao['pos3']))
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(posicao['pos4'], posicao['pos5'], posicao['pos6']))
    print('------+------+------')
    print('  {}  |  {}  |  {}  '.format(posicao['pos7'], posicao['pos8'], posicao['pos9']))

contar_jogadas = 0

def pedir_jogada(lista_totalpalpites):

    print('-=-'*15)
    while True:
        jogada = input('Digite uma posição no tabuleiro para jogar: ')

        if jogada.isdigit():
            jogada = int(jogada)
            if jogada in lista_totalpalpites:
                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 verifica_jogada(jogada, numero_jogadas, **posicao): 

    for key, value in posicao.items():
        if jogada == value:
            if numero_jogadas % 2 == 0:
                    posicao[key] = 'X'
            else:
                    posicao[key] = 'O'
    return posicao

def procurar_vencedor(**posicao):

    possiveis_1 = posicao['pos1'] == posicao['pos4'] == posicao['pos7']
    possiveis_2 = posicao['pos1'] == posicao['pos2'] == posicao['pos3']
    possiveis_3 = posicao['pos1'] == posicao['pos5'] == posicao['pos9']
    possiveis_4 = posicao['pos2'] == posicao['pos5'] == posicao['pos8']
    possiveis_5 = posicao['pos3'] == posicao['pos6'] == posicao['pos9']
    possiveis_6 = posicao['pos4'] == posicao['pos5'] == posicao['pos6']
    possiveis_7 = posicao['pos7'] == posicao['pos8'] == posicao['pos9']
    possiveis_8 = posicao['pos3'] == posicao['pos5'] == posicao['pos7']

    lista_possiveis = [possiveis_1, possiveis_2, possiveis_3, possiveis_4, possiveis_5, possiveis_6, possiveis_7, possiveis_8]

    for possiveis in lista_possiveis:
        if possiveis == True:
            print('Temos um vencedor! Parabéns!')
            return True
        elif contar_jogadas == 8:
            print('Deu velha! Ninguém ganhou.')
            return True

def tabuleiroVazio():
  return {
      'pos1': 1,
      'pos2': 2,
      'pos3': 3,
      'pos4': 4,
      'pos5': 5,
      'pos6': 6,
      'pos7': 7,
      'pos8': 8,
      'pos9': 9
  }

def palpitesVazios():
  return [1, 2, 3, 4, 5, 6, 7, 8, 9]

posicao = tabuleiroVazio()

lista_totalpalpites = palpitesVazios()

def denovo():
    jogar_denovo = input('''
Deseja jogar novamente?
Digite S para SIM ou N para NÃO.
''')

    if jogar_denovo.upper() == 'S':
        print('Bem Vindo ao Jogo da Velha! Vamos começar!')
        print('-=-'*15)
        return True
    elif jogar_denovo.upper() == 'N':
        print('Até logo!')
        return False
    else:
        return denovo()

while True:

    tabuleiro(**posicao)
    jogada = pedir_jogada(lista_totalpalpites)
    lista_totalpalpites[jogada - 1] = 'X'
    posicao = verifica_jogada(jogada, contar_jogadas, **posicao)

    if procurar_vencedor(**posicao): 
        posicao = tabuleiroVazio()
        lista_totalpalpites = palpitesVazios()
        tabuleiro(**posicao)
        if not denovo():
          break

    contar_jogadas += 1

See online: https://repl.it/repls/CluelessIcyAddon

Browser other questions tagged

You are not signed in. Login or sign up in order to post.