Example #1
0
class Game:
    """
    Represents a game instance

    Recommended training questions based on the following
    1) Squaring a number
    2) Multiplying two numbers having the same first n-1 digits and ones digit add up to ten
    3) Multiplying two numbers ending with 1
    4) Multiplication between a range
    """

    def __init__(self):
        self.lower = 0
        self.upper = 100
        self.score = 0
        self.total_questions = 0
        self.current_question = None
        self.history = {}
        self.user_score = None
        self.saved_question = []
        self.start_time = 0
        self.end_time = 0
        self.set_history()
        self.question_generator = None

    def set_history(self):
        """
        Loads history from database
        :return:
        """
        self.user_score = UserData()
        self.user_score.load_or_create_db()
        self.history = self.user_score.db

    def start_timing(self):
        self.start_time = clock()

    def end_timing(self):
        self.end_time = clock()

    def save_current_question(self):
        self.saved_question.append(self.current_question)

    def gen_next_question(self, lower=None, upper=None, op_type_value=None):
        """
        Generate a random question based on the given parameter (if any)
        :param lower:
        :param upper:
        :param op_type_value:int Give the operation value
        :return:
        """

        lower_bound = self.lower if lower is None else lower
        upper_bound = self.upper if upper is None else upper
        op1 = randint(lower_bound, upper_bound)
        op2 = randint(lower_bound, upper_bound)
        if op_type_value is None:
            op_type_value = randrange(len(Operation))
        self.current_question = Question(op1, op_type_value, op2)

    def solve_question(self, user_input):
        """
        Take a user input and check whether it solves the current question
        :param user_input:int
        :return:(is_user_correct, solution, time_taken)
        """
        if self.current_question is None:
            raise NoQuestionException
        time_taken = self.end_time - self.start_time
        solution = eval(self.current_question.query)
        is_user_correct = solution == user_input
        self.total_questions += 1
        if hash(self.current_question) in self.history:
            self.current_question = self.history[hash(self.current_question)]
        if is_user_correct:
            self.score += 1
            self.current_question.add_correct_time(time_taken)
        else:
            self.current_question.add_wrong_time(time_taken)
        self.history[hash(self.current_question)] = self.current_question

        # For displaying purposes
        return is_user_correct, solution, time_taken

    def gen_squares(self, lower, upper):
        """
        Generate a square question between range upper and lower inclusive
        :param lower:
        :param upper:
        :return:
        """
        x = randint(lower, upper)
        self.current_question = Question(x, Operation.MULTIPLICATION.value, x)

    def gen_ones_digit_sum_to_ten(self, upper_bound):
        """
        two numbers having the same first n-1 digits and ones digit add up to ten
        :param upper_bound:
        :return:
        """
        ones = randint(1, 9)
        ones_complement = 10 - ones
        tens1 = randint(1, upper_bound)
        self.current_question = Question(tens1 * 10 + ones, Operation.MULTIPLICATION.value,
                                         upper_bound * 10 + ones_complement)

    def gen_tens_digit_are_the_same(self, upper_bound):
        """
        Generate two numbers with the same first n-1 digits and is <= upperbound
        :param upper_bound:
        :return:
        """
        ones1 = randint(0, 9)
        ones2 = randint(0, 9)
        tens = randint(upper_bound)
        self.current_question = Question(tens * 10 + ones1, Operation.MULTIPLICATION.value, tens * 10 + ones2)

    def gen_numbers_ending_with_one(self, upper_bound):
        """
        Generate two numbers ending with one with the first n-1 digit <= upper_bound
        :param upper_bound:
        :return:
        """
        tens1 = randint(upper_bound)
        tens2 = randint(upper_bound)
        self.current_question = Question(tens1 * 10 + 1, Operation.MULTIPLICATION.value, tens2 * 10 + 1)