Skip to content

Instantly share code, notes, and snippets.

@jamesoff
Created September 23, 2018 18:06
Show Gist options
  • Save jamesoff/0a197643eb1bdb7f7382e3352ee04a74 to your computer and use it in GitHub Desktop.
Save jamesoff/0a197643eb1bdb7f7382e3352ee04a74 to your computer and use it in GitHub Desktop.
maths challenge practice
#!/usr/local/bin/python
"""Ask complicated maths questions."""
__revision__ = 1
import sys
import random
import operator
import time
from math import log10
from datetime import datetime
from optparse import OptionParser
CORRECT_QUESTIONS = []
INCORRECT_QUESTIONS = []
def ask_question(maximum, operations, precision):
"""Ask a maths question and check the answer."""
first_num = second_num = 0
precision = 0 - precision
while first_num == second_num:
first_num = random.randint(0, maximum)
first_num = round(first_num, precision)
if first_num == 0:
lower_limit = 1
else:
lower_limit = 0
second_num = random.randint(lower_limit, maximum)
second_num = round(second_num, precision)
operation = random.choice(operations)
if operation == "-" and (second_num > first_num):
#avoid negative results for now
(first_num, second_num) = (second_num, first_num)
if operation == "-":
answer = first_num - second_num
else:
answer = first_num + second_num
start_time = datetime.now()
while True:
try:
response = raw_input("%d %s %d = " % (first_num, operation, second_num))
end_time = datetime.now()
difference = end_time - start_time
if int(response) == answer:
CORRECT_QUESTIONS.append((first_num, operation, second_num, answer, difference))
return True
else:
print "Incorrect; %d %s %d = %d" % (first_num, operation, second_num, answer)
countdown("Learn from your mistake", 3, "and continue!")
INCORRECT_QUESTIONS.append((first_num, operation, second_num, answer, response, difference))
return False
except ValueError:
print "Invalid input, try again."
def interactive():
"""Ask user for parameters."""
limit = raw_input("Enter highest number to use: ")
limit = int(limit)
if limit < 5:
sys.exit("Choose a higher number!")
operations = raw_input("Addition, subtraction, or both [asb]: ")
if not operations in ("a", "s", "b"):
sys.exit("Enter a, s or b!")
if operations == "a":
operations = ("+")
elif operations == "s":
operations = ("-")
elif operations == "b":
operations = ("+", "-")
count = raw_input("Number of questions to ask (0 for infinite): ")
count = int(count)
precision = raw_input("Precision (i.e. number of digits to round to): ")
precision = int(precision)
run_quiz(limit, operations, count, precision)
def sensible_timedelta(timedelta):
"""Convert a timedelta into minutes and seconds."""
minutes = timedelta.seconds / 60
if minutes > 0:
seconds = timedelta.seconds
seconds -= (minutes * 60)
return "%dmin %0.1fs" % (minutes, (seconds + (timedelta.microseconds / 1000000.0)))
else:
return "%0.1fs" % (timedelta.seconds + (timedelta.microseconds / 1000000.0))
def countdown(first_message, seconds, end_message):
"""Countdown until we start the quiz."""
timer = seconds
print first_message,
while timer > 0:
print timer,
sys.stdout.flush()
time.sleep(1)
timer -= 1
print end_message + "\n"
def run_quiz(limit, operations, count, precision):
"""Ask the right number of questions."""
#sanity check
if round(log10(limit)) < precision + 1:
sys.exit("Error: precision cannot be higher than length of numbers in use, try %d" % (round(log10(limit)) - 1))
total = 0
correct = 0
_count = count
if count == 0:
infinite = True
print "Hit Ctrl-D to stop"
else:
infinite = False
countdown("Get ready...", 5, "GO!")
start_time = datetime.now()
while count > 0 or infinite:
try:
total += 1
if ask_question(limit, operations, precision):
correct += 1
except EOFError:
total -= 1
break
count -= 1
end_time = datetime.now()
difference = end_time - start_time
print "All done."
option = raw_input("Display detailed results or summary [ds]: ")
if option == "s":
detailed = False
else:
detailed = True
display_results(difference, _count, detailed)
def display_results(timetaken, count, detailed):
"""Output results and times."""
if detailed:
print
if len(CORRECT_QUESTIONS) > 0:
print "Correct answers:"
correct_sorted = sorted(CORRECT_QUESTIONS, key=operator.itemgetter(4))
for (first_num, operation, second_num, answer, difference) in correct_sorted:
print "%2d %s %-2d = %-2d (%s)" % (first_num, operation, second_num, answer, sensible_timedelta(difference))
if len(INCORRECT_QUESTIONS) > 0:
print "Incorrect answers:"
for ((first_num, operation, second_num, answer, response, difference)) in INCORRECT_QUESTIONS:
print "%2d %s %-2d = %-2d [%2d]" % (first_num, operation, second_num, answer, int(response))
print "\n%d correct out of %d questions (%d%%)." % (len(CORRECT_QUESTIONS), len(CORRECT_QUESTIONS) + len(INCORRECT_QUESTIONS), (len(CORRECT_QUESTIONS) / float(count) * 100))
print " Total time: %s" % (sensible_timedelta(timetaken))
print "Average time: %0.1fs" % ((timetaken.seconds + (timetaken.microseconds / 1000000.0)) / float(count))
def main():
"""Figure out if we should ask for parameters and run quiz."""
if len(sys.argv) == 1:
interactive()
else:
parser = OptionParser()
parser.set_defaults(ops="b", maximum="10", count="10", precision=0)
parser.add_option("-m", "--max", dest="maximum", help="maximum value to use in question")
parser.add_option("-c", "--count", dest="count", help="number of questions to ask (infinite if not given)")
parser.add_option("-o", "--operations", dest="ops", help="question type; (a)ddition, (s)ubtraction, (b)oth", type="choice", choices=("a", "s", "b"))
parser.add_option("-p", "--precision", dest="precision", help="precision: 1475 = 1000 (3), 1500 (2), 1480 (1), etc")
(options, args) = parser.parse_args()
if options.ops == "a":
operations = ("+")
elif options.ops == "s":
operations = ("-")
elif options.ops == "b":
operations = ("+", "-")
run_quiz(int(options.maximum), operations, int(options.count), int(options.precision))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment