Sadly lacking in multi-media bells and whistles. But my daughter actually likes playing with it.
Coded on windows, but no reason it shouldn't work on Linux/OS X. (hopefully the indentation won't be too mangled by usenet. apologies in advance if that is the case) Enjoy. Sample session: D:\user\python>mathtester.py -1 3 -o /+ -r 2 Hello, I am your friendly computer. I have a math quiz for you Problem #1 1 + 2 = 3 Answered: 3. Correct. Problem #2 3 + 3 = 6 Answered: 6. Correct. Congratulations, you got 2 right out of 2 code: ************************************ """ mathtester.py -h for more help . HELPS YOUR KIDS TO LEARN MATH WITH INTERACTIVE PROMPTS. EXAMPLE: Hello, I am windoze, your friendly computer. I have a math quiz for you Problem #0 4 - 3 = 1 Answered: 1. Correct. Problem #1 8 - 6 = 14 Answered:14. Wrong. Correct answer: 2 This will pick two numbers, each between 0 and 10. It will either add or substract them. Any questions with solutions less than zero or greater than 20 will be rejected and re-created. You get this by running it with all defaults. i.e. c:\>python mathtester.py to get something like doing the multiplication of 1 to 3 times 10, run c:\>python mathtester -o * -1 3 -2 10 -H 30 only multiplication '*' will be used, number #1 will be between 0 and 3. number #2 will be between 0 and 10. answers greater than 30 will be rejected. """ import os, sys, optparse, random _module_doc = __doc__ class Writer: """write to file and output to console""" def __init__(self,fout): self.fout = fout def __call__(self,s,echoconsole=True): self.fout.write("\n" + s.replace("\t"," ")) if echoconsole: print s class Worker: fout = None filename = "test.txt" trivial_tolerance_percentage = 40 accepted_operators = "+-*" def formatoptions(self): """most of the work is already done by optparser""" #filter on acceptable operators. exit if none found. self.operators = [i for i in self.options.operators if i in self.accepted_operators] if not self.operators: print ERROR_MSG_OPERATORS % {"supported" : self.accepted_operators} sys.exit() #both number range limits are equal. if not self.options.numberRange2: self.options.numberRange2 = self.options.numberRange def __init__(self): self.fout = open(self.filename,"w") Worker.writer = Writer(self.fout) self.formatoptions() self.asked = self.correct = 0 self.set_asked = set() def process(self): """main loop - prints greetings, loops on questions, print result summary and exits""" try: self.writer(GREETING) [self.doTest(cntr) for cntr in range(0,self.options.repetitions)] except KeyboardInterrupt: pass self.writer(FAREWELL % vars(self)) return True def doTest(self,number): """the workhorse function. randomly picks a question + vets the solution then asks the question and checks the answer""" self.writer("\n Problem #%s" % (number+1)) while True: #pick random numbers and operator number1 = random.randint(0,self.options.numberRange) number2 = random.randint(0,self.options.numberRange2) operator = self.operators[random.randint(0,len(self.operators)-1)] if number1 < 2 or number2 < 2 and random.randint(1,100)>self.trivial_tolerance_percentage: #potentially reject trivial problems consisting of zeros and ones. continue #flip a coin and put number #1 either right or left - #remember that the number ranges can be unequal so there is a difference if random.randint(1,2) % 2: problem = "%2s %s %2s" % (number1,operator,number2) else: problem = "%2s %s %2s" % (number2,operator,number1) #use eval to get the expected solution solution = eval(problem) #solution within accepted bounds? if not, build another problem if not ((solution >= self.options.minSolution) and (solution <= self.options.maxSolution)): continue #don't ask the same question multiple times... if problem in self.set_asked: continue self.set_asked.add(problem) #answers other than digits will be ignored and the prompt will repeat while True: try: prompt = "\n\t\t" + problem + " = " self.writer(prompt,False) answer = raw_input(prompt) answer = int("%s" % (answer.strip())) except ValueError: continue break self.asked += 1 #good, or bad, answer? if (answer == solution): msg = GOOD_ANSWER % {"answer":answer} self.correct += 1 else: msg = BAD_ANSWER % locals() self.writer(msg,True) return #not exactly i18n, but it's a start GOOD_ANSWER = "\t\t\t\t\tAnswered:%(answer)2s. Correct." BAD_ANSWER = "\t\t\t\t\tAnswered:%(answer)2s. Wrong. Correct answer:%(solution)s" GREETING = "Hello, I am your friendly computer. I have a math quiz for you" FAREWELL = "\n\nCongratulations, you got %(correct)2s right out of %(asked)2s" HELP_NUMBER1 = "max value for number #1. this keeps things from getting too hard or easy. default:%s" HELP_NUMBER2 = """max value for number #2, defaults to use the same as number #1. the reason you may want to have different ranges is say doing the table of multiplications for 1 to 3 times 10""" HELP_MATH_OPERATORS = "math operators to use/ defaults: %s" HELP_REPETITIONS = "number of questions to ask [%s]" HELP_MIN_SOLUTION = "minimum solution you want [%s]. used to have simple or hard questions" HELP_MAX_SOLUTION = "maximum solution you want [%s]. used to have simple or hard questions" ERROR_MSG_OPERATORS = "no valid operators provided. supported operators: %(supported)s" def getParser(): """use optparse to prompt on the command line""" parser = optparse.OptionParser(usage = _module_doc) default = "10" parser.add_option("-1",action="store",type="int",default=default,dest="numberRange",help=HELP_NUMBER1 % (default)) parser.add_option("-2",action="store",type="int",dest="numberRange2",help=HELP_NUMBER2) default = "+-" parser.add_option("- o",action="store",dest="operators",default=default,help=HELP_MATH_OPERATORS % default) default = "20" parser.add_option("- r",action="store",type="int",dest="repetitions",default=default,help=HELP_REPETITIONS % default) default = "0" parser.add_option("- L",action="store",type="int",dest="minSolution",default=default,help=HELP_MIN_SOLUTION % default) default = "20" parser.add_option("- H",action="store",type="int",dest="maxSolution",default=default,help=HELP_MAX_SOLUTION % default) return parser def main(): worker = success = 0 try: (Worker.options, Worker.args) = getParser().parse_args(sys.argv[1:]) worker = Worker() success = worker.process() finally: if worker and worker.fout: worker.fout.close() if success : os.startfile(Worker.filename) if __name__ == "__main__": main() -- http://mail.python.org/mailman/listinfo/python-list