Program won't loop or add to a list - python

I have made (or more, I'm trying to make) a program to help me calculate some figures.
I have some levels that each give a reward and to give out the rewards I prefer to not insert each amount and add them all up to get the totals.
I've made it so that I write the level number, it adds the amount to a list, it loops again, I insert a different number etc.
But it doesn't loop or add the numbers to the list.
Heres my super un-compact code:
lists = []
total = 0
def moneyz():
level=input('-> ')
print('g') #just a testing bookmark
print(level) #same here
if level==1:
print('oo') #and here
lists.apped('150')
total==total+150
elif level == 2:
lists.apped('225')
total==total+225
moneyz()
elif level == 3:
lists.apped('330')
total==total+330
moneyz()
elif level == 4:
lists.apped('500')
total==total+500
moneyz()
elif level == 5:
lists.apped('1000')
total==total+1000
moneyz()
elif level == 6:
lists.apped('1500')
total==total+1500
moneyz()
elif level == 7:
lists.apped('2250')
total==total+2250
moneyz()
elif level == 8:
lists.apped('3400')
total==total+3400
moneyz()
elif level == 9:
lists.apped('5000')
total==total+5000
moneyz()
elif level == 10:
lists.apped('15000')
total==total+15000
moneyz()
moneyz()
print(lists)
print(total)

I can see three bugs in this code:
level is a str, so it will never equal an int. None of your if checks will ever be satisfied, which is why your function isn't recursing. A way to spot this in debugging would have been to add a print(repr(level)) after you receive the input; you'd see that it's a value like '1' (a string) instead of 1 (an integer).
There is no such thing as apped(), so once you hit that line of code (which currently isn't happening because your if checks never match), it'd raise an AttributeError.
Your total is never going to increase because you're using the == (equality check) operator rather than the = (assignment) operator.
Here's a much shorter (working) version of the program, using a simple lookup table in place of a bunch of if statements:
# Rewards for levels 0 to 10.
rewards = [0, 150, 225, 330, 500, 1000, 1500, 2250, 3400, 5000, 15000]
# Running totals.
lists = []
total = 0
while True:
# Get reward level from the user. If not a valid reward level, stop.
level = input('-> ')
try:
level_num = int(level)
except ValueError:
break
if level_num not in range(len(rewards)):
break
# Add the reward to the lists and the total.
reward = rewards[level_num]
lists.append(reward)
total += reward
# Final output.
print(lists)
print(total)

You are using level==1where level is a string as input() returns a string and you are comparing it with int.
You should try level=='1' or convert level to int by level = int(input("->")).
Also, list has append() method and not apped()
Also, total==total+1000 won't help for adding. It will just check if value of total is equal to total plus 1000. You should use total = total + 1000 for adding value.
Here is one sample modified if block:
if level=='1':
print('oo') #and here
lists.append('150')
total=total+150
Hope it helps.

Related

Calculating the number of rolls of a dice in python

So I'm a beginner programmer and I'm trying to calculate the number of rolls it would take for two dice to add up to the sum of 11. This is the code I tried, but every time I run this, it gives me the output 'None'. What am I doing wrong here?
from random import randint
def die_roll1():
return(randint(1, 6))
def die_roll2():
return(randint(1,6))
def roll_sum():
sum = die_roll1() + die_roll2()
count = 2
if sum == 11:
return(count)
else:
count +=2
roll_sum()
print("The number of rolls are: ", roll_sum())
You are not returning the result of roll_sum() in the else block. However, consider using a while loop instead, as recursion for simpler cases is generally unpythonic:
import random
tries = 1
while True:
a, b = random.randint(1, 6), random.randint(1, 6)
if a + b == 11:
winning = [a, b]
break
tries += 1
Output:
22
[5, 6]
Technically, you simply need to return the count after the else portion. If you roll two non-11s, then the result is never passed recursively through all function calls, so it gets lost in limbo and returns None.
However, your code would never produce a number other than 4 in this case because you reset the count variable to 2 every time you roll an 11.
This can be fixed by making your count variable global (outside the function), and then incrementing it inside the function. This can also be fixed by declaring the variable outside of a while loop.
Iterative programs are nearly always more readable than recursive ones, and your program for this problem should definitely be iterative. The other answers give you an iterative solution.
But as nobody has shown you exactly how to correct your own (recursive) program, I'll do that. I think there are a few things you can learn which will help you (and other beginners) in the long run.
Here's the corrected code.
from random import randint
def die_roll():
return(randint(1, 6))
def roll_sum(count):
sum = die_roll() + die_roll()
if sum == 11:
return(count)
else:
count += 2
return roll_sum(count)
# Call roll_sum with 2 as your initial count
roll_sum(2)
Explanation
When your if statement block has a return statement, your else block should ALWAYS have a return statement too (and so should any elif blocks). If Python doesn't find an explicit return statement (this is what happens in your original program), it returns a special object called None.
So you need to make sure that every possible flow through your function leads to a return statement. Preceding your recursive call in your else block fixes this problem.
Initializing count = 2 inside your roll_sum function results in 2 being assigned to count every single time that the function is (recursively) called. This is obviously not what you want. Instead, you can add a function argument called count, which will solve this problem.
In your initial call of roll_sum, you will have to pass the initial value of count.
There is no need of having 2 functions which do exactly the same thing -- die_roll1 and die_roll2. A function is only supposed to encapsulate a functionality. You can instead just call the same function twice. If you want to make it explicit that you have 2 separate dice rolls, you can just add 2 variables.
roll1 = die_roll()
roll2 = die_roll()
sum = roll1 + roll2
All the best!
Here are several simple solutions to calculate the number of times each sum occurs in the rolling of two dice. To answer your specific problem, you would simply need to use the 'Specific Solution' in place of the 'General Solution' below.
dice1 = [1,2,3,4,5,6]
dice2 = [1,2,3,4,5,6]
totals = []
for num in dice1:
for roll in dice2:
sumz = str(num+roll)
if [sumz, 0] not in totals:
temp = [sumz, 0]
totals.append(temp)
for item in totals:
for num in dice1:
for roll in dice2:
# General Solution - sum of all roles
sumz2 = str(num+roll)
if sumz2 == item[0]:
item[1] += 1
# Specific Solution - only count number of 11's rolled
if sumz2 == '11':
if item[0] == '11':
item[1] += 1
print(totals)
# Using a dictionary to count
totals = {}
for num in dice1:
for roll in dice2:
sumz = str(num+roll)
if sumz not in totals:
totals[sumz] = 1
else:
totals[sumz] += 1
print(totals)
# using collections
from collections import Counter
# temp list to hold all sumz, including multiple entries of same value
temp = []
for num in dice1:
for roll in dice2:
temp.append(num+roll)
# unsorted dictionary of key value pairs
d = Counter(temp)
list_sorted_by_key = []
for i in sorted (d):
temp2 = (i, d[i])
list_sorted_by_key.append(temp2)
print(list_sorted_by_key)

Assigning points based on length of list of list

I was trying to figure out how to assign numbers to a certain point in a list based on how many items that there were left in a list.
For example:
def prizeHandout(prizeWinners):
for x in range(len(prizeWinners)):
if len(prizeWinners) == 24:
prizeWinners[x][2] = (int(prize[0]))
elif len(prizeWinners) == 12:
prizeWinners[x][2] = (int(prize[1]))
elif len(prizeWinners) == 6:
prizeWinners[x][2] = (int(prize[2]))
print(prizeWinners)
I have a global variable 'prize' which is a list with the prizes [10, 20, 30,....]
The 'prizeWinners' are in a list of list in this format [[ab, 2, 0], [ba, 5, 0], [aa, 12, 0], .....]
In the 'prizeWinners' variable, the assignment of the 'prize' should add on to the current space [2] and be added to the previous number if there was one.
Can't seem to get this working.
Any help would be appreciated, thanks :)
def prizesFunction():
with open('prizes.csv', 'r') as f:
reader = csv.reader(f)
prizePoints = list(reader)
first= [i[1] for i in prizePoints]
second = [i[0] for i in prizePoints]
third = [i[2] for i in prizePoints]
fourth = [i[3] for i in prizePoints]
choice = input('Enter your choice [0-4] : ')
choice = int(choice)
global prize
if choice == 1:
prize = first
return prize
elif choice == 2:
prize =second
return prize
elif choice == 3:
prize = third
return prize
elif choice == 4:
prize = fourth
return prize
Ok, since you are getting something out of this, I'll break it down again. Although I'm pretty sure that I still don't understand, and therefore, can't solve your problem. But, we can clean it up a bit.
I still don't like global variables. You do what you want in your code for now, but I'm telling you that global is a keyword because it should only be used in extraordinary situations. But, since you return prize and don't use it, before or after assignment I've replaced the global with a return value and added an assignment outside of the function. Again, this is python, not C. Everything is an object, and is generally passed by reference. So it's OK to return things, and not modify in place.
The next thing that catches my attention is the list comprehensions for first through fourth. Three things about this, first is that they are defined in a with block, which means that they potentially could be undefined if there is an error opening 'prizes.csv' So I initilize them as an empty list breofre the with. Next, this list comprehension is a bit our of order in that first is the 2nd value and second is the 1st value, so I rearranged that. Finally, why are you doing this exactly? This will produce a list of values that represent the 1st through 4th columns of the input csv.
If I had to guess, what this means is that you want to create the prize that is the column of the CSV. At least the first 4 rows of that column, anyway.
So finally, your problem is a type error. This is why you're really here. The output of the csv.reader is a list of str and the values you want are int or possibly float values. So, as I mentioned above, the safe way to read a string literal into a python value is to use the ast.literal_eval() function. This can be accomplished in a couple of ways. I think that the best place in your code is in the list comprehension (I left them there just for this purpose). You can see where I added the ast.literal_eval(), this function takes a string as an input and parses it as if it were python code, but does not execute it (making it the "safe" alternative to eval()) This will mean that when you try to add the numbers together you won't get the type error you were getting. You were getting that type error because python is strongly typed (and dynamically typed). This means that you cannot add a str to a int and it doesn't automatically convert int to a str like JavaScript would.
import ast
def prizesFunction():
first = []
second = []
third = []
fourth = []
with open('prizes.csv', 'r') as f:
reader = csv.reader(f)
prizePoints = list(reader)
first = [ast.literal_evel(i[0]) for i in prizePoints]
second = [ast.literal_evel(i[1]) for i in prizePoints]
third = [ast.literal_evel(i[2]) for i in prizePoints]
fourth = [ast.literal_evel(i[3]) for i in prizePoints]
choice = input('Enter your choice [0-4] : ')
choice = int(choice)
if choice == 1:
return first
elif choice == 2:
return second
elif choice == 3:
return third
elif choice == 4:
return fourth
prize = prizesFunction()
Ok, This should help a bit. Also, doesn't it look nice? When you are writing python and it starts to look messy... you're probably not doing it pythonically. import this
First thing's first, this is python, not C and so you should be using the for loop
for prizeWinner in prizeWinners:
This eliminates the need for range(). "What if I need to know the index," I hear you ask? Well, in this case you don't but if you did, the pythonic way is to use enumerate() Like this
for ii,prizeWinner in enumerate(prizeWinners):
I know this is pedantic, but let's take a look at what this simple change does to your code.
def prizeHandout(prizeWinners):
for prizeWinner in prizeWinners:
if len(prizeWinners) == 24:
prizeWinner[2] = (int(prize[0]))
elif len(prizeWinners) == 12:
prizeWinner[2] = (int(prize[1]))
elif len(prizeWinners) == 6:
prizeWinner[2] = (int(prize[2]))
print(prizeWinners)
Already feels better.
Now, "Prize is a global variable" is already not good. So we should pass that into the function, and we'll use a default value.
Why are you casting prize as an int? I'm sure you have a good reason, but if that reason happens to be that you are converting a str to an int I'd recommend you use ast.literal_eval(). I'm removing it, because it doesn't have any context on the rest of your question.
As far as adding the prize to the prizeWinner[2], let's make that change.
def prizeHandout(prizeWinners, prize=[10,20,30]):
for prizeWinner in prizeWinners:
if len(prizeWinners) == 24:
prizeWinner[2] += prize[0]
elif len(prizeWinners) == 12:
prizeWinner[2] += prize[1]
elif len(prizeWinners) == 6:
prizeWinner[2] += prize[2]
print(prizeWinners)
What I cannot answer from your program is why you are determining prizes by the len(prizeWinners)? What I imagine you were trying to do is see what index in the array they were. So, this is where that enumerate() would be handy. Try this on for size; this will increment the prizeWinner[2] by 10 if they are 25th in from the front of the list of prizeWinners, 20 if they are 13th, and 30 if they are 7th.
def prizeHandout(prizeWinners, prize=[10,20,30]):
for ii, prizeWinner in enumerate(prizeWinners):
if ii == 24:
prizeWinner[2] += prize[0]
elif ii == 12:
prizeWinner[2] += prize[1]
elif ii == 6:
prizeWinner[2] += prize[2]
print(prizeWinners)
That's all I can say on this. I hope you can follow my steps.

Python: Issue with Elif Break

I'm trying to make a simple program that will take all of your lottery numbers, and compare them (using set intersect) with the winning numbers that you input.
I've gotten the groundwork laid where you enter your numbers, it gets submitted to a sublist, which will then be converted into five separate sets, which will be used to compare. However, when you run the script, the while loop will not break when the length of the list is 5 (this is the goal).
Can someone explain what I'm doing wrong? Or maybe even a better way of working this whole program. I'm relatively new to the world of Python, I'm just diving in, and trying to make this program work.
# Start Program
def set_convert(list):
conversion = set(list)
return conversion
def comparison(winning_numbers, my_numbers):
pass
def main():
print('Welcome to the Lottery Checker v1.0!')
winning_numbers = [int(x) for x in input('Enter the winning numbers(Sep w/ Spaces): ').split()]
winning_set = set_convert(winning_numbers)
my_numbers = []
while True:
numbers = [int(x) for x in input('Enter your numbers(Sep w/ Spaces Max: 5): ').split()]
if len(numbers) == 6:
my_numbers.append(numbers)
print('Added! Want to add more?')
elif len(my_numbers) == 5:
break
else:
pass
else:
pass
print('Here are your numbers: {}. Good luck! :-)'.format(my_numbers))
main()
Replace
elif len(my_numbers) == 5:
with
elif len(numbers) == 5:
Also, it is advisable that you don't use the keyword list as an argument for the function set_convert. Rather, define it as:
def set_convert(mylist):
conversion = set(mylist)
return conversion
And finally, you don't need to pass in my_numbers and winning_numbers into the function comparison as arguments since they are available in the outer scope.

Square factorization in python 3?

Note - Go down to the edits if you want the more recent code, look here if you want to see the original question. I have made edits to the code, however, so mistakes in this code block may be outdated.
As a self-taught Python 3 programmer, I have been working on a way to simplify radical expressions. The one part of the program that does not work, however, is the square factorization. I have a function that detects square numbers, which works fine. The function that does not work is the following-
def sqfactorslist(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #if no square ints other than 1 square into num, append and finish.
while is_square(counter) == True and counter != 1: #If counter is a valid square integer, append it's square and subtract it from num.
if (counter ** 2) >= num:
factors.append(counter ** 2)
num -= counter ** 2
else: #Else, continue with a program.
break
if counter > 0:
counter -= 1 #If counter more than 0, subtract 1 from it
else:
break #If number is equal to or less than 0, break
return factors #If the input is 32, this should return 16 and 2.
It doesn't return anything other than an infinite loop. Anyone know whats wrong?
Edit 1 -- I have changed the program so that it runs, but now I have a stranger issue: If I input a square number as num, for example 16, I get a number larger than the input, e.x. 81, in the return list. I get no returned elements for a non-square number.
To make it run, I indented the first if statement after the end of the second while loop.
Edit 2 -- I have changed the program again, but I come up with another issue similar to the one above. After eliminating another mistake, where I squared numbers already shown to be square, found in the second while loop, the program now has a new problem - If I use a non-square integer, it returns an empty list, and if I use a square integer, like 16, it gives me an infinite loop. Current code shown below --
def findsqfactors(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #If no square ints other than 1 square into num, append then finish.
while is_square(counter) == True and counter != 1: #
if counter >= num:
factors.append(counter)
num -= counter
else:
break
if counter > 0:
counter -= 1
else:
break
return factors

In my 'high scores' python program, a comparison operator raises an error, but only sometimes

The question refers to the following python program -
# High Scores
# Maintains a list of the five highest scores and the players responsible.
hiscores = [56,45,23,11]
again = "a"
def findplace(xlist, x):
# list is in descending order
for j in range(len(xlist)-1):
if x >= xlist[j]:
xlist.insert(j, x)
return xlist
while again:
print("\n", hiscores)
score = int(input("\nEnter a score (zero to exit): "))
if score >= hiscores[3]:
hiscores = findplace(hiscores, score)
elif score == 0:
again = ""
print(hiscores)
input("\nETE")
The program takes scores from the user and adds them to the list if they are high enough. I wanted to set the entry level at the lowest score by setting the index value on the third line of the while loop at 3, but this raises an error. 0, 1 and 2 work perfectly! What am I doing wrong?
I can not reproduce your problem with the "entry level" score. However, since your list has only five elements anyway, you can make things easier by dropping the entry level check completely.
while True:
print("\n", hiscores)
score = int(input("\nEnter a score (zero to exit): "))
if score == 0:
break
hiscores = findplace(hiscores, score)
Also note that your findplace method will extend the high scores list to more than five entries, and that it can return None if the score is not within the first len-1 entries. Instead, you could just add the new score, sort the list in reverse order, and take the first five elements.
def findplace(xlist, x):
return sorted(xlist + [x], reverse=True)[:5]
The issue is that findplace only returns a new list if the score is a high score. If you enter 11, which is not inserted, it doesn't hit a return statement (and so returns None). Since you set highscores = findplace(hiscores, score), you essentially set your list to None, causing the TypeError.
Moving return xlist to the same level as the for loop in findplace fixes this error (but reveals a logic error in your findplace function, which I'll leave for you to discover).

Categories

Resources