Dice roller repeat issue in python3
Question:
I’m fairly new to programming in general and have been learning python3 for the last week or so. I tried building a dice roller and ran into an issue when asking the user if they wanted to repeat the roller or end the program.
import random as dice
d100 = dice.randint(1,100)
d20 = dice.randint(1,20)
d10 = dice.randint(1,10)
d8 = dice.randint(1,8)
d6 = dice.randint(1,6)
d4 = dice.randint(1,4)
d2 = dice.randint(1,2)
repeat = 'Y'
while repeat == 'Y' or 'y' or 'yes' or 'Yes':
roll = (input('What would you like to roll? A d100, d20, d10, d8, d6, d4, or d2?:'))
quantity = (input('How many would you like to roll?'))
quantity = int(quantity)
if roll == 'd100':
print('You rolled a: ' + str(d100 * quantity) + '!')
elif roll == 'd20':
print('You rolled a: ' + str(d20 * quantity) + '!')
elif roll == 'd10':
print('You rolled a: ' + str(d10 * quantity) + '!')
elif roll == 'd8':
print('You rolled a: ' + str(d8 * quantity) + '!')
elif roll == 'd6':
print('You rolled a: ' + str(d6 * quantity) + '!')
elif roll == 'd4':
print('You rolled a: ' + str(d4 * quantity) + '!')
elif roll == 'd2':
print('You rolled a: ' + str(d2 * quantity) + '!')
else:
print('That is not an available die! Please select a die.')
repeat = input('Would you like to continue?: ')
if repeat == 'yes' or 'Y' or 'y' or 'Yes':
continue
As of right now, despite what is input for the repeat variable it always continues even if it isn’t "yes", "Y", "y", or "Yes". I’m sure the answer is simple and right in front of me but I’m stumped! Thanks in advance!
Answers:
It’s a problem of precedence: repeat == 'Y' or 'y' or 'yes' or 'Yes'
is interpreted as (repeat == 'Y') or 'y' or 'yes' or 'Yes'
and then it tries to check whether 'y'
counts as true, which it does (it’s a non-empty string).
What you want is while repeat in ('Y', 'y', 'yes', 'Yes'):
By the way, you don’t need the if
statement at the end of the loop since it will exit automatically if repeat
is something other than 'Y'
, 'y'
, 'yes'
, or 'Yes'
.
Two things
continue
means go to the top of the loop (and then check whether to re-enter it), not guaranteed to go through the loop again. It might be better named skip because it really means "skip the rest of this iteration". Hence you don’t need if ... continue
because you’re already at the end of the iteration.
The real loop control is what follows while
. You’ve made a common mistake by assuming Python can group those or
operators as one set of options opposite the ==
. It can’t. Only the first string is compared to repeat
and the others are treated as individual conditions. A string on its own is True
as long as it’s not empty. Hence Python reads that as
while repeat
is 'Y'
, or 'y'
is not empty, or 'Yes'
is not empty, or 'yes'
is not empty
Since all three of those strings are by definition not empty, it doesn’t matter if repeat
is 'Y'
, the whole condition will always be True
.
The way to do multiple options for equality is
while repeat in ('Yes', 'yes', 'Y', 'y')
This means that repeat
must appear in that list of options.
Note that you can simplify by normalizing or casefolding repeat.
while repeat.upper() in ('Y', 'YES')
Or be even simpler and less strict
while repeat.upper().startswith('Y')
You should also strip repeat
to further eliminate user error of whitespace:
while repeat.strip().upper().startswith('Y')
Then you begin to arrive at a best practice for user-ended loops 🙂
I’m fairly new to programming in general and have been learning python3 for the last week or so. I tried building a dice roller and ran into an issue when asking the user if they wanted to repeat the roller or end the program.
import random as dice
d100 = dice.randint(1,100)
d20 = dice.randint(1,20)
d10 = dice.randint(1,10)
d8 = dice.randint(1,8)
d6 = dice.randint(1,6)
d4 = dice.randint(1,4)
d2 = dice.randint(1,2)
repeat = 'Y'
while repeat == 'Y' or 'y' or 'yes' or 'Yes':
roll = (input('What would you like to roll? A d100, d20, d10, d8, d6, d4, or d2?:'))
quantity = (input('How many would you like to roll?'))
quantity = int(quantity)
if roll == 'd100':
print('You rolled a: ' + str(d100 * quantity) + '!')
elif roll == 'd20':
print('You rolled a: ' + str(d20 * quantity) + '!')
elif roll == 'd10':
print('You rolled a: ' + str(d10 * quantity) + '!')
elif roll == 'd8':
print('You rolled a: ' + str(d8 * quantity) + '!')
elif roll == 'd6':
print('You rolled a: ' + str(d6 * quantity) + '!')
elif roll == 'd4':
print('You rolled a: ' + str(d4 * quantity) + '!')
elif roll == 'd2':
print('You rolled a: ' + str(d2 * quantity) + '!')
else:
print('That is not an available die! Please select a die.')
repeat = input('Would you like to continue?: ')
if repeat == 'yes' or 'Y' or 'y' or 'Yes':
continue
As of right now, despite what is input for the repeat variable it always continues even if it isn’t "yes", "Y", "y", or "Yes". I’m sure the answer is simple and right in front of me but I’m stumped! Thanks in advance!
It’s a problem of precedence: repeat == 'Y' or 'y' or 'yes' or 'Yes'
is interpreted as (repeat == 'Y') or 'y' or 'yes' or 'Yes'
and then it tries to check whether 'y'
counts as true, which it does (it’s a non-empty string).
What you want is while repeat in ('Y', 'y', 'yes', 'Yes'):
By the way, you don’t need the if
statement at the end of the loop since it will exit automatically if repeat
is something other than 'Y'
, 'y'
, 'yes'
, or 'Yes'
.
Two things
continue
means go to the top of the loop (and then check whether to re-enter it), not guaranteed to go through the loop again. It might be better named skip because it really means "skip the rest of this iteration". Hence you don’t need if ... continue
because you’re already at the end of the iteration.
The real loop control is what follows while
. You’ve made a common mistake by assuming Python can group those or
operators as one set of options opposite the ==
. It can’t. Only the first string is compared to repeat
and the others are treated as individual conditions. A string on its own is True
as long as it’s not empty. Hence Python reads that as
while
repeat
is'Y'
, or'y'
is not empty, or'Yes'
is not empty, or'yes'
is not empty
Since all three of those strings are by definition not empty, it doesn’t matter if repeat
is 'Y'
, the whole condition will always be True
.
The way to do multiple options for equality is
while repeat in ('Yes', 'yes', 'Y', 'y')
This means that repeat
must appear in that list of options.
Note that you can simplify by normalizing or casefolding repeat.
while repeat.upper() in ('Y', 'YES')
Or be even simpler and less strict
while repeat.upper().startswith('Y')
You should also strip repeat
to further eliminate user error of whitespace:
while repeat.strip().upper().startswith('Y')
Then you begin to arrive at a best practice for user-ended loops 🙂