Make sure the entry doesn’t happen again, numerically and within a range?

Asked

Viewed 69 times

1

I am programming a game of old. When the user chooses the house where he will mark his symbol (X or O), I need to ensure that:

  1. The input value refers to an empty box (which has not previously been selected for tagging);
  2. The input value is an integer number;
  3. The input value refers to an existing box range(0,9);

As long as the input value does not meet these three requirements at the same time, I want to continue repeating the value request with the command input.

What I tried to:

casa = ''

while tabuleiro[casa] != VAZIO:
    casa = input("Escolha onde quer jogar: ")
   
   while type(casa) != int:
        casa = input("Escolha onde quer jogar: ")
       
       if casa.isdigit():
            casa = int(casa)
        
        while casa not in range(0, 9):
            casa = input("Escolha onde quer jogar: ")
           
            if casa.isdigit():
                casa = int(casa)

2 answers

2

It is always best to divide a large or multi-step task into smaller tasks. Look at this code structure that uses functions to do the tasks you have established:

def casa_eh_numero_valido(casa): 
    return casa.isdigit() and 0 <= int(casa) <= 8

def casa_esta_vazia(casa, tabuleiro): 
    return tabuleiro[int(casa)] == 'VAZIA'

def casa_eh_valida(casa, tabuleiro): 
    return casa_eh_numero_valido(casa) and casa_esta_vazia(casa, tabuleiro)

Here we have a function casa_eh_valida who is responsible for checking whether a given casa (presumably the user input) is valid for a given tabuleiro (here I assume that tabuleiro is a list of size 9, since it was not explicit in its code). Both are function parameters, and this function performs this work by calling other functions.

The function casa_eh_numero_valido checks if the house is a digit between 0 and 8. Already the function casa_esta_vazia checks if the box is empty on the board. Note the conversion to number, since indexes are of the type int, nay str. This conversion is safe precisely because of the function casa_eh_numero_valido that we call immediately before. If the return of the first function is False, Python doesn’t even waste time calling the second function, since False and ... always returns False.

Remember: divide large tasks into small tasks to make your life easier.

In your main code, you can do something like:

tabuleiro = ["VAZIA"] * 9

while True:
    casa = input("Escolha onde quer jogar: ")
    if casa_eh_valida(casa, tabuleiro):
        print("A casa é válida.")
        # mais código continua aqui...
        # modificar tabuleiro, etc
    else:
        print("A casa é inválida.")
    if jogo_acabou(tabuleiro):
        break

I have already left here another idea to continue your game: a function jogo_acabou who picks up the board and checks if the game is over - either because someone has won (who?), or because there are no more empty houses. I leave this idea for you to complement :-)

2

If you want to check if a string contains a number and then validate if that number is between certain values, you do not need to use isdigit and then convert to int. Of course if the user always type correct values, there will be no problems, the problem is that there are several characters for which isdigit returns True but error when converting to int, see here.

All right it’s a corner case and "probably the user will never type these characters". But the best - and most guaranteed - would be to make the conversion with int(entrada) and capture the ValueError to know if a number has not been entered (more or less thus).

Anyway, in your case, just make a loop infinite and only interrupt it if all conditions are met:

tabuleiro = [ '' ] * 9

while True:
    try:
        casa = int(input('Escolha onde quer jogar: '))
        if 0 <= casa <= 8: # valor válido
            if tabuleiro[casa] == '':
                break # valor válido, encerra o loop
            else:
                print(f'Casa {casa} está ocupada')
        else:
            print('Valor deve estar entre 0 e 8')
    except ValueError:
        print('Não foi digitado um número')

# usar tabuleiro[casa]...

I mean, I read the dice and I try to turn them into numbers with int. If a number has not been typed, it launches the ValueError and falls into the block except.

If it is number, I check if it is in the correct value range and if the house is occupied (and in each case I print the respective message). If everything is OK, I close the loop with break.

As the rest of the program was not posted, it was unclear whether the loop should be stopped or if something should be done with the casa right there. If that’s the case, just do what you need with the position casa within the if tabuleiro[casa] == '' (instead of the break, do what you need to do in the if).


Of course you could even separate each check into a specific function, as suggested to another answer. But I think in this case neither compensates, the checks are too simple - not to mention that each function suggested there is calling int again (i.e., he converts to int twice, unnecessarily - apart from the problem of isdigit already mentioned, which does not always guarantee that the conversion to int will work).

Browser other questions tagged

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