0

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.")

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

So does the second part go after "if users_class == 1:" and replace what was there before? or does it only replace 'class1 = open("Class1.txt", "a+")'. Im sorry for bothering you but im very new to coding.
1

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.

2 Comments

does this all go before the test function?
the defs can go anywhere before you use the update_user_score function. Put them at the top if you like. Then, remove everything at the end starting with "if users_class == 1:" replace it with: update_user_score(users_class, username, correct_answers)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.