Pickle in Python - python

How do you save and load a variable using pickle? I am trying to save and load a high score from a trivia game. Here is the relevant code:
high_scorz=open_file("high.dat", "wb+")
high = 0
try:
high=pickle.load(high_scorz)
except EOFError:
print("EOF ERROR!!!!")
finally:
print("NO DATA RECEIVED")
# later in the code when score has been updated
if score > high:
pickle.dump(score, high_scorz)
high = score
trivia_file.close()
high_scorz.close()
print("High Scorz: " + str(high))
The problem is every time score and high are equal. high = 0 every time because every time I receive a end of file error. Therefor when I run the final print statement it always prints the current score.
Heres all of the code if you want it:
# Trivia Challenge
# Trivia game that reads a plain text file
import pickle
import sys
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
question = next_line(the_file)
answers = []
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
points = next_line(the_file)
explanation = next_line(the_file)
return category, question, answers, correct, points, explanation
def welcome(title):
"""Welcome the player and get his/her name."""
print("\t\tWelcome to Trivia Challenge!\n")
print("\t\t", title, "\n")
def main():
trivia_file = open_file("trivia.txt", "r")
high_scorz=open_file("high.dat", "wb+")
high = 0
try:
high=pickle.load(high_scorz)
except EOFError:
print("EOF ERROR!!!!")
finally:
print("NO DATA RECEIVED")
title = next_line(trivia_file)
welcome(title)
score = 0
# get first block
category, question, answers, correct, points, explanation = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
for i in range(4):
print("\t", i + 1, "-", answers[i])
# get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nRight!", end=" ")
score += int(points)
else:
print("\nWrong.", end=" ")
print(explanation)
print("Score:", score, "\n\n")
# get next block
category, question, answers, correct, points, explanation = next_block(trivia_file)
print("That was the last question!")
print("You're final score is", score)
if score > high:
pickle.dump(score, high_scorz)
high = score
trivia_file.close()
high_scorz.close()
print("High Scorz: " + str(high))
main()
input("\n\nPress the enter key to exit.")

If you open with a w mode, you overwrite any previous data. It would be easier to open the file twice:
filename = "high.dat"
with open(filename) as high_scores:
try:
high_score = pickle.load(high_scores)
except Exception:
print("No data loaded")
high_score = 0
# later in the code when score has been updated
if score > high_score:
with open(filename, 'w') as high_scores:
pickle.dump(score, high_scores)
high_score = score

Related

How to create a simple ordered leaderboard for top 5 players in a text file for a one player game

I'm making a 1 player quiz and need to implement a high score system that records the score of the top 5 highscorers and the player names appropriate to the scorer. This should be written to a text file (.txt) and overwritten if the score is higher (sorted from 1. highest score to 5. lowest score). If someone could share some code I could use for my highscore system that would be really helpful.
The players that get through n rounds should be ordered from highest n score to lowest n score. It should have the top 5 n scores in a txt file, ordered.
I've looked at loads of forums for hours and was unable to implement codes I found into my code. Side note: I don't know how to do this at all
counter = 0
print("The songs' initials are " ,initialsofsong, " and the name of the artist is " ,randomartist)
print (randomsong)
songnameguess = input("Guess the name of the song!")
counter = counter + 1
while counter < 3 and songnameguess != randomsong :
songnameguess = input("Nope! Try again!")
counter = counter + 1
if songnameguess == randomsong:
print ("Well done!")
if counter == 2:
score = score + 1
elif counter == 1:
score = score + 3
elif counter >=3 and songnameguess != randomsong:
print ("Sorry, you've had two chances. Come back soon!")
print ("Game over.")
print (score)
You could store the score in many formats, I'll go for json since it is readable and builtin:
score_file = r"/pat/to/score/file.json"
# at the beginning of your script: load the current scores
try:
with open(score_file, 'r') as f:
scores = json.load(f)
except FileNotFoundError:
scores = {}
# (...)
# during your script: update the scores with the player's new
scores[player_name] = new_score
# (...)
# at the end of your script: store the new scores
with open(score_file, 'w+') as f:
json.dump(scores, f)
To print your scores sorted:
scores_sorted = sorted([(p, s) for p, s in scores.items()], reverse=True, key=lambda x: x[1])
for player, score in scores_sorted:
print(player, score)
You could implement a class like this (if multiple users have the same score then they are all on the highscore, see example):
import json
class Highscore:
def __init__(self):
self.highscores = None
self.load()
def load(self):
"""Loads highscores from a file called 'highscores.txt'"""
try:
with open('highscores.txt', 'r') as handle:
text = handle.read()
if text:
self.highscores = json.loads(text)
return
except FileNotFoundError:
pass
self.highscores = {}
def update(self, name, score):
"""Update current highscore for user and keep only top 5 users"""
self.highscores[name] = max(score, self.highscores.get(name, 0))
self.highscores = {n: s for n, s in self.highscores.items()
if s in sorted(self.highscores.values(), reverse=True)[:5]}
def save(self):
"""Saves highscores to a file called 'highscores.txt'"""
with open('highscores.txt', 'w') as handle:
json.dump(self.highscores, handle)
def clear(self):
"""Remves highscores (in memory, save is needed to clear record)"""
self.highscores = {}
def __str__(self):
"""Return highscores as a string"""
return '\n'.join(
f'{name}: {score}'
for name, score in
sorted(self.highscores.items(), key=lambda x: x[1], reverse=True)
) or 'No highscores!'
Example:
import random
highscores = Highscore() # Loads the current highscores
highscores.clear() # Removes them
highscores.save() # Saves to file
highscores.load() # Loads from file again (to make sure save worked)
print(highscores) # prints: "No highscores!"
# Generate random scores:
for i in range(10):
highscores.update(f'name{i}', random.randint(10, 100))
print(highscores)
# prints:
# name9: 94
# name8: 79
# name1: 62
# name6: 57
# name0: 48 Same score as below so both are kept...
# name4: 48 Same score as above so both are kept...

python trivia game error

Trying to have a game where each question has a unique value associated to it. The player's score is then the total number of points of the questions she or he answers correctly. Been fiddling with it but I keep running into these errors :
code:
# Trivia Challenge
# Trivia game that reads a plain text file
import sys
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
point_value = 0
question = next_line(the_file)
answers = []
answers.append(next_line(the_file))
if( answers[0]=="True\n"):
answers.append(next_line(the_file))
else:
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
point_value = (int)(next_line(the_file).strip())
explanation = next_line(the_file)
return category, question, answers, correct, explanation, point_value
def welcome(title):
"""Welcome the player and get his/her name."""
print("\t\tWelcome to Trivia Challenge!\n")
print("\t\t", title, "\n")
def main():
trivia_file = open_file("trivia.txt", "r")
title = next_line(trivia_file)
welcome(title)
score = 0
# get first block
category, question, answers, correct, explanation, point_value = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
i=0
for a in answers:
print ("\t", i + 1, "-", a)
i = i + 1 # get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nRight!", end=" ")
score += 1
else:
print("\nWrong.", end=" ")
print(explanation)
print("Score:", score, "\n\n")
# get next block
category, question, answers, correct, explanation, score, point_value = next_block(trivia_file)
trivia_file.close()
print("That was the last question!")
print("You're final score is", score)
main()
input("\n\nPress the enter key to exit.")
not sure why it's having these errors/why its not running - suggestions? ty!
this is connected to a seperate .txt file named "trivia.txt" with all the questions and points.
Most likely the error is occurring because your text file contains unicode characters. You can add the encoding parameter to the open call to tell python that it isn't in the default ascii encoding.
the_file = open(file_name, mode, encoding='utf-8')
If this doesn't work, it may be because the file is using a different encoding such as 'iso-8859-15'.
The Python documentation Unicode-HOWTO has more details about dealing with Reading and Writing Unicode Data.

Michael Dawson's trivia game assignment

Please help me to understand what I'm doing wrong.
I'm getting error
NameError: name 'name' is not defined
Regardless function welcome returns name.
Here's the code.
import sys, pickle, shelve
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
question = next_line(the_file)
answers = []
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
score = next_line(the_file)
explanation = next_line(the_file)
return category, question, answers, correct, score, explanation
def welcome(title):
"""Welcome the player and get his/her name."""
print("\t\tWelcome to Trivia Challenge!\n")
print("\t\t", title, "\n")
name = input('Enter your name')
return name
def pic_save(name, final_score):
records = {name: final_score}
f = open('pickles.dat', 'ab')
pickle.dump(records, f)
return records
def pic_read():
f = open("pickles.dat", "rb")
records = pickle.load(f)
print(records)
f.close()
def main():
trivia_file = open_file("7.1.txt", "r")
title = next_line(trivia_file)
welcome(title)
final_score = 0
# get first block
category, question, answers, correct, score, explanation = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
for i in range(4):
print("\t", i + 1, "-", answers[i])
# get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nRight!", end=" ")
final_score += int(score)
print("Score:", score, "\n\n")
else:
print("\nWrong.", end=" ")
print(explanation)
# get next block
category, question, answers, correct, score, explanation = next_block(trivia_file)
trivia_file.close()
pic_save(name, final_score)
print("That was the last question!")
print("You're final score is", final_score)
pic_read()
main()
input("\n\nPress the enter key to exit.")
Probably what you want to do is assign the return value of welcome to a variable named name, otherwise the return value is lost.
name = welcome(title)

Python for absolute beginners chapter 7 challenge 2

I am currently working through the python for absolute beginners 3rd addition. I am struggling with the 2nd challenge in the 7th chapter of the book, as i keep getting an error i don't understand.
The challenge is to:
"improve triva challenge game so that it maintains a high score list in a file. The program should records the player's name and score if the player makes the list. store the high scores using a pickled object."
The original code
# Trivia Challenge
# Trivia game that reads a plain text file
import sys
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
question = next_line(the_file)
answers = []
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
explanation = next_line(the_file)
return category, question, answers, correct, explanation
def welcome(title):
"""Welcome the player and get his/her name."""
print("\t\tWelcome to Trivia Challenge!\n")
print("\t\t", title, "\n")
def main():
trivia_file = open_file("trivia.txt", "r")
title = next_line(trivia_file)
welcome(title)
score = 0
# get first block
category, question, answers, correct, explanation = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
for i in range(4):
print("\t", i + 1, "-", answers[i])
# get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nRight!", end=" ")
score += 1
else:
print("\nWrong.", end=" ")
print(explanation)
print("Score:", score, "\n\n")
# get next block
category, question, answers, correct, explanation = next_block(trivia_file)
trivia_file.close()
print("That was the last question!")
print("You're final score is", score)
main()
input("\n\nPress the enter key to exit.")
my attempt at the challenge code
# Trivia Challenge
# Trivia game that reads a plain text file
import sys, pickle
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
points = next_line(the_file)
question = next_line(the_file)
answers = []
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
explanation = next_line(the_file)
return category, points, question, answers, correct, explanation
def welcome(title):
"""Welcome the player and get his/her name."""
print("\t\tWelcome to Trivia Challenge!\n")
print("\t\t", title, "\n")
def high_scores():
global score
value = int(score)
name = input("What is your name? ")
entry = (value, name)
f = open("high_scores.dat", "wb+")
high_scores = pickle.load(f)
high_scores.append(entry)
high_scores = high_scores[:5]
print("High Scores\n")
print("NAME\tSCORE")
for entry in high_scores:
value, name = entry
print(name, "\t", value)
pickle.dump(high_scores, f)
f.close()
def main():
trivia_file = open_file("trivia.txt", "r")
title = next_line(trivia_file)
welcome(title)
# get first block
category, points, question, answers, correct, explanation = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
for i in range(4):
print("\t", i + 1, "-", answers[i])
# get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nRight!", end=" ")
j = int(points)
global score
score += j
else:
print("\nWrong.", end=" ")
print(explanation)
print("Score:", score, "\n\n")
# get next block
category, points, question, answers, correct, explanation = next_block(trivia_file)
trivia_file.close()
print("That was the last question!")
print("You're final score is", score)
high_scores()
score = 0
main()
input("\n\nPress the enter key to exit.")
And the wonderfully confusing error
Traceback (most recent call last):
File "C:\Users\Cheyne\Desktop\Python\chapter07\Challenges\temp.py", line 104, in <module>
main()
File "C:\Users\Cheyne\Desktop\Python\chapter07\Challenges\temp.py", line 100, in main
high_scores()
File "C:\Users\Cheyne\Desktop\Python\chapter07\Challenges\temp.py", line 54, in high_scores
high_scores = pickle.load(f)
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError
Can anyone help explain what's going wrong here please? I have been staring at it for days.
You have an "EOFError", which is an "End Of File Error" at line 54.
That's where you try to load the pickle file so, considering that you are not checking that the file actually exists, my guess is that you have no file and get the error.
Either create an initial file by yourself, or check that it exists and is valid before trying to load it.
EDIT: I just noticed that you open the pickle file as "wb+", which means that you open it for writing and try to read it. You're overwriting the file, which becomes zero bytes. If you want to append to the existing file, you should use "a" instead of "w". Again, before loading make sure the file contains valid data.

python: Adding to username

I am fairly new to python and I need to make a program to ask 10 questions, save the score into a file and allow someone to read the scores in from the file.
My problem: I need to check if the person who has done the quiz already has a record in the file, and if so, I need to add their score to the end of their record.
The records should look like this:
name,score,score,score,score,
etc so they can be split using commas.
I am also looking for the simplest answer, not the most efficient. Also, if you could comment the code, it would make it much easier. Here is my code so far:
import random
import math
import operator as op
import sys
import re
def test():
num1 = random.randint(1, 10)
num2 = random.randint(1, num1)
ops = {
'+': op.add,
'-': op.sub,
'*': op.mul,
}
keys = list(ops.keys())
rand_key = random.choice(keys)
operation = ops[rand_key]
correct_result = operation(num1, num2)
print ("What is {} {} {}?".format(num1, rand_key, num2))
while True:
try:
user_answer = int(input("Your answer: "))
except ValueError:
print("Only enter numbers!")
continue
else:
break
if user_answer != correct_result:
print ("Incorrect. The right answer is {}".format(correct_result))
return False
else:
print("Correct!")
return True
print("1. Are you a student?")
print("2. Are you a teacher?")
print("3. Exit")
while True:
try:
status = int(input("Please select an option:"))
except ValueError:
print("Please enter a number!")
else:
if status not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
if status == 1:
username=input("What is your name?")
while not re.match("^[A-Za-z ]*$", username) or username=="":
username=input(str("Please enter a valid name (it must not contain numbers or symbols)."))
print ("Hi {}! Wellcome to the Arithmetic quiz...".format(username))
while True:
try:
users_class = int(input("Which class are you in? (1,2 or 3)"))
except ValueError:
print("Please enter a number!")
else:
if users_class not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
correct_answers = 0
num_questions = 10
for i in range(num_questions):
if test():
correct_answers +=1
print("{}: You got {}/{} {} correct.".format(username, correct_answers, num_questions,
'question' if (correct_answers==1) else 'questions'))
if users_class == 1:
class1 = open("Class1.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class1.write(newRecord)
class1.close()
elif users_class == 2:
class2 = open("Class2.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class2.write(newRecord)
class2.close()
elif users_class == 3:
class3 = open("Class3.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class3.write(newRecord)
class3.close()
else:
print("Sorry, we can not save your data as the class you entered is not valid.")
EDIT:
Add this function before your "test" function:
def writeUserScore(file, name, score):
with open (file, "r") as myfile:
s = myfile.read()
rows = s.split("\n")
data = {}
for row in rows:
tmp = row.split(",")
if len(tmp) >= 2: data[tmp[0]] = tmp[1:]
if name not in data:
data[name] = []
data[name].append(str(score))
output = ""
for name in data:
output = output + name + "," + ",".join(data[name]) + "\n"
handle = open(file, "w+")
handle.write(output)
handle.close()
After that, where you have "if users_class == 1:" do this:
writeUserScore("Class1.txt", username, str(correct_answers))
Do the same for the other two else ifs.
Let me know what you think!
Try using a dictionary to hold the existing file data.
Read the file in a variable called "str" for example. And then do something like this:
rows = str.split("\n")
data1 = {}
for row in rows:
tmp = row.split(",")
data1[tmp[0]] = tmp[1:]
When you have a new score you should then do:
if username not in data1:
data1[username] = []
data1[username] = str(correct_answers)
And to save the data back to the file:
output = ""
for name in data1:
output = outupt + name + "," + ",".join(data1[name]) | "\n"
And save the contents of "output" to the file.
PS: If you are not bound by the file format you can use a JSON file. I can tell you more about this if you wish.
Hope that helps,
Alex
First, define these functions:
from collections import defaultdict
def read_scores(users_class):
"""
If the score file for users_class does not exist, return an empty
defaultdict(list). If the score file does exist, read it in and return
it as a defaultdict(list). The keys of the dict are the user names,
and the values are lists of ints (the scores for each user)
"""
assert 0 <= users_class <= 3
result = defaultdict(list)
try:
lines =open("Class%d.txt"%users_class,'r').readlines()
except IOError:
return result
for line in lines:
# this line requires python3
user, *scores = line.strip().split(',')
# if you need to use python2, replace the above line
# with these two lines:
# line = line.strip().split(',')
# user, scores = line[0], line[1:]
result[user] = [int(s) for s in scores]
return result
def write_scores(users_class, all_scores):
"""
Write user scores to the appropriate file.
users_class is the class number, all scores is a dict kind of dict
returned by read_scores.
"""
f = open("Class%d.txt"%users_class,'w')
for user, scores in all_scores.items():
f.write("%s,%s\n"%(user, ','.join([str(s) for s in scores])))
def update_user_score(users_class, user_name, new_score):
"""
Update the appropriate score file for users_class.
Append new_score to user_name's existing scores. If the user has
no scores, a new record is created for them.
"""
scores = read_scores(users_class)
scores[user_name].append(new_score)
write_scores(users_class, scores)
Now, in the last portion of your code (where you actually write the scores out) becomes much simpler. Here's an example of writing some scores:
update_user_score(1, 'phil', 7)
update_user_score(1, 'phil', 6)
update_user_score(1, 'alice', 6)
update_user_score(1, 'phil', 9)
there will be two lines in Class1.txt:
phil,7,6,9
alice,6
We read the whole file into a dict (actually a defaultdict(list)),
and overwrite that same file with an updated dict. By using defaultdict(list), we don't have to worry about distinguishing between updating and adding a record.
Note also that we don't need separate if/elif cases to read/write the files. "Scores%d.txt"%users_class gives us the name of the file.

Categories