Python Nested List - Changing and replacing individual items - python

I am completing a simple programming exercise (I am still new) where I am creating a character profile by allocating 30 points to 4 different character attributes. Program features are: show current profile, create a new profile, or change existing profile. First and second feature work fine, but there is problem with the last: the program is meant to unpack the nested list item (attribute + allocated score), ask for a new score, take the difference between the old and new and change the number of available points in the pool accordingly. Finally, add a new entry to the list (attribute + newly allocated score) at position 0 and then delete the entry at position 1, which should be the old entry for this attribute. Loop through the list, and done. However, once you execute the code you will see it won't work. Please see below the complete code:
options = ["Strength", "Health", "Wisdom", "Dexterity"]
profile = []
points = 30
choice = None
while choice != "0":
print(
"""
CHARACTER CREATOR PROGRAM
0 - Exit
1 - See current profile
2 - Build new profile
3 - Amend existing profile
"""
)
choice = input("Please choose an option: ")
print()
if choice == "0":
print("Good bye.")
elif choice == "1":
for item in profile:
print(item)
input("\nPress the enter key to continue.")
elif choice == "2":
print("You can now equip your character with attributes for your adventures.")
print("You have",points,"points to spent.")
print("Now configure your character: \n")
#Run the point allocation loop
for item in options:
point_aloc = int(input("Please enter points for " + str(item) + ":"))
if point_aloc <= points:
entry = item, point_aloc
profile.append(entry)
points = points - point_aloc
print("\nYour current choice looks like this: ")
print(profile)
input("\nPress the enter key to continue.")
else:
print("Sorry, you can only allocate", points," more points!")
print("\nYour current choice looks like this: ")
print(profile)
input("\nPress the enter key to continue.")
print("\nWell done, you have configured your character as follows: ")
for item in profile:
print(item)
input("Press the enter key to continue.")
elif choice == "3":
print("This is your current character profile:\n")
for item in profile:
print(item)
print("\nYou can change the point allocation for each attribute.")
for item in profile:
point_new = int(input("Please enter new points for " + str(item) + ":"))
attribute, points_aloc = item
diff = points_aloc - point_new
if diff >0:
points += diff
print("Your point allocation has changed by", -diff,"points.")
print(diff,"points have just been added to the pool.")
print("The pool now contains", points,"points.")
entry = item, point_new
profile.insert(0, entry)
del profile[1]
input("Press the enter key to continue.\n")
elif diff <0 and points - diff >=0:
points += diff
print("Your point allocation has changed by", -diff,"points.")
print(-diff,"points have just been taken from the pool.")
print("The pool now contains", points,"points.")
entry = item, point_new
profile.insert(0, entry)
del profile[1]
input("Press the enter key to continue.\n")
elif diff <0 and points - diff <=0:
print("Sorry, but you don't have enough points in the pool!")
input("Press the enter key to continue.\n")
else:
print("Sorry, but this is not a valid choice!")
input("Press the enter key to continue.\n")
input("\n\nPress the enter key to exit.")
Note: You need to create the profile first to run the changes.
Thanks in advance for your help!!

As the comments to your question indicate, you haven't asked your question in the best way. However, I see what's wrong with it. I could show you how to fix your current code, but the truth is that the best way to fix it is to rewrite it completely. As you do so, you should adopt the following strategies:
Break your code up into parts. In this case, I would advise you to create several different functions. One could be called main_loop, and would contain the logic for looping through the menu. It wouldn't contain any of the code for updating or displaying profiles. Instead, it would call other functions, display_profile, build_profile, and amend_profile. Those functions would accept variables such as options, profile, and points, and would return values such as options and points. This will enormously simplify your code, and make it much easier to test and debug. Here's an example of what main_loop might look like:
def main_loop():
options = ["Strength", "Health", "Wisdom", "Dexterity"]
profile = []
points = 30
choice = None
while choice != "0":
print(menu_string) #define menu_string elsewhere
choice = input("Please choose an option: ")
print()
if choice == "0":
print("Good bye.")
elif choice == "1":
display_profile(profile)
elif choice == "2":
profile, points = build_profile(options, profile, points)
elif choice == "3":
profile, points = amend_profile(profile, points)
else:
print("Sorry, but this is not a valid choice!")
input("Press the enter key to continue.\n")
input("\n\nPress the enter key to exit.")
See how much nicer this is? Now all you have to do is define the other functions. Something like...
def build_profile(options, profile, points):
# insert logic here
return profile, points
Another advantage to this approach is that now you can test these functions individually, without having to run the whole program.
Use the correct idioms for list modification. Modifying a list while iterating over it takes special care, and in some cases (such as when you change the length of the list by removing or adding items you've already iterated over) it won't work at all. There are ways to do what you try to do to profile, but for a beginning programmer I would recommend something much simpler: just create a new list! Then return that list. So in your amend_profile function, do something like this:
def amend_profile(profile, points):
# other code ...
new_profile = []
for item in profile:
attribute, points_aloc = item
# other code ...
new_proflie.append(entry)
# other code ...
return new_profile, points
Note also that this is where one of your main bugs is; you create an entry containing (item, point_new) instead of (attribute, point_new), so your new tuple has an item tuple inside it, instead of a lone attribute string as expected.

Related

How do I make a code that repeats without while-loop?

I'm trying to repeat a code that asks the user for a name, and thereafter asks for a new name. If the user writes a number, the program should ask for a new name. If the user types 'quit' the program should print how many names the user has entered.
So far I've solved it with a while-loop, but would like to do it WITHOUT using a while-loop and still keep prompting the user for new names.
participants=[]
count=0
while True:
user_name=input("Course participant name: ")
if user_name == "quit":
print("Number of participants: ", count)
elif user_name.isdigit():
continue
elif user_name.isalpha():
participants.append(user_name)
count+=1
else:
print("Invalid input")
break
Any suggestions?
You could use recursion:
def ask(participants):
user_name = input("Course participant name: ")
if user_name == "quit":
print("Number of participants: ", len(participants))
elif user_name.isdigit():
ask(participants)
elif user_name.isalpha():
participants.append(user_name)
ask(participants)
else:
print("Invalid input")
return
Instead of looping, you go deeper and deeper into the call stack. No need to track count separately because it is already encoded in the length of participants.
This is a slightly tricky way to do it, by using the participants list itself and providing an initial element (to start the loop), which will be deleted in the end. The loop will keep going as long as there is a name being inputted, because the participants list grows at every iteration.
participants=["Start"] # insert initial element, to start the loop
count=0
for i in participants:
user_name=input("Course participant name: ")
if user_name == "quit":
print("Number of participants: ", count)
elif user_name.isdigit():
continue
elif user_name.isalpha():
participants.append(user_name)
count+=1
else:
print("Invalid input")
break
del participants[0] # remove initial element
If you are looking for solution using for loop then you can do as follow:
participants=[]
count=0
from itertools import cycle
for i in cycle(range(0, 1)):
user_name=input("Course participant name: ")
if user_name == "quit":
print("Number of participants: ", count)
elif user_name.isdigit():
continue
elif user_name.isalpha():
participants.append(user_name)
count+=1
else:
print("Invalid input")
break

python trouble getting code to work

update so it seems like no matter what i do or type it asks
what would you like to add?
instead of doing the other options it just keeps asking this
it should only be asking this if the user types a
this is a 2 issue thing im having and the main original post is here
How to debug errors in Python?
but the bigger issue im having is i cant get the bottom half of my code to work
it just ignores the inputs given to it and continues to add them to the list
#.....
elif user == "d" :
listdelete = input("what item do you want deleted")
list.remove (listdelete)
elif user == "p" : # prints the list
print (list)
elif user == "x" : # exits the program
print ("good bye")
print ("!!!!!!that is not a choice!!!!!!")
#right now everything is being called through a single procedure
print (option())
and on the bottom here is going to be the entire code sorry for pasting the entire code on the bottom here but i thought it would be easy to understand the whole issue if i showed the whole code and then the section thats not working since its all under one procedure
list = []
def option() :
print ("(a) -to add item ")
print ("(d) -to delete item")
print ("(p) -to see items on your list")
print ("(x) -to exit ")
#above just prints out user options with a input after
user = input("please select a choice")
if user == "a" :
item = input("what would you like to add? ")
list.append (item)
# next im going to ask if they would like to add another item
more = input(" would you like to add something else? yes or no")
while more == "yes":
if more == "yes" :
item = input("what else would you like to add? type b to back ")
if item == "b" :
print (option())
else :
list.append(item)
elif more == "no" :
print (option())
#.....
elif user == "d" :
listdelete = input("what item do you want deleted")
list.remove (listdelete)
elif user == "p" : # prints the list
print (list)
elif user == "x" : # exits the program
print ("good bye")
print ("!!!!!!that is not a choice!!!!!!")
#right now everything is being called through a single procedure
print (option())
I have updated your code which still has flaws and exploits the mutability of the list datatype but does work as you would expect it:
#!/usr/bin/env python
def AddElement(collection):
elementToAdd = input("What would you like to add: ")
collection.append(elementToAdd)
return collection
def DeleteElement(collection):
print("You have the following items:", collection)
elementToDelete = input("What item do you want deleted: ")
for elements in collection:
if elements == elementToDelete:
collection.remove(elements)
print("You have the following items left:", collection)
return collection
def WriteMenu():
print("(a) -to add item")
print("(d) -to delete item")
print("(p) -to see items on your lst1")
print("(x) -to exit")
return True
def option():
WriteMenu()
UserInput = input("Please select a choice: ")
while UserInput:
if UserInput == "a":
AddElement(collection)
elif UserInput == "d":
DeleteElement(collection)
elif UserInput == "p":
print(collection)
elif UserInput == "x":
print("Good bye!")
break
WriteMenu()
UserInput = input("Please select a choice: ")
else:
print(collection)
#right now everything is being called through a single procedure
collection = []
option()

Creating a "Flashcard" vocabulary program

I'd like to make a program in Python 3 that would be essentially vocabulary flashcards. I'd be able to list the terms, add a term, or display a random definition to try and accurately guess. Once guessed accurately, I would be given the option for another definition to guess. Alternatively, I'd like to just be able to display a random key:value pair, and to continue viewing pairs until I enter EXIT.
I have made most of the program using a dictionary, but am not sure how to go about with entering the proper command to enter the key for the definition displayed. If anyone could provide suggestions, I'd appreciate it! Also I got some sort of error message when entering this code in and had to do a bunch of indentations, not sure what I did wrong there.
import random
terms = {"1" : "def 1", #Dictionary of 'terms' and 'definitions'
"2" : "def 2",
"3" : "def 3"}
menu = None
while menu != "4":
print("""
DIGITAL FLASHCARDS!
1 - List Terms
2 - Add Term
3 - Guess Random Definition
4 - Exit
""")
menu = input("\t\t\tEnter Menu option: ")
if menu == "1": # List Terms
print("\n")
for term in terms:
print("\t\t\t", term)
input("\n\tPress 'Enter' to return to Main Menu.\n")
elif menu == "2": # Add Term
term = input("\n\tEnter the new term: ").upper()
if term not in terms:
definition = input("\tWhat is the definition? ")
terms[term] = definition
print("\n\t" + term, "has been added.")
else:
print("\n\tThat term already exists!")
input("\n\tPress 'Enter' to return to Main Menu.\n")
elif menu == "3": # Guess Random Definition. Once correct, choose new random definition
print("\n\t\t\tType 'Exit' to return to Menu\n")
choice = random.choice(list(terms.values()))
print("\n\t" + choice + "\n")
guess = None
while guess != "EXIT":
guess = str(input("\tWhat is the term? ")).upper()
display a random definition to try and accurately guess. Once guessed accurately, I would be given the option for another definition to guess
Use terms.items() to get key and value at the same time.
Define the process of generating a new definition question into a function generate_question() to avoid duplicity.
elif menu == "3": # Guess Random Definition. Once correct, choose new random definition
print("\n\t\t\tType 'Exit' to return to Menu\n")
def generate_question():
term, definition = random.choice(list(terms.items()))
print("\n\t" + definition + "\n")
return term
term = generate_question()
guess = None
while guess != "EXIT":
guess = input("\tWhat is the term? ").upper()
if guess == term:
print("Correct!")
if input("\tAnother definition?(y/n)").upper() in ["Y", "YES"]:
term = generate_question()
else:
break
Alternatively, I'd like to just be able to display a random key:value pair, and to continue viewing pairs until I enter EXIT.
elif menu == "4": # Random display a term-definition pair.
print("\n\t\t\tType 'Exit' to return to Menu\n")
exit = None
while exit != "EXIT":
term, definition = random.choice(list(terms.items()))
print(term + ":", definition)
exit = input("").upper() # Press enter to continue.
Remember to modify the beginning part:
while menu != "5":
print("""
DIGITAL FLASHCARDS!
1 - List Terms
2 - Add Term
3 - Guess Random Definition
4 - View term-definition pairs
5 - Exit
""")

How to save the users name and last 3 scores to a text file?

I need to write the last three scores of students and their names into a text file for the teacher's program to read and sort later.
I still don't know how to save the last 3 scores
I have tried this so far:
#Task 2
import random
name_score = []
myclass1= open("class1.txt","a")#Opens the text files
myclass2= open("class2.txt","a")#Opens the text files
myclass3= open ("class3.txt","a")#Opens the text files
def main():
name=input("Please enter your name:")#asks the user for their name and then stores it in the variable name
if name==(""):#checks if the name entered is blank
print ("please enter a valid name")#prints an error mesage if the user did not enter their name
main()#branches back to the main fuction (the beggining of the program), so the user will be asked to enter their name again
class_name(name)#branches to the class name function where the rest of the program will run
def class_name(yourName):
try:#This function will try to run the following but will ignore any errors
class_no=int(input("Please enter your class - 1,2 or 3:"))#Asks the user for an input
if class_no not in range(1, 3):
print("Please enter the correct class - either 1,2 or 3!")
class_name(yourName)
except:
print("Please enter the correct class - either 1,2 or 3!")#asks the user to enter the right class
class_name(yourName)#Branches back to the class choice
score=0#sets the score to zero
#add in class no. checking
for count in range (1,11):#Starts the loop
numbers=[random.randint (1,11),
random.randint (1,11)]#generates the random numbers for the program
operator=random.choice(["x","-","+"])#generates the random operator
if operator=="x":#checks if the generated is an "x"
solution =numbers[0]*numbers[1]#the program works out the answer
question="{0} * {1}=".format(numbers[0], numbers [1])#outputs the question to the user
elif operator=="+":#checks if the generated operator is an "+"
solution=numbers[0]+numbers[1]#the program works out the answer
question="{0} + {1}=".format(numbers[0], numbers [1])#outputs the question to the user
elif operator=="-":
solution=numbers[0]-numbers[1]#the program works out the answer
question="{0} - {1}=".format(numbers[0], numbers [1])#outputs the question to the user
try:
answer = int(input(question))
if answer == solution:#checks if the users answer equals the correct answer
score += 1 #if the answer is correct the program adds one to the score
print("Correct! Your score is, {0}".format(score))#the program outputs correct to the user and then outputs the users score
else:
print("Your answer is not correct")# fail safe - if try / else statment fails program will display error message
except:
print("Your answer is not correct")#if anything else is inputted output the following
if score >=5:
print("Congratulations {0} you have finished your ten questions your total score is {1} which is over half.".format(yourName,score))#when the user has finished there ten quetions the program outputs their final score
else:
print("Better luck next time {0}, your score is {1} which is lower than half".format(yourName,score))
name_score.append(yourName)
name_score.append(score)
if class_no ==1:
myclass1.write("{0}\n".format(name_score))
if class_no ==2:
myclass2.write("{0}\n".format(name_score))
if class_no ==3:
myclass3.write("{0}\n".format(name_score))
myclass1.close()
myclass2.close()
myclass3.close()
Your program seems to be working just fine now.
I've re-factored your code to follow the PEP8 guidelines, you should really try to make it more clear to read.
Removed the try/except blocks, not needed here. Don't use try/except without a exception(ValueError, KeyError...). Also, use with open(...) as ... instead of open/close, it will close the file for you.
# Task 2
import random
def main():
your_name = ""
while your_name == "":
your_name = input("Please enter your name:") # asks the user for their name and then stores it in the variable name
class_no = ""
while class_no not in ["1", "2", "3"]:
class_no = input("Please enter your class - 1, 2 or 3:") # Asks the user for an input
score = 0
for _ in range(10):
number1 = random.randint(1, 11)
number2 = random.randint(1, 11)
operator = random.choice("*-+")
question = ("{0} {1} {2}".format(number1,operator,number2))
solution = eval(question)
answer = input(question+" = ")
if answer == str(solution):
score += 1
print("Correct! Your score is, ", score)
else:
print("Your answer is not correct")
print("Congratulations {0}, you have finished your ten questions!".format(your_name))
if score >= 5:
print("Your total score is {0} which is over half.".format(score))
else:
print("Better luck next time {0}, your score is {1} which is lower than half".format(your_name, score))
with open("class%s.txt" % class_no, "a") as my_class:
my_class.write("{0}\n".format([your_name, score]))
main()

Python 3.x - If quitting program, at the y/n conditional how do I make the no answer go back to the start of program?

I'm trying to create a high scores program. It has to be able to do the following:
1. Display the names / scores
2. Add a name / score
3. Delete a name / score
4. Sort list ascending
5. Sort list descending
6. Quit option < this is where I'm having an issue
I can't figure out how to make the y/n quit conditional at the end go back to the start of the program.
import sys
#declaring variables
choice = int()
name = str()
score = int()
entry = (name, score)
scores = [("Moe", 1000), ("Larry", 1500), ("Curly", 3000), ("Mirza", 9000), ("George", 100)]
#asking user to choose
print ("Please enter your choice.")
print ("0 = quit, 1 = List players and scores, 2 = Add more scores, 3 = Delete score, 4 = sort ascending, 5 = sort descending")
choice = input()
if choice == "1":#this lists the already pre-defined list
for entry in scores:
name, score = entry
print (name, "\t", score)
elif choice == "2":#this adds a name / score to the list
print("What is the player's name?")
name = input()
print("What score did the player get?")
score = int(input())
entry = (name, score)
scores.append(entry)
print(scores)
elif choice == "3":#this deletes a name / score from the list
print("What is the player's name you wish to delete?")
name = input()
print("What is said players score?")
score = int(input())
entry = (name, score)
scores.remove(entry)
print(scores)
elif choice == "4":#this sorts in ascending order
scores.sort()
print(scores)
elif choice == "5":#this sorts in descending order
scores.sort(reverse = True)
print(scores)
else:#here is a conditional y/n statement to quit program
print("Are you sure you want to quit? Please enter y for yes and n for no")
response = input().lower()
if response == "y":
sys.exit(0)
## elif response == "n":
###How do I make the N conditional go back to the start of the program???? I can't figure this out.
You will definitely need a loop of some kind. This could work for you:
while True:
# do some stuff
if (want_to_go_to_start_early):
continue # Go back to the start of the loop
if (want_to_exit_loop):
break # Exit the loop
# do other stuff in the loop
# at the end of the loop it goes back to the top
# stuff outside the loop (only gets reached after the 'break')
You can simply do:
exit = ''
while( exit != 'yes' ):
menu() # print menu
in menu you if exit will get set to 'yes' program ( loop ) will end.
So you can have choice like - Exit program? where you set exit to 'yes', and you can aswell ask for confirmation.
A slightly different take on the problem would be to recursivly call your main sequence again on the "no" condition and return on the "yes" condition.
def main():
#do stuff
if(condition == 'y'):
return;
else:
main();
your going to need to enclose your main program in a loop like:
def display_menu():
start_over=False
print ("Please enter your choice.")
print ("0 = quit, 1 = List players and scores, 2 = Add more scores, 3 = Delete score, 4 = sort ascending, 5 = sort descending")
choice = input()
if choice == "1":#this lists the already pre-defined list
...
....
....
if choice == "0":
start_over=True
return start_over
while true:
play_game()
...
...
start_over_flag=display_menu()
if not start_over_flag:
break
sys.exit()
Read up on looping mechanisms and functions in the python documentation. The Docs will become your best friend these next few months.
make sure you are reading the right version (I linked you the latest, but you may be using 2.7 instead of 3.x)

Categories