# Copyright 2008 by Peter Moxhay and Wade Brainerd. # This file is part of Math. # # Math is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Math is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Math. If not, see . from objectarea import ObjectArea, Color from vector import Vector from shapeobject import ShapeObject from symbolobject import SymbolObject from instructionsobject import InstructionsObject from problem import Problem import gtk, math, random class AreaProblem(Problem): """ Generates a problem in which two areas are compared. """ def __init__(self, container, color_scheme, (letter1, letter2) ): self.container = container self.color_scheme = color_scheme self.letter1 = letter1 self.letter2 = letter2 self.problem_number = -1 self.generate_problem() self.show_problem() self.answer = self.find_answer() self.container.moons_visible = False def generate_problem(self): # Choose two random colors. if self.color_scheme == 'red_green': (color1, color2) = random.choice([(Color.RED, Color.GREEN), (Color.GREEN, Color.RED)]) elif self.color_scheme == 'green_blue': (color1, color2) = random.choice([(Color.GREEN, Color.BLUE), (Color.BLUE, Color.GREEN)]) else: (color1, color2) = random.choice([(Color.RED, Color.BLUE), (Color.BLUE, Color.RED)]) # Some regular polygons. SQUARE_SHAPE = [ Vector(0, 0), Vector(250, 0), Vector(250, 250), Vector(0, 250) ] SMALL_SQUARE_SHAPE = self.smaller(SQUARE_SHAPE) LARGE_SQUARE_SHAPE = self.larger(SQUARE_SHAPE) RECTANGLE_SHAPE = [ Vector(0, 0), Vector(400, 0), Vector(400, 200), Vector(0, 200) ] SMALL_RECTANGLE_SHAPE = [ Vector(0, 0), Vector(350, 0), Vector(350, 150), Vector(0, 150) ] LARGE_RECTANGLE_SHAPE = [ Vector(0, 0), Vector(450, 0), Vector(450, 250), Vector(0, 250) ] SMALL_TRIANGLE_SHAPE = [ Vector(0, 0), Vector(250, 0), Vector(0, 250) ] TRIANGLE_SHAPE = [ Vector(0, 0), Vector(300, 0), Vector(0, 300) ] LARGE_TRIANGLE_SHAPE = [ Vector(0, 0), Vector(350, 0), Vector(0, 350) ] SMALL_RT_ANGLE_TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(175, 0), Vector(350, 175), Vector(0, 175) ] RT_ANGLE_TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(200, 0), Vector(400, 200), Vector(0, 200) ] LARGE_RT_ANGLE_TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(225, 0), Vector(450, 225), Vector(0, 225) ] SMALL_TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(125, 0), Vector(250, 125), Vector(-125, 125) ] TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(150, 0), Vector(300, 150), Vector(-150, 150) ] LARGE_TRAPEZOID_SHAPE = [ Vector(0, 0), Vector(175, 0), Vector(350, 175), Vector(-175, 175) ] SMALL_PARALLELOGRAM_SHAPE = [ Vector(-125, 0), Vector(125, 0), Vector(250, 125), Vector(0, 125) ] PARALLELOGRAM_SHAPE = [ Vector(-150, 0), Vector(150, 0), Vector(300, 150), Vector(0, 150) ] LARGE_PARALLELOGRAM_SHAPE = [ Vector(-175, 0), Vector(175, 0), Vector(350, 175), Vector(0, 175) ] # Some irregular polygons. IRREG_TRIANGLE_SHAPE_1 = [Vector(0, -115), Vector(379, -258), Vector(330, 0)] SMALL_IRREG_TRIANGLE_SHAPE_1 = self.smaller(IRREG_TRIANGLE_SHAPE_1) LARGE_IRREG_TRIANGLE_SHAPE_1 = self.larger(IRREG_TRIANGLE_SHAPE_1) IRREG_TRIANGLE_SHAPE_2 = [Vector(0, 0), Vector(70, -158), Vector(367, 57)] SMALL_IRREG_TRIANGLE_SHAPE_2 = self.smaller(IRREG_TRIANGLE_SHAPE_2) LARGE_IRREG_TRIANGLE_SHAPE_2 = self.larger(IRREG_TRIANGLE_SHAPE_2) IRREG_QUADRIATERAL_SHAPE_1 = [Vector(0, 0), Vector(0, -215), Vector(50, -307), Vector (382, -166)] SMALL_IRREG_QUADRIATERAL_SHAPE_1 = self.smaller(IRREG_QUADRIATERAL_SHAPE_1) LARGE_IRREG_QUADRIATERAL_SHAPE_1 = self.larger(IRREG_QUADRIATERAL_SHAPE_1) IRREG_QUADRIATERAL_SHAPE_2 = [Vector(0, -61), Vector(194, -331), Vector(275, -0), Vector (153, -66)] SMALL_IRREG_QUADRIATERAL_SHAPE_2 = self.smaller(IRREG_QUADRIATERAL_SHAPE_2) LARGE_IRREG_QUADRIATERAL_SHAPE_2 = self.larger(IRREG_QUADRIATERAL_SHAPE_2) IRREG_QUADRIATERAL_SHAPE_3 = [Vector(0, -75), Vector(204, -290),Vector(189, -206), Vector(304, -0), Vector (143, -78), Vector (163, -102)] IRREG_PENTAGON_SHAPE_1 = [Vector(0, -183), Vector(53, -300), Vector(213, -328), Vector (350, -173), Vector (154, 0)] SMALL_IRREG_PENTAGON_SHAPE_1 = self.smaller(IRREG_PENTAGON_SHAPE_1) LARGE_IRREG_PENTAGON_SHAPE_1 = self.larger(IRREG_PENTAGON_SHAPE_1) IRREG_PENTAGON_SHAPE_2 = [Vector(0, -123), Vector(150, -186), Vector(175, -311), Vector (382, -145), Vector (215, 0)] SMALL_IRREG_PENTAGON_SHAPE_2 = self.smaller(IRREG_PENTAGON_SHAPE_2) LARGE_IRREG_PENTAGON_SHAPE_2 = self.larger(IRREG_PENTAGON_SHAPE_2) # Standard initial positions for the shapes. upper_left_position = Vector(300, 300) lower_right_position = Vector(900, 400) upper_right_position = Vector(900, 300) lower_left_position = Vector(300, 400) # Randomize the initial positions of the shapes. (original_position1, original_position2) = random.choice([(upper_left_position, lower_right_position), \ (lower_right_position, upper_left_position), \ (upper_right_position, lower_left_position), \ (lower_left_position, upper_right_position)]) # Randomize the initial angles of the shapes. (original_angle1, original_angle2) = random.choice( [(0, math.pi/4), (math.pi/4, 0) , \ (0, math.pi/4), (math.pi/4, 0), (0, math.pi/4), (math.pi/4, 0), (0, 0), (math.pi/2, 0), (0, math.pi/2) ]) # The total number of problems. self.n_problems = 30 # Choose a random problem. while (self.problem_number in self.container.recently_used): self.problem_number = random.randrange(0, self.n_problems) # Uncomment to test a particular problem. #problem_number = 0 # Define the various problems. if self.problem_number == 0: object1 = SQUARE_SHAPE object2 = LARGE_SQUARE_SHAPE elif self.problem_number == 1: object1 = SMALL_SQUARE_SHAPE object2 = SQUARE_SHAPE elif self.problem_number == 2: object1 = SQUARE_SHAPE object2 = SQUARE_SHAPE elif self.problem_number == 3: object1 = RECTANGLE_SHAPE object2 = LARGE_RECTANGLE_SHAPE elif self.problem_number == 4: object1 = SMALL_RECTANGLE_SHAPE object2 = RECTANGLE_SHAPE elif self.problem_number == 5: object1 = RECTANGLE_SHAPE object2 = RECTANGLE_SHAPE elif self.problem_number == 6: object1 = TRIANGLE_SHAPE object2 = LARGE_TRIANGLE_SHAPE elif self.problem_number == 7: object1 = SMALL_TRIANGLE_SHAPE object2 = TRIANGLE_SHAPE elif self.problem_number == 8: object1 = TRIANGLE_SHAPE object2 = TRIANGLE_SHAPE elif self.problem_number == 9: object1 = RT_ANGLE_TRAPEZOID_SHAPE object2 = LARGE_RT_ANGLE_TRAPEZOID_SHAPE elif self.problem_number == 10: object1 = SMALL_RT_ANGLE_TRAPEZOID_SHAPE object2 = RT_ANGLE_TRAPEZOID_SHAPE elif self.problem_number == 11: object1 = RT_ANGLE_TRAPEZOID_SHAPE object2 = RT_ANGLE_TRAPEZOID_SHAPE elif self.problem_number == 12: object1 = TRAPEZOID_SHAPE object2 = LARGE_TRAPEZOID_SHAPE elif self.problem_number == 13: object1 = SMALL_TRAPEZOID_SHAPE object2 = TRAPEZOID_SHAPE elif self.problem_number == 14: object1 = TRAPEZOID_SHAPE object2 = TRAPEZOID_SHAPE elif self.problem_number == 15: object1 = PARALLELOGRAM_SHAPE object2 = LARGE_PARALLELOGRAM_SHAPE elif self.problem_number == 16: object1 = SMALL_PARALLELOGRAM_SHAPE object2 = PARALLELOGRAM_SHAPE elif self.problem_number == 17: object1 = PARALLELOGRAM_SHAPE object2 = PARALLELOGRAM_SHAPE elif self.problem_number == 18: object1 = IRREG_TRIANGLE_SHAPE_1 object2 = LARGE_IRREG_TRIANGLE_SHAPE_1 elif self.problem_number == 19: object1 = SMALL_IRREG_TRIANGLE_SHAPE_1 object2 = IRREG_TRIANGLE_SHAPE_1 elif self.problem_number == 20: object1 = IRREG_TRIANGLE_SHAPE_1 object2 = IRREG_TRIANGLE_SHAPE_1 elif self.problem_number == 21: object1 = IRREG_QUADRIATERAL_SHAPE_1 object2 = LARGE_IRREG_QUADRIATERAL_SHAPE_1 elif self.problem_number == 22: object1 = self.smaller(SMALL_SQUARE_SHAPE) object2 = self.smaller(SQUARE_SHAPE) elif self.problem_number == 23: object1 = IRREG_QUADRIATERAL_SHAPE_1 object2 = IRREG_QUADRIATERAL_SHAPE_1 elif self.problem_number == 24: object1 = IRREG_QUADRIATERAL_SHAPE_2 object2 = LARGE_IRREG_QUADRIATERAL_SHAPE_2 elif self.problem_number == 25: object1 = self.larger(self.larger(IRREG_QUADRIATERAL_SHAPE_2)) object2 = LARGE_IRREG_QUADRIATERAL_SHAPE_2 elif self.problem_number == 26: object1 = IRREG_QUADRIATERAL_SHAPE_2 object2 = IRREG_QUADRIATERAL_SHAPE_2 elif self.problem_number == 27: object1 = IRREG_PENTAGON_SHAPE_1 object2 = LARGE_IRREG_PENTAGON_SHAPE_1 elif self.problem_number == 28: object1 = self.larger(LARGE_IRREG_PENTAGON_SHAPE_2) object2 = LARGE_IRREG_PENTAGON_SHAPE_2 elif self.problem_number == 29: object1 = IRREG_PENTAGON_SHAPE_1 object2 = IRREG_PENTAGON_SHAPE_1 else: object1 = SQUARE_SHAPE object2 = LARGE_SQUARE_SHAPE # Switch the shapes half the time (so we get > as well as < problems). if random.choice([0,1]) == 0: self.shape1 = ShapeObject(color1, self.letter1, object1, original_position1, original_angle1) self.shape2 = ShapeObject(color2, self.letter2, object2, original_position2, original_angle2) else: self.shape1 = ShapeObject(color1, self.letter1, object2, original_position1, original_angle1) self.shape2 = ShapeObject(color2, self.letter2, object1, original_position2, original_angle2) return def show_problem(self): self.container.configure_dragging_area(50, 24, 16, math.pi/4) self.container.add_object(self.shape1) self.container.add_object(self.shape2) # Randomize which object is initially selected. if random.choice([0,1]) == 0: self.container.select_object(self.shape1) else: self.container.select_object(self.shape1) # Add letter symbols. self.container.letter1 = SymbolObject(Vector(500 + 400 - 50, 650), self.shape1.symbol, None, None, size=100) self.container.letter2 = SymbolObject(Vector(700 + 400 - 50, 650), self.shape2.symbol, None, None, size=100) self.container.letter1.draggable = False self.container.letter1.selectable = False self.container.letter2.draggable = False self.container.letter2.selectable = False self.container.add_object(self.container.letter1) self.container.add_object(self.container.letter2) self.container.questionmark = SymbolObject(Vector(600 + 400 - 50, 650), '?', None, None, size=80) self.container.questionmark.draggable = False self.container.questionmark.selectable = False self.container.add_object(self.container.questionmark) self.container.instructions = InstructionsObject(Vector(50, 25), 'Compare the things in area') self.container.add_object(self.container.instructions) def scaled(self, vectors, factor): for vector in vectors: new_vectors = [v.scaled(factor) for v in vectors] return new_vectors def larger(self, vectors): for vector in vectors: new_vectors = [v.scaled(1.2) for v in vectors] return new_vectors def smaller(self, vectors): for vector in vectors: new_vectors = [v.scaled(0.8) for v in vectors] return new_vectors def check_problem_solved(self): # Make sure the two ShapeObjects have the same number of points. if len(self.shape1.points) != len(self.shape2.points): return False # First, test whether the first two ShapeObjects coincide (areas are equal). p0 = self.shape1.points p0 = [self.shape1.transform_point(p) for p in p0] p1 = self.shape2.points p1 = [self.shape2.transform_point(p) for p in p1] # Sort the points so they can be compared consistently. def sort_points_arbitrarily(a, b): if a.x != b.x: return cmp(a.x, b.x) else: return cmp(a.y, b.y) p0 = sorted(p0, cmp=sort_points_arbitrarily) p1 = sorted(p1, cmp=sort_points_arbitrarily) all_equal = True for i in range(0,len(p0)): if not p0[i].approx_equal(p1[i]): all_equal = False if all_equal: return True # Test if one object is completely inside the other (areas are not equal) area0 = self.shape1.area area1 = self.shape2.area if area0 > area1: object_larger = self.shape1 p_smaller = p1 else: object_larger = self.shape2 p_smaller = p0 for i in range(0,len(self.shape1.points)): if not object_larger.contains_point(p_smaller[i]): return False return True def find_answer(self): if self.shape1.area > self.shape2.area: self.answer = 'greater' elif self.shape1.area < self.shape2.area: self.answer = 'less' else: self.answer = 'equal' return self.answer