Math (aka Maths) Trainer

In this Tutorial I would like to write a short (command line) program to help you to practise your times tables.  The program will ask you a series of questions like, for example, “5×6 =”  which you need to answer.  The time you take will be recorded as well as your score, which will be printed out at the end.

First, I will define a model to store the data that we’ll be using. The model makes an allowance for an upper and lower limit on what is being multiplied together (so you don’t have to answer 1×1=). By default this produces the four through 12 times tables, but that can be changed by nominating different values.

# Brendan Scott
# 19 November 2014

# train user on times tables
# from lowest to highest

from random import shuffle
from time import time

range = xrange
class Model(object):
    def __init__(self, lowest = 4, highest = 12):
        self.lowest = lowest
        self.highest = highest

    def make_guess_list(self,random_order=True, allow_reversals= True, max_questions = None):
        if allow_reversals:
            question_list = [(x, y) for x in range(self.lowest, self.highest + 1)
                                    for y in range(self.lowest, self.highest + 1)]
            question_list = [(x, y) for x in range(self.lowest, self.highest + 1)
                                    for y in range(x, self.highest + 1)]

        if random_order:

        if max_questions is not None:
        return question_list

The model also contains a method for constructing a list of “questions”. Each question is a tuple with two elements. These two elements will be the numbers to be multiplied together. The method has a few parameters:
* random_order determines whether the trainer will ask questions in a random order or in the normal order for a times table (eg all of the four times followed by the five times)
* allow_reversals – this determines whether the trainer will allow both 4×5 and 5×4 or will treat them as the same. This reduces the total number of questions and avoids repetition.
* max_questions: limits the number of questions being asked by chopping questions off the end of the list. This parameter makes more sense when random_order is True.
time.time() is used later…

To this model we add the following interface code:

if __name__ == "__main__":
    m = Model()
    question_list = m.make_guess_list(random_order=True, allow_reversals=False, max_questions=10)
    qn_format = "%sx%s= "  # a x b
    summary_fmt = "You scored %s (%s%%) out of a possible %s.  " \
                  "You took %0.1f seconds in total or %0.2f seconds for each correct answer"
                  # score, percent, possible, time_taken, time per correct

    start = raw_input("Press the enter key to start")
    score = 0

    t1 = time()
    for qn in question_list:
        answer = raw_input(qn_format % (qn))
        if answer.lower() == "q":
        correct_answer = qn[0] * qn[1]
            if int(answer) == correct_answer:
                score += 1
                print ("wrong! (should be %s)" % correct_answer)
            print ("wrong! (should be %s)" % correct_answer)
            # something other than a number has been typed, just ignore it

    t2 = time()

    total_questions = len(question_list)
    percent = int(100.0 * score / total_questions)
    time_taken = t2 - t1
        time_per_correct = float(time_taken) / score
    except(ZeroDivisionError): # if score == 0 (!)
        time_per_correct= time_taken

    fmt_args = (score, percent, total_questions, time_taken, time_per_correct)
    print(summary_fmt % fmt_args)

When this script is run from the command line, a Model is created with default values (4 and 12). A question list is produced which is randomly ordered, does not allow reversals and has at most 10 questions. These values can be changed to suit your needs.
Two template strings are define, the first for asking questions, the second for providing a summary at the end.
The user is asked to press the enter key to begin the test. Before the questions start a time marker (t1) is initialised. After the questions have ended a second time marker is taken (t2). For each of the questions in (the) question_list the question is put to the user. If the user responds with a “q”, the rest of the test is aborted (break) and the summary is printed. Otherwise the answer is either correct (in which case the score is increased by one) or it isn’t (in which case the user is told what the correct answer is. There is a little bit of error checking.

This script could be improved by, for example, keeping track of which questions were wrong (for later practise) and by keeping a leaderboard of results.