Rietowet
Rietowet

Reputation: 23

A user score saving program

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

Answers (3)

Reut Sharabani
Reut Sharabani

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:

  1. Load the serialized results object from the score file (dict)
  2. update the score dict (add key / update value of key)
  3. write the updated 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:

  1. Read the serialized 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]

Bonus - Closures:

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

Igor Hatarist
Igor Hatarist

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

Marcus Müller
Marcus Müller

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

Related Questions