Reputation: 23
I am trying to make a program where the it will ask the user's name and then a series of questions. With a point added for every time the question is correct. I am trying to make it store the score along with the user's name onto a text file so it will look like so on the text file:
Name Score
so let's use John as an example, if he were to score 4 points, in the text file it would write:
John 4
But I want it so that if John were to take the test again instead of having John twice:
John 4
John 6
I want it to read:
John 4 6
Instead of rewriting the name and score, it would write tab and then the score onto the same line as the one with the name John in.
Here is my code so far:
import random
name = input("Hello user, what is your name?")
count = (0)
score = (0)
while count != (8):
count = count + (1)
symbols = ['+', '-', '*']
valueF = random.randint(1,10)
valueS = random.randint(1,10)
chosensymb = random.choice (symbols)
question = input("What is %d %s %d ? :"%(valueF, chosensymb, valueS))
answer = eval(str(valueF) + chosensymb + str(valueS))
if question == str(answer):
score = score + (1)
print ("Correct")
else:
print ("Incorrect")
print("%s, you have scored %d points"%(name,score))
filewrite = open("ScoreSheet.txt","a")
filewrite.write("\n%s\t%d"%(name,score))
filewrite.close()
I have no idea how to do this, I am new to python so sorry if I made any mistakes, thanks!
Upvotes: 1
Views: 2417
Reputation: 31339
Just serialize your data using pickle
or json
. Here is an example using json
to serialize the scores (storing scores in a dict
- a mapping between a name and a score):
# import the serializing library
import json as serializer
Now we'll make a function to write a score to a given file:
def write_score(score_file_name, name, score):
scores = read_scores(score_file_name)
# add score
scores[name] = score
with open(score_file_name, 'w') as f:
serializer.dump(scores, f)
What it does is:
dict
)dict
(add key / update value of key)dict
to the file (using json.dump
)When writing the write_score
function, we were missing a read_scores
function, that enables us to see what the current scores are. So let's write this read_scores
:
def read_scores(score_file_name):
try:
with open(score_file_name, 'r') as f:
scores = serializer.load(f)
return scores
except IOError:
# if file does not exist - we have no scores
return {}
What read_scores
does is:
dict
(using json.load
)Now we can test if it actually works. Here is a small example:
# set the score file name
SCORES_FILE_NAME = 'scores.txt'
write_score(SCORES_FILE_NAME, 'john', 10)
print(read_scores(SCORES_FILE_NAME))
write_score(SCORES_FILE_NAME, 'jim', 11)
print(read_scores(SCORES_FILE_NAME))
# overwrite john's score
write_score(SCORES_FILE_NAME, 'john', 12)
print(read_scores(SCORES_FILE_NAME))
Tip 1: You may want to use name.lower()
when writing a score so that john
and John
are considered the same user.
Tip 2: Because we referenced the json
library as serializer
, and it has the same API as pickle
, you can choose between the two simply by replacing import json as serializer
to import pickle as serializer
. Just make sure you delete the scores file since they don't serialize data the same way.
The whole code together:
# import the serializing library
import json as serializer
def write_score(score_file_name, name, score):
scores = read_scores(score_file_name)
# add score
scores[name] = score
with open(score_file_name, 'w') as f:
serializer.dump(scores, f)
def read_scores(score_file_name):
try:
with open(score_file_name, 'r') as f:
scores = serializer.load(f)
return scores
except IOError:
# if file does not exist - we have no scores
return {}
# TESTS
# set the score file name
SCORES_FILE_NAME = 'scores.txt'
write_score(SCORES_FILE_NAME, 'john', 10)
print(read_scores(SCORES_FILE_NAME))
write_score(SCORES_FILE_NAME, 'jim', 11)
print(read_scores(SCORES_FILE_NAME))
# overwrite john's score
write_score(SCORES_FILE_NAME, 'john', 12)
print(read_scores(SCORES_FILE_NAME))
Output:
{u'john': 10}
{u'john': 10, u'jim': 11}
{u'jim': 11, u'john': 12}
To read a specific score you can use the existing method read_scores
:
def read_score(score_file_name, name):
return read_scores(score_file_name)[name]
You can make the functions specific to a file if you understand closures, the following way:
def write_score(score_file_name):
# create closure specific to 'score_file_name'
def write_score_specific(name, score):
scores = read_scores(score_file_name)
# we're going to make a 'read_scores' with closures as well!
# so use that one...
scores_reader = read_scores(score_file_name)
scores = scores_reader()
# add score
scores[name] = score
with open(score_file_name, 'w') as f:
serializer.dump(scores, f)
# return file-specific function
return write_score_specific
Now, we only have to call the function with the file name argument once, and from that moment we can use the result ot write scores:
# create specific 'write_score' for our file
score_txt_writer = write_score('scores.txt')
# update john's score to 10 without specifying the file
score_txt_writer('john', 10)
The same done with read_score
:
def read_scores(score_file_name):
# create closure function
def read_scores_specific():
try:
with open(score_file_name, 'r') as f:
scores = serializer.load(f)
return scores
except IOError:
# if file does not exist - we have no scores
return {}
return read_scores_specific
The whole code with closures together:
# import the library
import serializer
# CLOSURES
SCORES_FILE = 'scores.txt'
def read_scores(score_file_name):
# create closure function
def read_scores_specific():
try:
with open(score_file_name, 'r') as f:
scores = serializer.load(f)
return scores
except IOError:
# if file does not exist - we have no scores
return {}
return read_scores_specific
def write_score(score_file_name):
# create closure specific to 'score_file_name'
def write_score_specific(name, score):
scores_reader = read_scores(score_file_name)
scores = scores_reader()
# add score
scores[name] = score
with open(score_file_name, 'w') as f:
serializer.dump(scores, f)
# return file-specific function
return write_score_specific
# create specific 'write_score' for our file
score_txt_writer = write_score(SCORES_FILE)
# update john's score to 10 without specifying the file
score_txt_writer('john', 10)
score_txt_reader = read_scores(SCORES_FILE)
print score_txt_reader()
Output:
{u'john': 10}
Upvotes: 3
Reputation: 5442
Well, for a start, you could store everybody's scores in a dictionary.
Let's introduce a scores
object:
scores = {}
It will have the names as the keys and the scores as the values. Like that:
scores = {'John': 2,
'Mary': 5}
If you introduce a new player, we'll create a new element inside the said dictionary, let's call it 'John'
, with a score 0
:
scores['John'] = 0
Then if the player guesses correctly, we increment the player's score:
scores['John'] += 1
(You can use the +=
operator if you'd like to just add something to the object. It's a shorter way of saying scores['John'] = scores['John'] + 1
.
Then the magic kicks in!
There's a builtin module in Python called pickle
, which can store the objects (like the dictionary we've made - scores
) in files and then just pop them out of files and they're being restored!
There's a quick manual on how to work with pickle
. In short, you save the scores into the file like that:
import pickle
pickle.dump(scores, open("scores.p", "wb"))
and then load it like that:
scores = pickle.load(open("scores.p", "rb"))
It's not really the greatest way to store stuff - there are more things like json, csv, sqlite and even manual read/writing, but you'll be OK for now :)
Upvotes: 1
Reputation: 36352
That's not how file access works: In a file, you can't just "insert" new values somewhere, shifting the rest of the file backwards; you can only overwrite characters or rewrite the whole file.
Generally, as long as your file is rather short, you won't notice any performance effect if rewriting the whole file.
Upvotes: 1