Can this code be made more Pythonic? Loops - python

So I am writing some code to roll three fudge dice (six sided dice with sides of -1,-1,0,0,+1,+1). If the three dice together roll a total of -3, I have a function that then rolls a single fudge dice over and over again, subtacting 1 from the total for each -1 that get's rolled and quiting if something other than a -1 is rolled - in this way I get an "explosion down" making totals less than -3 possible, though increasingly less likely.
My explode down function is this:
def explodedown():
curval = -3
while 1:
newroll = rolldie()
if newroll != -1:
break
else:
curval = curval-1
return curval;
That seems to work well enough, but I almost feel that if I wanted to write this even more simply, there should be some way to write the loop more like:
while newroll == -1
newroll = rolldie()
curval = curval-1
And then the loop would naturally break without needing an if statement. Problem is newroll does not exist until we get inside the loop, so I don't think that will work. Maybe if I added another statement before the loop starts like:
newroll = rolldie()
while newroll == -1
newroll = rolldie()
curval = curval-1
But it seems un-pythonic to have the newroll line there twice.
Thoughts? is there a way to simplify and make more readable my explode down function?

You could do it like this:
while rolldie() == -1:
curval -= 1

Related

Breaking out of a while loop

I am new to python and programming and having difficulty breaking out of a while loop that calls a few functions. I have tried a variety of different options but they all end the same, well they don't end it just keeps running. I am only on here because I have really researched and tried for a long time to fix this. Below is some of the code where you can see there might be confusion with a function. I am not posting the full program just the last part. Thank you for any assistance while I learn. This is also my first time posting, I've been using stackoverflow for the past year dabbling.
def main():
choice = input('''Hello,
Would you like to do basic math or return an average?
Please select 1 for basic math and 2 for average and 3 to quit:
''')
if choice == '1':
print(performCalculation())
elif choice == '2':
print(calculateAverage())
elif choice == '3':
print(main())
j = 0
k = 0
while j < 3:
print(main())
while k == 3:
break
print('All Done!')
Simply change
j = 0
k = 0
while j < 3:
print(main())
while k == 3:
break
print('All Done!')
to
j = 0
while j < 3:
print(main())
j += 1
print('All Done!')
The reason your while loop never breaks is because you have while j < 3:, but you never change the value of j, so if it was smaller to begin with, it will forever be smaller.
Also, k will never equal to 3, and even if it will, the break statement within that while loop will only make that while loop terminate, not the main one.
You have several basic mistakes here. I'll go in order of your program execution.
You aren't incrementing your loop variables.
You've started your loop variables with j and k (why not i and j?) set to zero, and are looped based on the value of these variables. Since they are never incremented, your loop never hits an exit condition.
You can increment the variables with j += 1, and k += 1 at the end of the respective loops.
Your loops are "unpythonic"
These would typically be written as my example below. You don't need to declare i separately, or increment it here. Python handles that for you.
for i in range(0, 3):
...
You're printing a function that doesn't return anything.
Your main function doesn't have a return value, so calling print(main()) is nonsense. You can replace this with simply main() unless you change main() to have some kind of return "foo" statement.

Creating a game where the computer guesses a value through inputs of <,> or =

I am trying to create a game where i think of a number in my head. And then the computer guesses the number through me telling it if its guess is too low or high.
This is what I've come up with but i am pretty lost tbh.
maxguess = 100
minguess = 1
count = 0
print("Think of a number between {} and {}".format(minguess,maxguess))
def midpoint(maxguess, minguess) :
z = ((maxguess + minguess)/2)
def guessing(x) :
print("Is you number greater (>) , equal (=) ,or less (<) than" ,z,)
print("please answer <,=, or >! >")
x = input()
if x == (">") :
minpoint = z
count += 1
continue
elif x == ("<") :
maxpoint = z
count += 1
continue
elif x == ("=") :
print ("I have guessed it!")
count += 1
break
print("I needed {} steps!".format(count))
Purposely not a complete solution, but some hints for you:
I'd recommend avoiding the global variables like count, maxguess, and minguess. Instead, make a function that holds all these variables.
Change your midpoint function to return z instead, then call it inside your guessing function.
Your continue and break functions would need to be inside a for or while loop. Since you aren't sure how many iterations you need to guess the number, I think a while loop would make sense here
Your functions are never run. On a style point, bring all your 'main' statements down to the bottom so they're together. After the prompt to think of a number, you need to call the guessing() function. When you call it, you should pass the minguess and maxguess values to it.
I can see what you're trying to do with the if...elif statements, but they need to be in a while True: block. So should the three statements preceding them so the script repeatedly asks for new advice from you.
Either bring the content of the midpoint() function into guessing() or make it return the value of z.
You also offer the user a choice of '>1' but don't handle it - and you don't need it as far as I can tell.
You never use minpoint or maxpoint - and you dont need them. Call the midpoint function instead and pass it the appropriate values, e.g., if '>', z = midpoint(z, maxguess).
Also, you're going to spend forever trying to get it to guess as you are using floats. Make sure everything is an integer.
Finally, you should add some code to manage input that isn't expected, i.e., not '<', '>' or '='.
Good luck!
minguess=1
maxguess=100
z=50
count=0
print("Think of a number between 1 and 100")
condition = True
while condition:
z=((maxguess + minguess)//2)
print("Is your number greater (>) , equal (=) ,or less (<) than" ,z,)
print("Please answer <,=, or >! >")
x = input()
if x == (">"):
minguess=z
count += 1
elif x == ("<") :
maxguess=z
count += 1
elif x == ("=") :
print ("I have guessed it!")
count += 1
condition=False

false if statements being called/variable not being assigned?

I wasn't too sure what to call this post.
Anyways, what I'm trying to do is assign 'diff' to a user input, and if 'diff' is not average or advanced, recall the function so that the user can (hopefully) enter average or advanced.
However, no matter what I input, it will always recall the function, even if the input is 'average' or 'advanced'.
Code -
def choices():
global diff
diff = input("Choose a difficulty: Average/Advanced ")
diff = diff.lower()
x = 0
while x > 1:
if diff == 'average':
print('Difficulty set to average.')
x = x + 1
elif diff == 'advanced':
print('Difficulty set to advanced.')
x = x + 1
if diff != 'average' or 'advanced':
print('Your input is invalid. Please try again.')
choices()
choices()
The same thing is also happening for another decision I have that is similar to this, but I figured that there's no point in putting it down if it follows the same logic.
Sorry if this is a stupid question. I'm only a beginner.
You can also wrap it all into the while loop, I'm new to python but spawning recursive instances of a function seems dangerous to me.
def choices():
global diff
while true:
diff = input("Choose a difficulty: Average/Advanced ")
diff = diff.lower()
if diff == 'average':
print('Difficulty set to average.')
return
if diff == 'advanced':
print('Difficulty set to advanced.')
return
print('Your input is invalid. Please try again.')
Your first bug lies in this statement:
while x > 1:
You'll never execute the code within that loop because you set x = 0 at the top of the function. When it hits the while loop, x = 0 and so the while loop will be completely skipped.
There are a number of other problems, but this one is what's stopping the "if" logic from running.
I'm so confused about this function that I can't determine exactly what you're trying to do so I can't supply a complete working solution to your problem, only the first rather large bug in it.

My "while loop" not working as expected

I am a new coder, sorry if my question is bad or I am not following proper etiquette!
I am designing a basic program that rolls dice. It is supposed to roll dice until the total points of either the computer or the user equals 100. However, even though my point totaler is working, the loop won't end. Anyone know why this is? Thank you!
def main():
GAME_END_POINTS = 100
COMPUTER_HOLD = 10
is_user_turn = True
user_pt = 0
computer_pt = 0
welcome()
while computer_pt < GAME_END_POINTS or user_pt < GAME_END_POINTS:
print_current_player(is_user_turn)
if is_user_turn is True:
user_pt = user_pt + take_turn(is_user_turn, COMPUTER_HOLD)
elif is_user_turn is False:
computer_pt = computer_pt + take_turn(is_user_turn, COMPUTER_HOLD)
report_points(user_pt, computer_pt)
is_user_turn = get_next_player(is_user_turn)
The condition is always True because either the computer or the user will have a points total less than 100.
Instead of or use and:
while computer_pt < GAME_END_POINTS and user_pt < GAME_END_POINTS:
Now the loop will continue only when both the user and the computer have a points total less than 100. As soon as one of them has more than 100 the condition will be be False and the loop will terminate.
You while loop will only end if both computer_pt >= GAME_END_POINTS and user_pt >= GAME_END_POINTS. Are you sure that those two variables satisfy those two conditions?
you can print computer_pt and user_pt in the loop to see what happened in this two variable, then you will find the answer by your self.
Print variable in loop is a common way to debug your code.

For Loop Not Breaking (Python)

I'm writing a simple For loop in Python. Is there a way to break the loop without using the 'break' command. I would think that by setting count = 10 that the exit condition would be met and the loop would stop. But that doesn't seem to be the case.
NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop.
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
count = 10
else:
print("Try again...")
count += 1
I'm new to programming, so I'm just getting my feet wet. I could use a 'break' but I'm trying figure out why the loop isn't ending when you enter the guessed number correctly.
The for loop that you have here is not quite the same as what you see in other programming languages such as Java and C. range(0,5) generates a list, and the for loop iterates through it. There is no condition being checked at each iteration of the loop. Thus, you can reassign the loop variable to your heart's desire, but at the next iteration it will simply be set to whatever value comes next in the list.
It really wouldn't make sense for this to work anyway, as you can iterate through an arbitrary list. What if your list was, instead of range(0,5), something like [1, 3, -77, 'Word', 12, 'Hello']? There would be no way to reassign the variable in a way that makes sense for breaking the loop.
I can think of three reasonable ways to break from the loop:
Use the break statement. This keeps your code clean and easy to understand
Surround the loop in a try-except block and raise an exception. This would not be appropriate for the example you've shown here, but it is a way that you can break out of one (or more!) for loops.
Put the code into a function and use a return statement to break out. This also allows you to break out of more than one for loop.
One additional way (at least in Python 2.7) that you can break from the loop is to use an existing list and then modify it during iteration. Note that this is a very bad way to it, but it works. I'm not sure that this will this example will work in Python 3.x, but it works in Python 2.7:
iterlist = [1,2,3,4]
for i in iterlist:
doSomething(i)
if i == 2:
iterlist[:] = []
If you have doSomething print out i, it will only print out 1 and 2, then exits the loop with no error. Again, this is a bad way to do it.
You can use while:
times = 5
guessed = False
while times and not guessed:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
times -= 1
For loops in Python work like this.
You have an iterable object (such as a list or a tuple) and then you look at each element in the iterable, storing the current value in a specified variable
That is why
for i in [0, 1, 2, 3]:
print item
and
for j in range(4):
print alist[j]
work exactly the same. i and j are your storage variables while [0, 1, 2, 3] and range(4) are your respective iterables. range(4) returns the list [0, 1, 2, 3] making it identical to the first example.
In your example you try to assign your storage variable count to some new number (which would work in some languages). In python however count would just be reassigned to the next variable in the range and continue on. If you want to break out of a loop
Use break. This is the most pythonic way
Make a function and return a value in the middle (I'm not sure if this is what you'd want to do with your specific program)
Use a try/except block and raise an Exception although this would be inappropriate
As a side note, you may want to consider using xrange() if you'll always/often be breaking out of your list early.
The advantage of xrange() over range() is minimal ... except when ...
all of the range’s elements are never used (such as when the loop is
usually terminated with break)
As pointed out in the comments below, xrange only applies in python 2.x. In python 3 all ranges function like xrange
In Python the for loop means "for each item do this". To end this loop early you need to use break. while loops work against a predicate value. Use them when you want to do something until your test is false. For instance:
tries = 0
max_count = 5
guessed = False
while not guessed and tries < max_count:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
tries += 1
What #Rob Watts said: Python for loops don't work like Java or C for loops. To be a little more explicit...
The C "equivalent" would be:
for (count=0; count<5; count++) {
/* do stuff */
if (want_to_exit)
count=10;
}
... and this would work because the value of count gets checked (count<5) before the start of every iteration of the loop.
In Python, range(5) creates a list [0, 1, 2, 3, 4] and then using for iterates over the elements of this list, copying them into the count variable one by one and handing them off to the loop body. The Python for loop doesn't "care" if you modify the loop variable in the body.
Python's for loop is actually a lot more flexible than the C for loop because of this.
What you probably want is to use break and to avoid assigning to the count variable.
See the following, I've edited it with some comments:
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
# for count in range(0, 5): instead of count, use a throwaway name
for _ in range(0, 5): # in Python 2, xrange is the range style iterator
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
# count = 10 # instead of this, you want to break
break
else:
print("Try again...")
# count += 1 also not needed
As others have stated the Python for loop is more like a a traditional foreach loop in the sense that it iterates over a collection of items, without checking a condition. As long as there is something in the collection Python will take them, and if you reassign the loop variable the loop won't know or care.
For what you are doing, consider using the for ... break ... else syntax as it is more "Pythonic":
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
break
else:
print("Try again...")
else:
print "You didn't get it."
As your question states NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop and you don't want to use break, you can put it in a function and return when the correct number is guessed to break the loop.
import random
def main():
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print ("You guessed it!")
return
else:
print("Try again...")

Categories