# 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 linesegmentmovableobject import LineSegmentMovableObject from linesegmentobject import LineSegmentObject from droptargetobject import DropTargetObject from signsdroptarget import SignsDropTarget from linesegmentoriginobject import LineSegmentOriginObject from signsoriginobject import SignsOriginObject from linesegmentdroptarget import LineSegmentDropTarget from answerobject import AnswerObject from groupobject import GroupObject from instructionsobject import InstructionsObject from progressobject import ProgressObject from threedobject import ThreeDObject from nextproblemobject import NextProblemObject from lengthproblem import LengthProblem from amountproblem import AmountProblem from areaproblem import AreaProblem from massproblem import MassProblem from volumeproblem import VolumeProblem from cuttingproblem import CuttingProblem import gtk, math, random, rsvg MOON_SVG = rsvg.Handle('moon.svg') PROBLEM_TYPES = ['length', 'amount', 'mass', 'volume', 'cutting', 'area'] COLOR_SCHEMES = [ 'red_green', 'green_blue', 'blue_red' ] class Compare3Lesson(ObjectArea): """ Lesson in which the user compares two objects in a given quantity, and represents the result of the measurement using a pair of line segments and the signs >, <, and =. """ def __init__(self, activity): ObjectArea.__init__(self, activity) self.problem = 0 self.level = 0 self.problem_type = 'none' self.color_scheme = 'no_colors' self.last_color_scheme = 'no_colors' self.alphabetical_letter1 = 'A' self.alphabetical_letter2 = 'A' self.last_alphabetical_letter1 = 'A' self.last_alphabetical_letter2 = 'A' self.problem_number = -1 self.recently_used = [-1, -1, -1, -1, -1, -1, -1, -1] self.progress = ProgressObject(Vector(10, 700), 30) self.add_object(self.progress) self.answer = 'equal' self.small_equal_sign = False self.drop_origin = None self.moons_visible = False self.n_errors = 0 self.n_equals_problems_correct = 0 self.n_greater_than_problems_correct = 0 self.n_less_than_problems_correct = 0 self.nextarrow = None self.pose_problem_stage1() self.solution_pending = False #TODO- Put this code in the ShapeObjects themselves. def check_problem_solved(self): #print "Compare3Lesson: check_problem_solved called" if self.stage == 1: if self.solution_pending: if not self.is_animating(): #print "Stage 1 Complete" self.solution_pending = False self.finish_problem_stage1() self.pose_problem_stage2() #print " check_problem_solved calling problem_solved_stage1" elif self.problem_solved_stage1(): self.solution_pending = True def register_error(self): #print '\a' self.n_errors += 1 #print "number of errors is now:", self.n_errors def pose_problem_stage1(self): #print "pose_problem_stage1: problem_type =", self.problem_type self.stage = 1 self.n_errors = 0 # Randomly choose between a length problem and an area problem. #self.problem_type = random.choice(PROBLEM_TYPES) self.last_color_scheme = self.color_scheme while (self.color_scheme == self.last_color_scheme): self.color_scheme = random.choice(COLOR_SCHEMES) self.last_alphabetical_letter1 = self.alphabetical_letter1 self.last_alphabetical_letter2 = self.alphabetical_letter2 # Choose two random letter to represent the two quantities while (self.alphabetical_letter1 == self.last_alphabetical_letter1 or self.alphabetical_letter1 == self.last_alphabetical_letter2 \ or self.alphabetical_letter2 == self.last_alphabetical_letter1 or self.alphabetical_letter2 == self.last_alphabetical_letter2 ): self.alphabetical_letter1 = random.choice(['A', 'B', 'C', 'D', 'G', 'H', 'K', 'L', 'M', 'N', 'P', 'S', 'T']) self.alphabetical_letter2 = self.alphabetical_letter1 while self.alphabetical_letter2 == self.alphabetical_letter1: self.alphabetical_letter2 = random.choice(['A', 'B', 'C', 'D', 'G', 'H', 'K', 'L', 'M', 'N', 'P', 'S', 'T']) #print "new problem: self.level is: ", self.level if self.level == 0: self.problem_type = 'length' elif self.level == 1: self.problem_type = 'area' elif self.level == 2: self.problem_type = 'volume' elif self.level == 3: self.problem_type = 'amount' elif self.level == 4: self.problem_type = 'mass' elif self.level == 5: self.problem_type = 'cutting' else: self.problem_type ='cutting' #print "... so self.problem_type is now: ", self.problem_type self.recently_used = [] if self.problem_type == 'length': n_problems = 18 elif self.problem_type == 'amount': n_problems = 8 elif self.problem_type == 'mass': n_problems = 9 elif self.problem_type == 'volume': n_problems = 12 elif self.problem_type == 'cutting': n_problems = 12 else: n_problems = 30 for i in range(0, n_problems - 3): self.recently_used.append(-1) #print "" #print "self.recently_used = ", self.recently_used # Uncomment this to choose a particular problem type. self.problem_type = 'volume' if self.problem_type == 'length': self.problem = LengthProblem(self, self.color_scheme, (self.alphabetical_letter1, self.alphabetical_letter2) ) elif self.problem_type == 'amount': self.problem = AmountProblem(self, self.color_scheme, (self.alphabetical_letter1, self.alphabetical_letter2) ) elif self.problem_type == 'mass': self.problem = MassProblem(self, self.color_scheme, (self.alphabetical_letter1, self.alphabetical_letter2) ) elif self.problem_type == 'volume': self.problem = VolumeProblem(self, (self.alphabetical_letter1, self.alphabetical_letter2) ) elif self.problem_type == 'cutting': self.problem = CuttingProblem(self, self.color_scheme, (self.alphabetical_letter1, self.alphabetical_letter2) ) else: self.problem = AreaProblem(self, self.color_scheme, (self.alphabetical_letter1, self.alphabetical_letter2) ) # Choose a random problem. while (self.problem_number in self.recently_used): self.problem_number = self.problem.problem_number #print "self.problem_number = ", self.problem_number self.recently_used.insert(0, self.problem_number) self.recently_used.pop() #print "Now self.recently_used = ", self.recently_used self.answer = self.problem.find_answer() self.problem_solved_stage1() def problem_solved_stage1(self): #print "Compare3Lesson: check_problem_solved called" #print " self.problem =", self.problem if self.problem: if self.problem.check_problem_solved(): return True return False #TODO- Put this code in the problems themselves. def finish_problem_stage1(self): #print "finish_problem_stage1 called" # Put the shapes in an answer box. #print "finish_problem_stage1 called" if self.problem_type == 'amount': self.shapesanswer = AnswerObject(Vector(50, 100), Vector(1100, 250), '1.') else: self.shapesanswer = AnswerObject(Vector(50, 100), Vector(650, 650), '1.') self.shapesanswer.z = -100 self.add_object(self.shapesanswer) if self.problem_type == 'area' or self.problem_type == 'length' \ or self.problem_type == 'cutting': self.problem.shape1.in_answer_box = True self.problem.shape2.in_answer_box = True # Make the ShapeObjects inactive. self.problem.shape1.selected = False self.problem.shape1.draggable = False self.problem.shape2.selected = False self.problem.shape2.draggable = False # Scale and move both shapes to the answer box. #print "scaling the shapes..." #print "shape1 =",self.problem.shape1 #print "shape2 =",self.problem.shape2 v = Vector(275 + 100, 350 + 75) - self.problem.shape1.pos self.problem.shape1.pos += v self.problem.shape2.pos += v self.problem.shape1.calculate_bounds() self.problem.shape2.calculate_bounds() elif self.problem_type == 'amount': self.problem.finish_problem_stage1() elif self.problem_type == 'mass': self.problem.finish_problem_stage1() self.problem.shape1.calculate_bounds() self.problem.shape2.calculate_bounds() # Make the ShapeObjects inactive. self.problem.shape1.selected = False self.problem.shape1.draggable = False self.problem.shape2.selected = False self.problem.shape2.draggable = False elif self.problem_type == 'volume': self.problem.finish_problem_stage1() def pose_problem_stage2(self): #print "pose_problem_stage2 called" self.stage = 2 self.instructions.text = 'Show the result using line segments' #print "pose_problem_stage2: string to call find_answer" self.answer = self.problem.find_answer() #print "pose_problem_stage2: self.answer = ", self.answer # Add DropTargetObjects for the line segments. shift_x = -500 shift_y = 250 if self.problem_type == 'amount': self.drop1 = LineSegmentDropTarget(Vector(810 + shift_x, 140 + shift_y), self) self.drop2 = LineSegmentDropTarget(Vector(1010 + shift_x, 140 + shift_y), self) self.dropletter1 = SymbolObject(Vector(850 + shift_x, 450 + shift_y), self.letter1.symbol, None, None) self.dropletter2 = SymbolObject(Vector(1050 + shift_x, 450 + shift_y), self.letter2.symbol, None, None) else: self.drop1 = LineSegmentDropTarget(Vector(810, 140), self) self.drop2 = LineSegmentDropTarget(Vector(1010, 140), self) self.dropletter1 = SymbolObject(Vector(850, 450), self.letter1.symbol, None, None) self.dropletter2 = SymbolObject(Vector(1050, 450), self.letter2.symbol, None, None) self.add_object(self.drop1) self.add_object(self.drop2) self.dropletter1.draggable = False self.dropletter1.selectable = False self.dropletter2.draggable = False self.dropletter2.selectable = False self.add_object(self.dropletter1) self.add_object(self.dropletter2) # Add a DropOrigin object to provide line segments for dropping. if self.problem_type == 'amount': self.drop_origin = LineSegmentOriginObject(Vector(910 + shift_x, 140 + shift_y), self, [self.drop1, self.drop2]) else: self.drop_origin = LineSegmentOriginObject(Vector(910, 140), self, [self.drop1, self.drop2]) self.add_object(self.drop_origin) self.drop1.drop_origin = self.drop_origin self.drop2.drop_origin = self.drop_origin self.drop1.drop_targets = [self.drop1, self.drop2] self.drop2.drop_targets = [self.drop1, self.drop2] self.drop1.answer = self.problem.find_answer() self.drop2.answer = self.problem.find_answer() self.select_object(self.drop_origin.line1) self.adjust_tab_order() def finish_problem_stage2(self): # Move the line segments in a little. shift_x = -500 shift_y = 250 if self.problem_type == 'amount': self.drop1.pos.x = 885 + shift_x self.drop2.pos.x = 985 + shift_x self.drop1.contents.pos.x = 900 + shift_x self.drop2.contents.pos.x = 1000 + shift_x self.drop1.contents.pos.y = self.drop1.pos.y + self.drop1.size.y - self.drop1.contents.length - 25 self.drop2.contents.pos.y = self.drop2.pos.y + self.drop1.size.y - self.drop2.contents.length - 25 self.dropletter1.pos.x = 900 + shift_x self.dropletter2.pos.x = 1000 + shift_x else: self.drop1.pos.x = 885 self.drop2.pos.x = 985 self.drop1.contents.pos.x = 900 self.drop2.contents.pos.x = 1000 self.drop1.contents.pos.y = self.drop1.pos.y + self.drop1.size.y - self.drop1.contents.length - 25 self.drop2.contents.pos.y = self.drop2.pos.y + self.drop1.size.y - self.drop2.contents.length - 25 self.dropletter1.pos.x = 900 self.dropletter2.pos.x = 1000 self.drop1.contents.selectable = False self.drop2.contents.selectable = False if self.drop1.contents.length == 100 and self.drop2.contents.length == 100: self.small_equal_sign = True else: self.small_equal_sign = False # Put the line segments in an answer box. shift_x = -500 shift_y = 250 if self.problem_type == 'amount': self.linesanswer = AnswerObject(Vector(750 + shift_x, 100 + shift_y), Vector(400, 400), '2.') else: self.linesanswer = AnswerObject(Vector(750, 100), Vector(400, 400), '2.') self.linesanswer.z = -100 if self.small_equal_sign: self.linesanswer.answer = 'equals_small' else: self.linesanswer.answer = self.answer self.add_object(self.linesanswer) self.drop_origin.remove_contents() self.clear_selection() self.remove_object(self.drop_origin) self.remove_object(self.drop1) self.remove_object(self.drop2) self.pose_problem_stage3() def pose_problem_stage3(self): self.stage = 3 self.instructions.text = 'Show the result using a sign' self.answer = self.problem.answer # Remove the Question mark. self.remove_object(self.questionmark) # Create the drop box for the symbol. self.symboldrop = SignsDropTarget(Vector(900, 600), self) self.add_object(self.symboldrop) # Add a DropOrigin object to provide signs for dropping. self.drop_origin = SignsOriginObject(Vector(850, 750), self, [self.symboldrop]) self.add_object(self.drop_origin) self.symboldrop.drop_origin = self.drop_origin self.symboldrop.drop_targets = [self.symboldrop] self.symboldrop.answer = self.problem.find_answer() #self.select_object(self.drop_origin.ltsymbol) self.adjust_tab_order() def finish_problem_stage3(self): #print "Compare3Lesson: finish_problem_stage3 called" # This means the problem is done, so we don't check stage 3 twice. self.stage = 4 i = 0 for o in self.objects: if isinstance(o, ShapeObject) and o.selectable: i += 1 o.selectable = False #print "Compare3Lesson:",i,"ShapeObjects were made not selectable" # Put it all in an answer box. self.symbolanswer = AnswerObject(Vector(400 + 350, 600 - 50), Vector(400, 200), '3.') self.symbolanswer.z = -100 self.add_object(self.symbolanswer) #print "Get rid of the drop origin..." self.drop_origin.remove_contents() self.drop_origin.background_visible = False self.remove_object(self.drop_origin) #print "...and the drop targets." self.remove_object(self.symboldrop) if self.answer == 'greater': text = 'greater than' elif self.answer == 'less': text = 'less than' else: text = 'equal to' if self.problem_type == 'cutting': quantity_name = 'area' else: quantity_name = self.problem_type self.instructions.text = 'The ' + quantity_name + ' ' + self.letter1.symbol + ' is ' \ + text + ' the ' + quantity_name + ' ' + self.letter2.symbol if (self.n_errors == 0 and self.n_equals_problems_correct > 0 \ and self.n_greater_than_problems_correct > 0 and self.n_less_than_problems_correct > 0): self.level += 1 #print "self.level is now:", self.level self.recently_used = [-1, -1, -1, -1, -1, -1, -1, -1] self.progress.take_a_step() self.n_equals_problems_correct = 0 self.n_greater_than_problems_correct = 0 self.n_less_than_problems_correct = 0 #else: # print "" # print "n_equals_problems_correct =", self.n_equals_problems_correct # print "n_greater_than_problems_correct =", self.n_greater_than_problems_correct # print "n_less_than_problems_correct =", self.n_less_than_problems_correct self.pose_next_problem_arrow() self.select_object(self.nextarrow) self.adjust_tab_order() def increment_n_equals_problems_correct(self): if self.n_errors == 0: self.n_equals_problems_correct += 1 def increment_n_greater_than_problems_correct(self): if self.n_errors == 0: self.n_greater_than_problems_correct += 1 def increment_n_less_than_problems_correct(self): if self.n_errors == 0: self.n_less_than_problems_correct += 1 def pose_next_problem_arrow(self): #print "Compare3Lesson: pose_next_problem_arrow called" # Put it all in an answer box. self.nextarrow = NextProblemObject() self.add_object(self.nextarrow) def finish_next_problem_arrow(self): self.remove_object(self.nextarrow) self.clean_up() self.pose_problem_stage1() def show_hint(self): if self.linesanswer: self.linesanswer.show_hint = True def clean_up(self): self.objects = [] self.add_object(self.progress) self.moons_visible = False def adjust_tab_order(self): # Remove and add the shapes to put all objects in a better order for tabbing. #print "adjust_tab_order called" o_new = [] i_next_problem = 0 for o in self.objects: if isinstance(o, NextProblemObject) and o.selectable: i_next_problem += 1 o_new.append(o) #print "Found ", i_shape ," NextProblemObject " i_shape = 0 for o in self.objects: if isinstance(o, ShapeObject) and o.selectable: i_shape += 1 o_new.append(o) #print "Found ", i_shape ," ShapeObjects " i_line_segment = 0 for o in self.objects: if isinstance(o, LineSegmentObject) and o.selectable: i_line_segment += 1 o_new.append(o) #print "Found ", i_line_segment ," LineSegmentObjects " i_line_segment_movable = 0 for o in self.objects: if isinstance(o, LineSegmentMovableObject) and o.selectable: i_line_segment_movable += 1 o_new.append(o) #print "Found ", i_line_segment_movable ," LineSegmentMovableObjects" i_sign = 0 for o in self.objects: if isinstance(o, SymbolObject) and o.selectable: if o.symbol == "<" or o.symbol == "=" or o.symbol == ">": i_sign += 1 o_new.append(o) #print "Found ", i_sign ," SymbolObjects" i_group = 0 for o in self.objects: if isinstance(o, GroupObject) and o.selectable: i_group += 1 o_new.append(o) #print "Found ", i_group ," GroupObjects" o_sorted = [] o_sorted = sorted(o_new, cmp=self.sort_by_type) i = 0 for o in o_sorted: i += 1 #for o in o_sorted: # print o # Find index of selected object. index_selected = 0 i = 0 for o in o_sorted: if isinstance (o, ShapeObject): if o.selected: index_selected = i elif isinstance (o, ThreeDObject): if o.selected: index_selected = i elif isinstance (o, LineSegmentObject): if o.selected: index_selected = i elif isinstance (o, LineSegmentMovableObject): if o.selected: index_selected = i elif isinstance (o, SymbolObject): if o.selected: index_selected = i elif isinstance (o, GroupObject): if o.selected: index_selected = i elif isinstance (o, NextProblemObject): if o.selected: index_selected = i i += 1 # Rotate the list. trans = index_selected while trans > 0: o_sorted.insert(0, o_sorted.pop(0)) trans -= 1 for o in o_new: self.remove_object(o) for o in o_sorted: self.add_object(o) # Sort objects by type. def sort_by_type(self, o1, o2): if isinstance(o1, ShapeObject) and isinstance(o2, LineSegmentObject): return 1 elif isinstance(o1, LineSegmentObject) and isinstance(o2, ShapeObject): return -1 elif isinstance(o1, ShapeObject) and isinstance(o2, LineSegmentMovableObject): return 1 elif isinstance(o1, LineSegmentMovableObject) and isinstance(o2, ShapeObject): return -1 elif isinstance(o1, LineSegmentObject) and isinstance(o2, LineSegmentMovableObject): return -1 elif isinstance(o1, LineSegmentMovableObject) and isinstance(o2, LineSegmentObject): return 1 elif isinstance(o1, ShapeObject) and isinstance(o2, SymbolObject): return 1 elif isinstance(o1, SymbolObject) and isinstance(o2, ShapeObject): return -1 elif isinstance(o1, ShapeObject) and isinstance(o2, GroupObject): return 1 elif isinstance(o1, GroupObject) and isinstance(o2, ShapeObject): return -1 elif isinstance(o1, ShapeObject) and isinstance(o2, NextProblemObject): return 1 elif isinstance(o1, NextProblemObject) and isinstance(o2, ShapeObject): return -1 elif isinstance(o1, ShapeObject) and isinstance(o2, ShapeObject): if o1.selected: return 1 elif o2.selected: return -1 else: if self.objects.index(o1) > self.objects.index(o2): return 1 elif self.objects.index(o1) < self.objects.index(o2): return -1 else: return 0 elif isinstance(o1, LineSegmentObject) and isinstance(o2, LineSegmentObject): if o1.length == 100: return -1 else: return 1 elif isinstance(o1, LineSegmentMovableObject) and isinstance(o2, LineSegmentMovableObject): if o1.pos.x < o2.pos.x: return 1 else: return -1 elif isinstance(o1, SymbolObject) and isinstance(o2, SymbolObject): if o1.symbol == '<': return -1 elif o2.symbol == '<': return 1 elif o1.symbol == '=': return -1 elif o2.symbol == '=' : return 1 elif o1.symbol == '>': return -1 elif o2.symbol == '<' : return 1 else: return 1 else: return 0 def draw_background(self, cr): if self.drop_origin: self.drop_origin.draw_background(cr) if self.moons_visible: self.draw_moons(cr) def draw_circle(self, cr, pos, color): cr.save() # Draw the fill. cr.set_source_rgb(color[0], color[1], color[2]) cr.arc(self.pos.x + pos.x, self.pos.y + pos.y, 35, 0.0, 2.0 * math.pi) cr.fill() # Draw the outline. cr.set_source_rgb(color[0]*0.75, color[1]*0.75, color[2]*0.75) cr.set_line_width(4.0) cr.arc(self.pos.x + pos.x, self.pos.y + pos.y, 35, 0.0, 2.0 * math.pi) cr.stroke() cr.restore() def draw_moons(self, cr): cr.save() cr.translate(45, 165) cr.rotate(-math.pi/6) cr.scale(1.5, 1.5) MOON_SVG.render_cairo(cr) cr.restore() cr.save() cr.translate(145, 615) cr.rotate(-math.pi/6) cr.scale(1.5, 1.5) MOON_SVG.render_cairo(cr) cr.restore()