0

I managed to get this code to work before, but I've changed something accidentally and can't figure out what. The code that will not work is:

while True:                                                                             
    answer = input ("Would you like to play this game? Type yes if you would like to. Type no to end the program")
    if answer == 'no' or 'n' or 'No' or 'N':
        sys.exit()
    elif answer == 'yes' or 'y' or 'Yes' or 'Y':
        code = input("Input a three digit code. Must be more than 001 and less than 100.")

When I run the code and put in one of the answers, the program will not run the next part and gives no error message. In case it is necessary, I have put the code for the entire program below:

import random                                                                           
import sys
while True:                                                                             
    answer = input ("Would you like to play this game? Type yes if you would like to. Type no to end the program")
    if answer == 'no' or 'n' or 'No' or 'N':
        sys.exit()
    elif answer == 'yes' or 'y' or 'Yes' or 'Y':
        code = input("Input a three digit code. Must be more than 001 and less than 100.") 
        try:                                                                                
            value = int(code)                                                               
        except:                                                                             
            print ("Invalid code")                                                          
            continue                                                                        
        if 1 <= value <= 100:                                                               
            print (code)                                                                    
            print ("Valid code")                                                            
            print ("I will now try to guess your number")                                   
            number = random.randint(1, 100)                                                 
            while number > int(code) or number < int(code):                                 
                print ("Failed attempt. Number guessed is")                                 
                number = random.randint(1, 100)                                             
                print (number)                                                              
            else:                                                                           
                if number == int(code):                                                 
                    print ("Your code is")                                              
                    print (code)                                                                     
        else:                                                                               
            print ("Invalid code")

EDIT: Thank you so much, the yes option is working now, but the program will still not exit when selecting any of the no options, as it did before. The edited code is:

if answer in ('no', 'n', 'No', 'N'):
    sys.exit()
elif answer in ('yes', 'y', 'Yes', 'Y'):

I checked by printing the answer value, and i believe it is registering the no input but not executing the command that follows for some reason.

EDIT: I'm still a bit fuzzy on the logic, but changing it to exit() fixed the problem. It asks for confirmation when closing now, when it didn't before, but otherwise sorted.

S Aylward
  • 47
  • 5
  • 1
    Please make sure you get the indentation correct. It's **critical** in Python. – Barmar Dec 28 '15 at 20:53
  • You have an infinite loop, because the `if answer` test is not inside `while True:` – Barmar Dec 28 '15 at 20:55
  • @Barmar: Since it's not prompting again, probably an indentation issue here, but not in the original code. If it was in the original code, they'd be getting prompted over and over, not silently exiting (or stalling, the OP isn't clear, but as I note in my answer, you'd expect a silent `exit` here). – ShadowRanger Dec 28 '15 at 21:05

2 Answers2

4

Problem causing silent exit:

if answer == 'no' or 'n' or 'No' or 'N':
    sys.exit()

That test is testing answer == 'no' as one test, then 'n' as a separate test, and so on. or chains return when any test returns a "truthy" value (or the last evaluated value if none are truthy), so the test always ends up evaluating as "truthy" because a non-empty string like 'n' is truthy. If you're trying to test for any one of those values, you'd do an "is contained in" test to see if answer is one of a recognized group of values, e.g.:

if answer in ('no', 'n', 'No', 'N'):
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 1
    or `if answer.lower() in ('no', 'n')` – styvane Dec 28 '15 at 20:59
  • @user3100115: I avoided that to precisely match intended behavior; `"NO"` would be accepted by that, but it's not in the "official" set of recognized inputs. But if `"NO"` (and `"nO"`) is acceptable, then testing a smaller set after lower casing is better for simpler code if nothing else. – ShadowRanger Dec 28 '15 at 21:01
  • Well, if `'no' or 'n' or 'No' or 'N' == True` and `answer != True` then why would the condition `answer == 'no' or 'n' or 'No' or 'N'` evaluate to true? – tglaria Dec 28 '15 at 21:12
  • @tglaria: Because it's not about `True` vs. `False`, it's "truthy" vs. "falsy". `if 'n':` will always evaluate as truthy and the block will execute. So if `answer` isn't `'no'`, then that evaluates to `False`, then the `or` says "but lets see if the next test is truthy" and evaluates `'n'`, which is truthy on its own. After that first `or`, `answer` isn't even checked. So either `answer == 'no`` returns `True` and shortcircuits to "whole expression is truthy" or it returns `False` and it then checks if `'n'` is truthy (which it is). Either way, whole expression is truthy. – ShadowRanger Dec 28 '15 at 21:17
  • @tglaria: If it helps, add parentheses matching the operator precedence. `==` binds more tightly than `or`, so the original test was equivalent to `if (answer == 'no') or ('n') or ('No') or ('N'):`. With the unnecessary parens, it's much more clear that `answer` is only involved in the comparison with `'no'`, not any of the other values (which are evaluated separately). Python developers shouldn't need the parens (that precedence is common; you need to memorize it), but it's helpful for illustration. – ShadowRanger Dec 28 '15 at 21:19
  • 1
    @tglaria: See [Operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence). Note: The table is from lowest to highest (many languages use highest to lowest), so don't be confused; `or` is lower precedence than `==`. – ShadowRanger Dec 28 '15 at 21:24
  • @ShadowRanger I was reading considering the `==` had less precedence, now it's all clear to me. Thanks! – tglaria Dec 29 '15 at 12:25
1

The reason is due to this expression:

if answer == 'no' or 'n' or 'No' or 'N':

In python, the above is exactly the same as this:

if (answer == 'no') or ('n' != '') or ('No' != '') or ('N' != ''):

Since all but the first expression evaluates to true, the whole expression is true.

The simplest solution is to convert your input to lowercase and trim off any extra space, then check if the answer is in a list of allowable answers so that you can easily compare for "n", "N", "no", "NO", "No", "nO".

if answer.strip().lower() in ("n", "no"):
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685