def test_r1_into_euk(): """Check Rectangle's generated euk file.""" r1 = Rectangle([Point(["A", (0.5, 0.5)]), 4, 3, "B", "C", "D"]) r1.side[2].label = Value(4, unit='cm') r1.side[3].label = Value(3, unit='cm') assert r1.into_euk() == \ 'box -0.1, -0.1, 5.1, 4.1\n\n'\ 'A = point(0.5, 0.5)\n'\ 'B = point(4.5, 0.5)\n'\ 'C = point(4.5, 3.5)\n'\ 'D = point(0.5, 3.5)\n'\ '\n'\ 'draw\n'\ ' (A.B.C.D)\n'\ ' $\\rotatebox{0}{\sffamily 4~cm}$ C 180 - 7.5 deg 6.4\n'\ ' $\\rotatebox{90}{\sffamily 3~cm}$ D 270 - 9 deg 4.9\n'\ ' "A" A 225 deg, font("sffamily")\n'\ ' "B" B 315 deg, font("sffamily")\n'\ ' "C" C 45 deg, font("sffamily")\n'\ ' "D" D 135 deg, font("sffamily")\n'\ 'end\n\n'\ 'label\n'\ ' B, A, D right\n'\ ' C, B, A right\n'\ ' D, C, B right\n'\ ' A, D, C right\n'\ 'end'
def a(self, **options): v = None if hasattr(self, 'hint'): v = Value(self.result, unit=self.hint)\ .into_str(display_SI_unit=True) else: v = Value(self.result).into_str() return v
def __init__(self, nbs_to_use, **kwargs): result_fct = kwargs.pop('result_fct', None) wording = kwargs.pop('wording', "") super().setup("minimal", **kwargs) super().setup("numbers", nb=nbs_to_use, **kwargs) super().setup("nb_variants", nb=nbs_to_use, **kwargs) self.result = Value(result_fct(self.nb1, self.nb2).evaluate()).into_str() if 'swap_nb1_nb2' in kwargs and kwargs['swap_nb1_nb2']: self.nb1, self.nb2 = self.nb2, self.nb1 if ('permute_nb1_nb2_result' in kwargs and kwargs['permute_nb1_nb2_result']): # __ self.nb1, self.nb2, self.result = self.result, self.nb1, self.nb2 self.nb1 = Value(self.nb1) self.nb2 = Value(self.nb2) self.wording = wording setup_wording_format_of(self)
def p1(): p1 = Polygon([Point(["A", (0.5, 0.5)]), Point(["B", (3, 1)]), Point(["C", (3.2, 4)]), Point(["D", (0.8, 3)]) ]) p1.side[0].label = Value(4, unit='cm') p1.side[1].label = Value(3, unit='cm') p1.side[2].label = Value(2, unit='cm') p1.side[3].label = Value(6.5, unit='cm') p1.angle[0].label = Value(64, unit="\\textdegree") p1.angle[1].label = Value(128, unit="\\textdegree") p1.angle[2].label = Value(32, unit="\\textdegree") p1.angle[3].label = Value(256, unit="\\textdegree") p1.angle[0].mark = 'simple' p1.angle[1].mark = 'simple' p1.angle[2].mark = 'simple' p1.angle[3].mark = 'simple' return p1
def __init__(self, numbers_to_use, **options): nb_list = list(numbers_to_use) hole = Item(Value('...')) self.hidden_one = None visible_one = None self.product = Item(Product([nb_list[0], nb_list[1]]).evaluate()) if isinstance(nb_list[1], Fraction): self.hidden_one = nb_list[1] visible_one = nb_list[0] else: nb1 = randomly.pop(nb_list) nb2 = randomly.pop(nb_list) nb_list = [nb1, nb2] self.hidden_one = Item(randomly.pop(nb_list)) visible_one = randomly.pop(nb_list) factors = [visible_one, hole] self.holed_product = Product([randomly.pop(factors), randomly.pop(factors)]) self.holed_product.set_compact_display(False)
def test_t1_into_euk(): """Check Triangle's generated euk file.""" t1 = Triangle((("Z", "E", "P"), { 'side0': 4, 'angle1': 64, 'side1': 5 }), rotate_around_isobarycenter=115) t1.side[0].label = Value(4, unit='cm') t1.side[1].label = Value(5, unit='cm') t1.side[2].label = Value(4.84, unit='cm') t1.angle[0].label = Value('?') t1.angle[1].label = Value(64, unit='\\textdegree') t1.angle[2].label = Value(35, unit='\\textdegree') t1.angle[0].mark = 'simple' t1.angle[1].mark = 'double' t1.angle[2].mark = 'dotted' assert t1.into_euk() == \ 'box -1.32, -0.48, 4.71, 4.6\n\n'\ 'Z = point(4.11, 0.37)\n'\ 'E = point(2.42, 4)\n'\ 'P = point(-0.72, 0.12)\n'\ '\n'\ 'draw\n'\ ' (Z.E.P)\n'\ ' $\\rotatebox{-65}{\sffamily 4~cm}$ Z 115 - 7.5 deg 6.5\n'\ ' $\\rotatebox{51}{\sffamily 5~cm}$ E 231 - 6.5 deg 8\n'\ ' $\\rotatebox{3}{\sffamily 4.84~cm}$ P 3 - 6.7 deg 7.8\n'\ ' $\\rotatebox{-31.2}{\sffamily ?}$ Z 148.8 deg 2.7\n'\ ' $\\rotatebox{82.9}{\sffamily 64\\textdegree}$ E 262.9 deg 2.7\n'\ ' $\\rotatebox{27}{\sffamily 35\\textdegree}$ P 27 deg 2.7\n'\ ' "Z" Z 328.8 deg, font("sffamily")\n'\ ' "E" E 82.9 deg, font("sffamily")\n'\ ' "P" P 207 deg, font("sffamily")\n'\ 'end\n\n'\ 'label\n'\ ' E, Z, P simple\n'\ ' P, E, Z double\n'\ ' Z, P, E dotted\n'\ 'end'
def negv(): return Value(-4.2)
def v3(): return Value(4.257)
def v4(): return Value(4.2571)
def v1(): return Value(4.2)
def v2(): return Value(4.25)
def __init__(self, numbers_to_use, picture='true', **options): super().setup("minimal", **options) if numbers_to_use[0] < 11: raise ValueError('numbers_to_use[0] == {} whereas it should be ' '>= 11'.format(str(numbers_to_use[0]))) numbers_to_use = (numbers_to_use[0] / 10, ) + numbers_to_use[1:] super().setup("numbers", nb=numbers_to_use, shuffle_nbs=False, **options) super().setup("length_units", **options) super().setup("intercept_theorem_figure", butterfly=True, **options) if self.variant == 'default': variant = ['random', 'random'] else: if self.variant.count('_') != 1: raise error.XMLFileFormatError('The variant for ' 'intercept_theorem_butterfly ' 'shoud contain one _') variant = self.variant.split(sep='_') valid_variant = [['random', 'oneside', 'twosides'], ['random', 'all', 'twocouples']] for v, valid, n in zip(variant, valid_variant, ['first', 'second', 'third']): if v not in valid: raise error.XMLFileFormatError('Invalid {} part of the ' 'variant. It should be in: {}' .format(n, str(valid))) if variant[0] == 'random': if variant[1] == 'twocouples': variant[0] = 'oneside' else: variant[0] = random.choice(['oneside', 'twosides']) if variant[1] == 'random': if variant[0] == 'twosides': variant[1] = 'twocouples' else: variant[1] == random.choice(['all', 'twocouples']) if variant == ['twosides', 'twocouples']: raise error.XMLFileFormatError('The twosides_twocouples ' 'variant is impossible.') # The order is: # small[0] small[1] small[2] side[0] side[1] side[2] labels_configurations = { 'oneside_all': [ ['?', True, True, True, True, True], [True, '?', True, True, True, True], [True, True, '?', True, True, True], [True, True, True, '?', True, True], [True, True, True, True, '?', True], [True, True, True, True, True, '?'] ], 'oneside_twocouples': [ ['?', True, False, True, True, False], [False, True, '?', False, True, True], [True, True, False, True, '?', False], [False, True, True, False, '?', True], ['?', False, True, True, False, True], [True, False, '?', True, False, True], [True, '?', False, True, True, False], [False, '?', True, False, True, True], [False, True, True, False, True, '?'], [True, True, False, '?', True, False], [True, False, True, True, False, '?'], [True, False, True, '?', False, True], ], 'twosides_all': [ ['?', '?', True, True, True, True], ['?', True, '?', True, True, True], [True, '?', '?', True, True, True], ['?', True, True, True, '?', True], ['?', True, True, True, True, '?'], [True, '?', True, '?', True, True], [True, '?', True, True, True, '?'], [True, True, '?', True, '?', True], [True, True, '?', '?', True, True], [True, True, True, '?', '?', True], [True, True, True, '?', True, '?'], [True, True, True, True, '?', '?'], ] } variant_key = '_'.join(variant) labels_conf = random.choice(labels_configurations[variant_key]) self.figure.setup_labels(labels_conf, segments_list=self.figure.small + self.figure.side) lengths_to_calculate = [s.length_name for s in self.figure.small + self.figure.side if s.label == Value('?')] self.line1 = self.figure.small[1].length_name self.line2 = self.figure.side[1].length_name self.length1_name = lengths_to_calculate[0] if len(lengths_to_calculate) == 2: self.length2_name = lengths_to_calculate[1] if len(lengths_to_calculate) == 1: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the length of {length1_name}.') else: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the lengths of {length1_name} ' 'and {length2_name}.') setup_wording_format_of(self) self.ratios = shared.machine.write_math_style1( self.figure.ratios_equalities() .into_str(as_a_quotients_equality=True)) self.ratios_substituted = shared.machine.write_math_style1( self.figure.ratios_equalities_substituted() .into_str(as_a_quotients_equality=True)) self.resolution0 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[0]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = _('hence: {resolution0} ') if len(lengths_to_calculate) == 2: self.resolution1 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[1]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = shared.machine.write( lengths_resolutions_part + _('and: {resolution1} '), multicolumns=2) ans_variant = options.get('ans_variant', 'default') ans_texts = { 'default': _('As: {line1} {parallel_to} {line2}, ' '{main_vertex_name} {belongs_to} {chunk0_length_name}' ' and ' '{main_vertex_name} {belongs_to} {chunk1_length_name}' ', then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative1': _('As {line1} is parallel to {line2}, ' 'and as the line {chunk0_length_name} cuts ' 'the line {chunk1_length_name} at point ' '{main_vertex_name}, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative2': _('As: {line1} is parallel to {line2}, ' 'and as {point0_name}, {main_vertex_name} and ' '{vertex1_name} on one hand, ' '{point1_name}, {main_vertex_name} and ' '{vertex2_name} on the other hand,' 'are aligned in the same order, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} ') } self.answer_wording = ans_texts[ans_variant] + lengths_resolutions_part setup_wording_format_of(self, w_prefix='answer_')
def v0(): return Value(4)
def setup(self, arg, shuffle_nbs=True, **options): if arg == "minimal": self.newline = '\\newline' self.parallel_to = '$\parallel$' self.belongs_to = '$\in$' if 'variant' in options and options['variant'] == 'decimal': options['variant'] = random.choice(['decimal1', 'decimal2']) self.variant = options.get('variant', "default") self.context = options.get('context', "default") self.picture = XML_BOOLEANS[options.get('picture', "false")]() elif arg == "length_units": if 'unit' in options: self.unit_length = Unit(options['unit']) self.unit_area = Unit(self.unit_length.name, exponent=2) self.length_unit = self.unit_length.name else: if hasattr(self, 'length_unit'): self.unit_length = Unit(self.length_unit) self.unit_area = Unit(self.unit_length.name, exponent=2) elif hasattr(self, 'unit_length'): self.length_unit = self.unit_length.name self.unit_area = Unit(self.unit_length.name, exponent=2) else: length_units_names = copy.deepcopy(COMMON_LENGTH_UNITS) self.unit_length = Unit(random.choice(length_units_names)) self.unit_area = Unit(self.unit_length.name, exponent=2) self.length_unit = self.unit_length.name elif arg == "numbers": nb_list = list(options['nb']) if shuffle_nbs: random.shuffle(nb_list) for i in range(len(nb_list)): setattr(self, 'nb' + str(i + 1), nb_list[i]) self.nb_nb = len(nb_list) elif arg == "nb_variants": if self.variant.startswith('decimal'): deci_nb = int(self.variant[-1]) # so, from decimal1 up to 9 chosen_ones = random.sample([i for i in range(self.nb_nb)], deci_nb) for i in chosen_ones: setattr(self, 'nb' + str(i + 1), getattr(self, 'nb' + str(i + 1)) / 10) elif arg == "division": nb_list = list(options['nb']) self.divisor = self.result = self.dividend = 0 self.result_str = self.quotient_str = "" if '10_100_1000' in options and options['10_100_1000']: self.divisor, self.dividend = nb_list[0], nb_list[1] self.result = Quotient(('+', self.dividend, self.divisor))\ .evaluate() else: self.divisor = nb_list.pop(random.choice([0, 1])) self.result = nb_list.pop() if self.variant[:-1] == 'decimal': self.result /= 10 self.dividend = Product([self.divisor, self.result]).evaluate() if self.context == "from_area": self.subcontext = "w" if self.result < self.divisor else "l" self.dividend_str = Item(self.dividend).printed self.divisor_str = Item(self.divisor).printed self.result_str = Item(self.result).printed q = Quotient(('+', self.dividend, self.divisor), use_divide_symbol=True) self.quotient_str = q.printed elif arg == "rectangle": if hasattr(self, 'nb1') and hasattr(self, 'nb2'): nb1, nb2 = self.nb1, self.nb2 elif 'nb' in options: nb1, nb2 = options['nb'][0], options['nb'][1] else: raise error.ImpossibleAction("Setup a rectangle if no width " "nor length have been provided" " yet.") if (not hasattr(self, 'unit_length') or not hasattr(self, 'unit_area')): self.setup(self, "units", **options) # nb1 = Decimal(str(nb1)) # nb2 = Decimal(str(nb2)) w = Value(min([nb1, nb2]), unit=self.unit_length) l = Value(max([nb1, nb2]), unit=self.unit_length) rectangle_name = "DCBA" if self.picture: rectangle_name = next(shared.four_letters_words_source) self.rectangle = Rectangle([Point([rectangle_name[3], (0, 0)]), 3, 1.5, rectangle_name[2], rectangle_name[1], rectangle_name[0]], read_name_clockwise=True) self.rectangle.set_lengths([l, w]) self.rectangle.setup_labels([False, False, True, True]) elif arg == "square": if hasattr(self, 'nb1'): nb1 = self.nb1 elif 'nb' in options: nb1 = options['nb'][0] else: raise error.ImpossibleAction("Setup a square if no side's " "length have been provided " "yet.") if (not hasattr(self, 'unit_length') or not hasattr(self, 'unit_area')): # __ self.setup(self, "units", **options) square_name = "DCBA" if self.picture: square_name = next(shared.four_letters_words_source) self.square = Square([Point([square_name[3], (0, 0)]), 2, square_name[2], square_name[1], square_name[0]], read_name_clockwise=True) self.square.set_lengths([Value(nb1, unit=self.unit_length)]) self.square.setup_labels([False, False, True, False]) self.square.set_marks(random.choice(["simple", "double", "triple"])) elif arg == 'intercept_theorem_figure': butterfly = options.get('butterfly', False) set_lengths = options.get('set_lengths', True) if set_lengths: if not all([hasattr(self, 'nb1'), hasattr(self, 'nb2'), hasattr(self, 'nb3'), hasattr(self, 'nb4')]): # __ raise error.ImpossibleAction("Setup an intercept theorem " "figure without a " "coefficient and 3 other " "lengths provided.") points_names = next(shared.five_letters_words_source) if butterfly: points_names = list(rotate(points_names, -1)) (points_names[0], points_names[1]) = (points_names[1], points_names[0]) points_names = ''.join(points_names) else: points_names = rotate(points_names, random.choice(range(5))) alpha, beta = next(shared.angle_ranges_source) rotation_angle = alpha + random.choice(range(beta - alpha)) self.figure = InterceptTheoremConfiguration( points_names=points_names, build_ratio=random.choice(range(25, 75)) / 100, sketch=False, butterfly=butterfly, build_dimensions={ False: {'side0': Decimal('5'), 'angle1': Decimal(str(random.choice(range(45, 120)))), 'side1': Decimal(str(random.choice(range(20, 60)) / 10))}, True: {'side0': Decimal('4'), 'angle1': Decimal(str(random.choice(range(55, 110)))), 'side1': Decimal(str(random.choice(range(15, 50)) / 10))} }[butterfly], rotate_around_isobarycenter=rotation_angle) if set_lengths: self.figure.set_lengths([self.nb2, self.nb3, self.nb4], Value(self.nb1)) self.figure.side[2].invert_length_name() self.figure.small[2].invert_length_name() self.point0_name = self.figure.point[0].name self.point1_name = self.figure.point[1].name self.main_vertex_name = self.figure.vertex[0].name self.vertex1_name = self.figure.vertex[1].name self.vertex2_name = self.figure.vertex[2].name self.side0_length_name = self.figure.side[0].length_name self.small0_length_name = self.figure.small[0].length_name self.chunk0_length_name = self.figure.chunk[0].length_name self.side0_length = str(self.figure.side[0].length) self.small0_length = str(self.figure.small[0].length) self.chunk0_length = str(self.figure.chunk[0].length) self.side1_length_name = self.figure.side[2].length_name self.small1_length_name = self.figure.small[2].length_name self.chunk1_length_name = self.figure.chunk[1].length_name self.side1_length = str(self.figure.side[2].length) self.small1_length = str(self.figure.small[2].length) self.chunk1_length = str(self.figure.chunk[1].length) elif arg == 'mini_problem_wording': self.wording = _(shared.mini_problems_wordings_source .next(q_id=options['q_id'], nb1_to_check=self.nb1, nb2_to_check=self.nb2)) setup_wording_format_of(self)
def a(self, **options): return Value(self.result).into_str()
def __init__(self, numbers_to_use, picture='true', **options): super().setup("minimal", **options) if numbers_to_use[0] < 11: raise ValueError('numbers_to_use[0] == {} whereas it should be ' '>= 11'.format(str(numbers_to_use[0]))) numbers_to_use = (numbers_to_use[0] / 10, ) + numbers_to_use[1:] super().setup("numbers", nb=numbers_to_use, shuffle_nbs=False, **options) super().setup("length_units", **options) super().setup("intercept_theorem_figure", **options) if self.variant == 'default': variant = ['oneside', 'random', 'false'] else: if self.variant.count('_') != 2: raise error.XMLFileFormatError('The variant for ' 'intercept_theorem_triangle ' 'shoud contain two _') variant = self.variant.split(sep='_') valid_variant = [[ 'onerandom', 'tworandom', 'random', 'oneside', 'onechunk', 'twosides', 'twochunks', 'onesideonechunk' ], ['random', 'all', 'twocouples'], ['random', 'true', 'false']] for v, valid, n in zip(variant, valid_variant, ['first', 'second', 'third']): if v not in valid: raise error.XMLFileFormatError( 'Invalid {} part of the ' 'variant. It should be in: {}'.format(n, str(valid))) if variant[0] == 'onerandom': variant[0] = random.choice(['oneside', 'onechunk']) elif variant[0] == 'tworandom': if variant[1] == 'twocouples': raise error.XMLFileFormatError('The tworandom_twocouples_* ' 'variants are impossible.') if variant[2] == 'random': variant[2] = random.choice(['true', 'false']) if variant[2] == 'false': variant[0] = random.choice( ['twosides', 'twochunks', 'onesideonechunk']) elif variant[2] == 'true': variant[0] = random.choice(['twosides', 'onesideonechunk']) else: raise error.XMLFilFormatError('The third part of the variant ' 'should be "true" or "false".') # The order is: # small[0] small[1] small[2] side[0] side[1] side[2] chunk[0] chunk[1] # 'hid' means 'hidden', e.g. the length won't be displayed but can be # easily calculated before using the intercept theorem. labels_configurations = { 'oneside_all_false': [['?', True, True, True, True, True, False, False], [True, '?', True, True, True, True, False, False], [True, True, '?', True, True, True, False, False], [True, True, True, '?', True, True, False, False], [True, True, True, True, '?', True, False, False], [True, True, True, True, True, '?', False, False]], 'oneside_all_true': [ ['?', True, True, True, True, 'hid', False, True], [True, '?', True, 'hid', True, 'hid', True, True], [True, '?', True, 'hid', True, True, True, False], [True, '?', True, True, True, 'hid', False, True], [True, True, '?', 'hid', True, True, True, False], [True, True, True, '?', True, 'hid', False, True], [True, True, True, True, '?', 'hid', False, True], [True, True, True, 'hid', '?', 'hid', True, True], [True, True, True, 'hid', '?', True, True, False], [True, True, True, 'hid', True, '?', True, False], ], 'onechunk_all_false': [[True, True, True, False, True, True, '?', False], [True, True, True, True, True, False, False, '?']], 'onechunk_all_true': [[True, True, True, False, True, 'hid', '?', True], [True, True, True, 'hid', True, False, True, '?']], 'twosides_all_false': [ ['?', '?', True, True, True, True, False, False], ['?', True, '?', True, True, True, False, False], [True, '?', '?', True, True, True, False, False], ['?', True, True, True, '?', True, False, False], ['?', True, True, True, True, '?', False, False], [True, '?', True, '?', True, True, False, False], [True, '?', True, True, True, '?', False, False], [True, True, '?', True, '?', True, False, False], [True, True, '?', '?', True, True, False, False], [True, True, True, '?', '?', True, False, False], [True, True, True, '?', True, '?', False, False], [True, True, True, True, '?', '?', False, False], ], 'twosides_all_true': [ ['?', '?', True, True, True, 'hid', False, True], [True, '?', '?', 'hid', True, True, True, False], ['?', True, True, True, '?', 'hid', False, True], [True, '?', True, '?', True, 'hid', False, True], [True, '?', True, False, True, '?', True, False], [True, True, '?', False, '?', True, True, False], [True, True, True, '?', '?', 'hid', False, True], [True, True, True, 'hid', '?', '?', True, False], ], 'twochunks_all_false': [ [False, True, False, True, True, True, '?', '?'], [True, True, False, False, True, True, '?', '?'], [False, True, True, True, True, False, '?', '?'], [True, True, True, False, True, False, '?', '?'], ], 'onesideonechunk_all_false': [ [False, '?', True, True, True, True, '?', False], [True, '?', False, True, True, True, False, '?'], [True, '?', True, False, True, True, '?', False], [True, '?', True, True, True, False, False, '?'], [False, True, '?', True, True, True, '?', False], ['?', True, False, True, True, True, False, '?'], [True, True, '?', False, True, True, '?', False], ['?', True, True, True, True, False, False, '?'], [True, True, True, False, True, '?', '?', False], [True, True, True, '?', True, False, False, '?'], [False, True, True, True, True, '?', '?', False], [True, True, False, '?', True, True, False, '?'], [False, True, True, True, '?', True, '?', False], [True, True, False, True, '?', True, False, '?'], [True, True, True, False, '?', True, '?', False], [True, True, True, True, '?', False, False, '?'], ], 'onesideonechunk_all_true': [ [True, '?', True, False, True, 'hid', '?', True], [True, '?', True, 'hid', True, False, True, '?'], [False, '?', True, True, True, 'hid', '?', True], [True, '?', False, 'hid', True, True, True, '?'], [True, True, True, False, '?', 'hid', '?', True], [True, True, True, 'hid', '?', False, True, '?'], [False, True, True, True, '?', 'hid', '?', True], [True, True, False, 'hid', '?', True, True, '?'], ], 'oneside_twocouples_false': [ ['?', True, False, True, True, False, False, False], [False, True, '?', False, True, True, False, False], [True, True, False, True, '?', False, False, False], [False, True, True, False, '?', True, False, False], ['?', False, True, True, False, True, False, False], [True, False, '?', True, False, True, False, False], [True, '?', False, True, True, False, False, False], [False, '?', True, False, True, True, False, False], [False, True, True, False, True, '?', False, False], [True, True, False, '?', True, False, False, False], [True, False, True, True, False, '?', False, False], [True, False, True, '?', False, True, False, False], ], 'oneside_twocouples_true': [ ['?', False, True, True, False, 'hid', False, True], [True, False, '?', 'hid', False, True, True, False], [True, '?', False, 'hid', True, False, True, False], [False, '?', True, False, True, 'hid', False, True], [True, True, False, 'hid', '?', False, True, False], [False, True, True, False, '?', 'hid', False, True], [True, False, True, '?', False, 'hid', False, True], [True, False, True, 'hid', False, '?', True, False], ], 'onechunk_twocouples_false': [ [True, True, False, False, True, False, '?', False], [False, True, True, False, True, False, False, '?'], [True, False, True, False, False, True, '?', False], [True, False, True, True, False, False, False, '?'], ], 'onechunk_twocouples_true': [ [True, False, True, False, False, 'hid', '?', True], [True, False, True, 'hid', False, False, True, '?'], ] } random_nb = variant.count('random') if random_nb == 3: variant = random.choice(list( labels_configurations.keys())).split(sep='_') elif random_nb == 2: if variant[0] == 'random' and variant[1] == 'random': if variant[2] == 'false': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) if variant[0] in [ 'twosides', 'twochunks', 'onesideonechunk' ]: variant[1] = 'all' else: variant[1] = random.choice(['all', 'twocouples']) elif variant[2] == 'true': variant[0] = random.choice( ['oneside', 'onechunk', 'twosides', 'onesideonechunk']) if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) else: variant[1] = 'all' elif variant[0] == 'random' and variant[2] == 'random': if variant[1] == 'all': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) if variant[0] == 'twochunks': variant[2] = 'false' else: variant[2] = random.choice(['true', 'false']) elif variant[1] == 'twocouples': variant[0] = random.choice(['oneside', 'onechunk']) variant[2] = random.choice(['true', 'false']) elif variant[1] == 'random' and variant[2] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) variant[2] = random.choice(['true', 'false']) elif variant[0] in ['twosides', 'onesideonechunk']: variant[1] = 'all' variant[2] = random.choice(['true', 'false']) elif variant[0] == 'twochunks': variant[1] = 'all' variant[2] = 'false' elif random_nb == 1: if variant[0] == 'random': if variant[1] == 'twocouples': variant[0] = random.choice(['oneside', 'onechunk']) elif variant[1] == 'all': if variant[2] == 'true': variant[0] = random.choice([ 'oneside', 'onechunk', 'twosides', 'onesideonechunk' ]) elif variant[2] == 'false': variant[0] = random.choice(ALL_LENGTHS_TO_CALCULATE) elif variant[1] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[1] = random.choice(['all', 'twocouples']) elif variant[0] in ['twosides', 'onesideonechunk']: variant[1] = 'all' elif variant[0] == 'twochunks': if variant[2] == 'false': variant[1] = 'all' else: raise error.XMLFileFormatError('Invalid variants: ' '"twochunks_*_true".') elif variant[2] == 'random': if variant[0] in ['oneside', 'onechunk']: variant[2] = random.choice(['true', 'false']) elif variant[1] == 'twocouples': raise error.XMLFileFormatError('Invalid variants: ' '"two..._twocouples_*".') else: if variant[0] == 'twochunks': variant[2] = 'false' else: variant[2] = random.choice(['true', 'false']) variant_key = '_'.join(variant) labels_conf = random.choice(labels_configurations[variant_key]) self.figure.setup_labels( labels_conf, segments_list=self.figure.small + [self.figure.u, self.figure.side[1], self.figure.v] + self.figure.chunk) self.figure.setup_labels( [labels_conf[3], labels_conf[5]], segments_list=[self.figure.side[0], self.figure.side[2]]) lengths_to_calculate = [ s.length_name for s in self.figure.small + self.figure.side if s.label == Value('?') ] chunks_to_calculate = [] chunks_infos = [] if 'chunk' in variant_key: if len(lengths_to_calculate) == 1: chunks_to_calculate = [None] chunks_infos = [None] if labels_conf[6] == '?': # This matches chunk0 chunks_to_calculate += [self.figure.chunk[0].length_name] chunks_infos += [ (self.figure.side[0].length_name, self.figure.small[0].length_name, self.figure.side[0].length, self.figure.small[0].length) ] if not labels_conf[0]: lengths_to_calculate += [self.figure.small[0].length_name] else: lengths_to_calculate += [self.figure.side[0].length_name] if labels_conf[7] == '?': # This matches chunk1 chunks_to_calculate += [self.figure.chunk[1].length_name] chunks_infos += [ (self.figure.side[2].length_name, self.figure.small[2].length_name, self.figure.side[2].length, self.figure.small[2].length) ] if not labels_conf[2]: lengths_to_calculate += [self.figure.small[2].length_name] else: lengths_to_calculate += [self.figure.side[2].length_name] self.line1 = self.figure.small[1].length_name self.line2 = self.figure.side[1].length_name lengths_asked_for = [ s.length_name for s in self.figure.small + self.figure.side + self.figure.chunk if s.label == Value('?') ] self.length1_name = lengths_asked_for[0] if len(lengths_asked_for) == 2: self.length2_name = lengths_asked_for[1] if len(lengths_asked_for) == 1: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the length of {length1_name}.') else: self.wording = _('The drawn figure is out of shape. {newline} ' 'The lengths are given in {length_unit}. ' '{newline} ' 'The {line1} is parallel to {line2}. {newline} ' '{newline} ' 'Determine the lengths of {length1_name} ' 'and {length2_name}.') setup_wording_format_of(self) preamble = '' if variant_key.endswith('true'): self.pre_reso0 = self.pre_reso1 = '' if labels_conf[6] is True: pre_equality0 = SubstitutableEquality( [ Item(self.side0_length_name), Sum([ Item(self.small0_length_name), Item(self.chunk0_length_name) ]) ], { Value(self.small0_length_name): Value(self.figure.small[0].length), Value(self.chunk0_length_name): Value(self.figure.chunk[0].length) }) pre_equality0_str = pre_equality0.into_str() pre_equation0 = Equation(pre_equality0.substitute()) self.pre_reso0 = shared.machine.write_math_style1( pre_equality0_str) \ + pre_equation0.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) if labels_conf[7] is True: pre_equality1 = SubstitutableEquality( [ Item(self.side1_length_name), Sum([ Item(self.small1_length_name), Item(self.chunk1_length_name) ]) ], { Value(self.small1_length_name): Value(self.figure.small[2].length), Value(self.chunk1_length_name): Value(self.figure.chunk[1].length) }) pre_equality1_str = pre_equality1.into_str() pre_equation1 = Equation(pre_equality1.substitute()) self.pre_reso1 = shared.machine.write_math_style1( pre_equality1_str) \ + pre_equation1.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) if labels_conf[6] is True and labels_conf[7] is True: preamble = _('Note: {pre_reso0} {newline} and: {pre_reso1} ' '{newline} ') elif labels_conf[6] is True: preamble = _('Note: {pre_reso0} {newline} ') elif labels_conf[7] is True: preamble = _('Note: {pre_reso1} {newline} ') self.ratios = shared.machine.write_math_style1( self.figure.ratios_equalities().into_str( as_a_quotients_equality=True)) self.ratios_substituted = shared.machine.write_math_style1( self.figure.ratios_equalities_substituted().into_str( as_a_quotients_equality=True)) self.resolution0 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[0]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = _('hence: {resolution0} ') if len(lengths_to_calculate) == 2: self.resolution1 = self.figure.ratios_equalities_substituted()\ .into_crossproduct_equation(Item(lengths_to_calculate[1]))\ .auto_resolution(dont_display_equations_name=True, skip_first_step=True, skip_fraction_simplification=True, decimal_result=2, unit=self.length_unit, underline_result=True) lengths_resolutions_part = shared.machine.write( lengths_resolutions_part + _('and: {resolution1} '), multicolumns=2) chunks_part = '' if len(chunks_to_calculate): if chunks_to_calculate[0] is not None: chunk_equality0 = SubstitutableEquality( [ Item(chunks_to_calculate[0]), Sum([ Item(chunks_infos[0][0]), Item(('-', chunks_infos[0][1])) ]) ], { Value(chunks_infos[0][0]): Value(chunks_infos[0][2]), Value(chunks_infos[0][1]): Value(chunks_infos[0][3]) }) chunk_equality0_str = chunk_equality0.into_str() chunk_equation0 = Equation(chunk_equality0.substitute()) self.chunk_reso0 = shared.machine.write_math_style1( chunk_equality0_str) \ + chunk_equation0.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) chunks_part += _('so: {chunk_reso0} ') else: chunks_part += '~\n\n\\newline\\newline\\newline\\newline\n\n' if len(chunks_to_calculate) == 2: chunk_equality1 = SubstitutableEquality( [ Item(chunks_to_calculate[1]), Sum([ Item(chunks_infos[1][0]), Item(('-', chunks_infos[1][1])) ]) ], { Value(chunks_infos[1][0]): Value(chunks_infos[1][2]), Value(chunks_infos[1][1]): Value(chunks_infos[1][3]) }) chunk_equality1_str = chunk_equality1.into_str() chunk_equation1 = Equation(chunk_equality1.substitute()) self.chunk_reso1 = shared.machine.write_math_style1( chunk_equality1_str) \ + chunk_equation1.auto_resolution( dont_display_equations_name=True, decimal_result=2, unit=self.length_unit, underline_result=True) chunks_part = shared.machine.write(chunks_part + _('so: {chunk_reso1} '), multicolumns=2) ans_variant = options.get('ans_variant', 'default') ans_texts = { 'default': _('As: {line1} {parallel_to} {line2}, ' '{point0_name} {belongs_to} {side0_length_name} and ' '{point1_name} {belongs_to} {side1_length_name}, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative1': _('As {line1} is parallel to {line2}, ' 'and as the line {chunk0_length_name} cuts ' 'the line {chunk1_length_name} at point ' '{main_vertex_name}, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} '), 'alternative2': _('As: {line1} is parallel to {line2}, ' 'and as {vertex1_name}, {point0_name} and ' '{main_vertex_name} on one hand, ' '{vertex2_name}, {point1_name} and ' '{main_vertex_name} on the other hand,' 'are aligned in the same order, ' 'then by the intercept theorem: {newline} ' '{ratios} ' 'thus: {ratios_substituted} ') } self.answer_wording = preamble \ + ans_texts[ans_variant] \ + lengths_resolutions_part \ + chunks_part setup_wording_format_of(self, w_prefix='answer_')
def h(self, **options): if hasattr(self, 'hint'): return "\hfill" + Value("", unit=self.hint)\ .into_str(display_SI_unit=True) else: return ""
def merge_nb_unit_pairs(arg: object, w_prefix=''): r""" Merge all occurences of {nbN} {\*_unit} in arg.wording into {nbN\_\*_unit}. In the same time, the matching attribute arg.nbN\_\*_unit is set with Value(nbN, unit=Unit(arg.\*_unit)).into_str(display_SI_unit=True) (the possible exponent is taken into account too). :param arg: the object whose attribute wording will be processed. It must have a wording attribute as well as nbN and \*_unit attributes. :type arg: object :rtype: None :Example: >>> class Object(object): pass ... >>> arg = Object() >>> arg.wording = 'I have {nb1} {capacity_unit} of water.' >>> arg.nb1 = 2 >>> arg.capacity_unit = 'L' >>> merge_nb_unit_pairs(arg) >>> arg.wording 'I have {nb1_capacity_unit} of water.' >>> arg.nb1_capacity_unit '\\SI{2}{L}' """ w_object_wording = getattr(arg, w_prefix + 'wording') logger = settings.dbg_logger.getChild('wording.merge_nb_unit_pairs') logger.debug("Retrieved wording: " + w_object_wording + "\n") new_words_list = [] words = w_object_wording.split() skip_next_w = False for i, w in enumerate(words): next_w = words[i + 1] if i <= len(words) - 2 else None logger.debug("w= " + w + " next_w= " + str(next_w)) next_w_is_a_unit = False if next_w is not None and (is_unit(next_w) or is_unitN(next_w)): next_w_is_a_unit = True logger.debug(" next_w_is_a_unit: " + str(next_w_is_a_unit) + "\n") if is_wrapped(w) and w[1:3] == "nb" and next_w_is_a_unit: n = w[1:-1] u = "" if is_wrapped(next_w): u = next_w[1:-1] p = "" elif is_wrapped_P(next_w): u = next_w[1:-2] p = next_w[-1] new_attr_name = n + "_" + u expnt = 1 if u.startswith('area'): expnt = 2 elif u.startswith('volume'): expnt = 3 new_val = Value(getattr(arg, n), unit=Unit(getattr(arg, u), exponent=Value(expnt)))\ .into_str(display_SI_unit=True) new_words_list += ["{" + new_attr_name + "}" + p] logger.debug(" setattr: name=" + str(new_attr_name) + "; val= " + str(new_val) + "\n") setattr(arg, new_attr_name, new_val) skip_next_w = True elif skip_next_w: skip_next_w = False else: new_words_list += [w] new_wording = " ".join(new_words_list) logger.debug(" setattr: name=" + w_prefix + 'wording' + "; val= " + new_wording + "\n") setattr(arg, w_prefix + 'wording', new_wording)
def q(self, **options): return _("In the multiplication tables (from 2 to 9), " "which product is equal to {n}?")\ .format(n=Value(self.product).into_str())
def level_02(q_subkind, **options): max_coeff = 20 if 'max_coeff' in options and is_.an_integer(options['max_coeff']): max_coeff = options['max_coeff'] attribute_a_minus_sign = 'randomly' if 'minus_sign' in options and options['minus_sign']: attribute_a_minus_sign = 'yes' elif 'minus_sign' in options and not options['minus_sign']: attribute_a_minus_sign = 'no' # Creation of the objects # The three Monomials: ax², bx and c # Maybe we don't need to keep the integer values... a_val = randomly.integer(1, max_coeff) b_val = randomly.integer(1, max_coeff) c_val = randomly.integer(1, max_coeff) if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1', 'type_1_C1' ]: # __ c_val = randomly.integer(2, max_coeff) ax2 = Monomial((randomly.sign(), a_val, 2)) bx = Monomial((randomly.sign(), b_val, 1)) c = Monomial((randomly.sign(), c_val, 0)) # deg1: mx + p # and we need two of them deg1 = [] for i in range(2): deg1_mx = Monomial((randomly.sign(), randomly.integer(1, max_coeff), 1)) deg1_p = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_A1', 'type_1_B1', 'type_1_D1', 'type_1_E1', 'type_1_G1', 'type_1_H1', 'type_4_A0' ]: # __ deg1_p = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 0)) else: deg1_p = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) if not deg1_p.is_null(): lil_box = [deg1_mx, deg1_p] deg1.append( Polynomial([randomly.pop(lil_box), randomly.pop(lil_box)])) else: deg1.append(deg1_mx) # deg2: mx² + px + r # and we also need two of them deg2 = [] for i in range(2): deg2_mx2 = Monomial((randomly.sign(), randomly.integer(1, max_coeff), 2)) deg2_px = None deg2_r = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_A1', 'type_1_B1', 'type_1_D1', 'type_1_E1', 'type_1_G1', 'type_1_H1' ]: # __ if randomly.heads_or_tails(): deg2_px = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) else: deg2_px = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(1, max_coeff), 0)) else: deg2_px = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 1)) deg2_r = Monomial( (randomly.sign(), randomly.integer(0, max_coeff), 0)) lil_box = [deg2_mx2] if not deg2_px.is_null(): lil_box.append(deg2_px) if not deg2_r.is_null(): lil_box.append(deg2_r) monomials_list_for_deg2 = [] for i in range(len(lil_box)): monomials_list_for_deg2.append(randomly.pop(lil_box)) deg2.append(Polynomial(monomials_list_for_deg2)) # Let's attribute the common factor C according to the required type # (NB: expression ± C×F1 ± C×F2) C = None if q_subkind in [ 'type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1' ]: # __ C = c elif q_subkind in [ 'type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_D1', 'type_1_E1' ]: # __ C = bx elif q_subkind in [ 'type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_G1', 'type_1_H1' ]: # __ C = ax2 elif q_subkind in [ 'type_2_A0', 'type_2_B0', 'type_2_C0', 'type_2_A1', 'type_2_B1', 'type_4_A0' ]: # __ C = Polynomial([bx, c]) elif q_subkind in [ 'type_2_D0', 'type_2_E0', 'type_2_F0', 'type_2_D1', 'type_2_E1' ]: # __ C = Polynomial([ax2, c]) elif q_subkind in [ 'type_3_A0', 'type_3_B0', 'type_3_C0', 'type_3_A1', 'type_3_B1' ]: # __ C = Polynomial([ax2, bx, c]) # Let's attribute F1 and F2 according to the required type # (NB: expression ± C×F1 ± C×F2) F1 = None F2 = None if q_subkind in [ 'type_1_A0', 'type_1_A1', 'type_1_D0', 'type_1_D1', 'type_1_G0', 'type_1_G1', 'type_2_A0', 'type_2_A1', 'type_2_D0', 'type_2_D1', 'type_3_A0', 'type_3_A1' ]: # __ F1 = deg1[0] F2 = deg1[1] elif q_subkind in [ 'type_1_B0', 'type_1_B1', 'type_1_E0', 'type_1_E1', 'type_1_H0', 'type_1_H1', 'type_2_B0', 'type_2_B1', 'type_2_E0', 'type_2_E1', 'type_3_B0', 'type_3_B1' ]: # __ F1 = deg2[0] F2 = deg2[1] elif q_subkind in [ 'type_1_C0', 'type_1_F0', 'type_1_I0', 'type_2_C0', 'type_2_F0', 'type_3_C0' ]: # __ F1 = deg1[0] F2 = deg2[0] # The special case type_4_A0: (ax+b)² + (ax+b)×deg1' # aka C² + C×F1 elif q_subkind == 'type_4_A0': F1 = C.clone() F2 = deg1[0] # Let's put a "1" somewhere in the type_*_*1 if q_subkind in [ 'type_1_A1', 'type_1_D1', 'type_1_G1', 'type_2_A1', 'type_2_D1', 'type_3_A1', 'type_1_B1', 'type_1_E1' 'type_1_H1', 'type_2_B1', 'type_2_E1', 'type_3_B1' ]: # __ if randomly.heads_or_tails(): F1 = Item(1) else: F2 = Item(1) # Let's possibly attribute a minus_sign # (NB: expression ± C×F1 ± C×F2) minus_sign = None # this will contain the name of the factor having # a supplementary minus sign in such cases: # C×F1 - C×F2# - C×F1 + C×F2 # in all the following cases, it doesn't bring anything to attribute # a minus sign if ((q_subkind in ['type_1_A0', 'type_1_B0', 'type_1_C0', 'type_1_A1', 'type_1_B1'] and c_val < 0) or ((q_subkind in ['type_1_D0', 'type_1_E0', 'type_1_F0', 'type_1_D1', 'type_1_E1']) and b_val < 0) or ((q_subkind in ['type_1_G0', 'type_1_H0', 'type_1_I0', 'type_1_G1', 'type_1_H1']) and a_val < 0)): # __ pass # here we let minus_sign equal to None # otherwise, let's attribute one randomly, # depending on attribute_a_minus_sign else: if attribute_a_minus_sign in ['yes', 'randomly']: # __ if (attribute_a_minus_sign == 'yes' or randomly.heads_or_tails()): # __ if randomly.heads_or_tails(): minus_sign = "F1" else: minus_sign = "F2" else: pass # here we let minus_sign equal to None # Now let's build the expression ! expression = None box_product1 = [C, F1] box_product2 = [C, F2] if q_subkind == 'type_4_A0': CF1 = Product([C]) CF1.set_exponent(Value(2)) else: CF1 = Product([randomly.pop(box_product1), randomly.pop(box_product1)]) CF2 = Product([randomly.pop(box_product2), randomly.pop(box_product2)]) if minus_sign == "F1": if len(F1) >= 2: CF1 = Expandable((Item(-1), CF1)) else: CF1 = Product([Item(-1), CF1]) elif minus_sign == "F2": if len(F2) >= 2: CF2 = Expandable((Item(-1), CF2)) else: CF2 = Product([Item(-1), CF2]) expression = Sum([CF1, CF2]) # Now let's build the factorization steps ! steps = [] steps.append(expression) F1F2_sum = None if minus_sign is None: F1F2_sum = Sum([F1, F2]) elif minus_sign == "F1": if len(F1) >= 2: F1F2_sum = Sum([Expandable((Item(-1), F1)), F2]) else: F1F2_sum = Sum([Product([Item(-1), F1]), F2]) elif minus_sign == "F2": if len(F2) >= 2: F1F2_sum = Sum([F1, Expandable((Item(-1), F2))]) else: F1F2_sum = Sum([F1, Product([Item(-1), F2])]) temp = Product([C, F1F2_sum]) temp.set_compact_display(False) steps.append(temp) F1F2_sum = F1F2_sum.expand_and_reduce_next_step() while F1F2_sum is not None: steps.append(Product([C, F1F2_sum])) F1F2_sum = F1F2_sum.expand_and_reduce_next_step() # This doesn't fit the need, because too much Products are # wrongly recognized as reducible ! if steps[len(steps) - 1].is_reducible(): steps.append(steps[len(steps) - 1].reduce_()) return steps
def perfect_square(): return Value(16)
def a(self, **options): v = Value(self.result, unit=self.hint).into_str(display_SI_unit=True) return v
def perfect_decimal_square(): return Value(1.96)
def __init__(self, q_kind='default_nothing', **options): self.derived = True # The call to the mother class __init__() method will set the # fields matching optional arguments which are so far: # self.q_kind, self.q_subkind # plus self.options (modified) Q_Structure.__init__(self, q_kind, AVAILABLE_Q_KIND_VALUES, **options) # The purpose of this next line is to get the possibly modified # value of **options options = self.options # Set the default values of the different options use_pythagorean_triples = False if (('use_pythagorean_triples' in options and options['use_pythagorean_triples']) or (self.q_kind == 'converse_of_pythagorean_theorem')): # __ use_pythagorean_triples = True use_decimals = True if 'use_decimals' in options and not options['use_decimals']: use_decimals = False self.round_to = "" if 'round_to' in options and options['round_to'] in PRECISION: self.round_to = options['round_to'] if not use_pythagorean_triples: if self.round_to == "": if use_decimals: self.round_to = HUNDREDTH else: self.round_to = TENTH self.use_pythagorean_triples = use_pythagorean_triples self.figure_in_the_text = True if ('figure_in_the_text' in options and not options['figure_in_the_text']): # __ self.figure_in_the_text = False rotation_option = 'no' if 'rotate_around_barycenter' in options: rotation_option = options['rotate_around_barycenter'] self.final_unit = "" if ('final_unit' in options and options['final_unit'] in LENGTH_UNITS): # __ self.final_unit = options['final_unit'] sides_units = [self.final_unit, self.final_unit, self.final_unit] # Later, allow to use a different length unit for the sides # than the final expected unit ; allow different units for different # sides (for instance giving a list in option 'sides_units')... # So far we will do with only ONE unit # if 'sides_units' in options \ # and options['sides_units'] in LENGTH_UNITS: # # __ # sides_units = options['sides_units'] self.right_triangle = None self.unknown_side = None self.known_sides = [] # Now set some randomly values letters = [elt for elt in alphabet.UPPERCASE] vertices_names = (randomly.pop(letters), randomly.pop(letters), randomly.pop(letters)) # Here you can begin to write code for the different # q_kinds & q_subkinds if self.q_kind == 'pythagorean_theorem': sides_values = [None, None, None] if use_pythagorean_triples: triples = pythagorean.ALL_TRIPLES_5_100 if use_decimals: triples = pythagorean.ALL_TRIPLES_5_100 \ + pythagorean.TRIPLES_101_200_WO_TEN_MULTIPLES sides_values = randomly.pop(triples) if use_decimals: sides_values = \ [Decimal(str(Decimal(sides_values[0]) / 10)), Decimal(str(Decimal(sides_values[1]) / 10)), Decimal(str(Decimal(sides_values[2]) / 10))] if self.q_subkind == 'calculate_hypotenuse': sides_values[2] = "" sides_units[2] = "" else: # case: self.q_subkind == 'calculate_one_leg' leg0_or_1 = randomly.pop([0, 1]) sides_values[leg0_or_1] = "" sides_units[leg0_or_1] = "" else: # NO pythagorean triples. # The two generated values must NOT match any pythagorean # triple if use_decimals: min_side_value = 5 max_side_value = 200 else: min_side_value = 5 max_side_value = 100 if self.q_subkind == 'calculate_hypotenuse': first_leg = randomly.integer(min_side_value, max_side_value) # we will take the leg values between # at least 25% and at most 150% of the length of first leg # (and smaller than max_side_value) second_leg_values = [] for i in range(int(first_leg * 1.5)): if (i + int(first_leg * 0.25) <= 1.5 * first_leg and i + int(first_leg * 0.25) <= max_side_value): # __ second_leg_values += [i + int(first_leg * 0.25)] second_leg_unauthorized_values = \ pythagorean.get_legs_matching_given_leg(first_leg) second_leg_possible_values = \ list(set(second_leg_values) - set(second_leg_unauthorized_values)) if randomly.heads_or_tails(): sides_values = \ [first_leg, randomly.pop(second_leg_possible_values), ""] sides_units[2] = "" else: sides_values = \ [randomly.pop(second_leg_possible_values), first_leg, ""] sides_units[2] = "" else: # case: self.q_subkind == 'calculate_one_leg' hypotenuse = randomly.integer(min_side_value, max_side_value) # we will take the leg values between # at least 25% and at most 90% of the length of hypotenuse # to avoid "weird" cases (with a very subtle difference # between the given values and the one to calculate) leg_values = [] for i in range(int(hypotenuse * 0.9)): if i + int(hypotenuse * 0.25) <= 0.9 * hypotenuse: leg_values += [i + int(hypotenuse * 0.25)] leg_unauthorized_values = \ pythagorean\ .get_legs_matching_given_hypotenuse(hypotenuse) leg_possible_values = list(set(leg_values) - set(leg_unauthorized_values)) if randomly.heads_or_tails(): sides_values = ["", randomly.pop(leg_possible_values), hypotenuse] sides_units[0] = "" else: sides_values = [randomly.pop(leg_possible_values), "", hypotenuse] sides_units[1] = "" self.right_triangle = \ RightTriangle((vertices_names, 'sketch'), rotate_around_isobarycenter=rotation_option) self.right_triangle.leg[0].label = Value(sides_values[0], unit=sides_units[0]) self.right_triangle.leg[1].label = Value(sides_values[1], unit=sides_units[1]) self.right_triangle.hypotenuse.label = Value(sides_values[2], unit=sides_units[2]) for side in self.right_triangle.side: if side.label.raw_value == "": self.unknown_side = side.clone() else: self.known_sides += [side.clone()] elif self.q_kind in ['converse_of_pythagorean_theorem', 'contrapositive_of_pythagorean_theorem']: # __ sides_values = [None, None, None] triples = list(pythagorean.ALL_TRIPLES_5_100) if use_decimals: triples += list(pythagorean.TRIPLES_101_200_WO_TEN_MULTIPLES) sides_values = randomly.pop(triples) if self.q_kind == 'contrapositive_of_pythagorean_theorem': # We'll change exactly one value to be sure the triplet # is NOT pythagorean if randomly.heads_or_tails(): # We will decrease the lowest value max_delta = int(0.1 * sides_values[0]) min_delta = 1 if min_delta > max_delta: max_delta = min_delta chosen_delta = randomly.pop( [i + min_delta for i in range(max_delta - min_delta + 1)]) sides_values = [sides_values[0] - chosen_delta, sides_values[1], sides_values[2]] else: # We will increase the highest value max_delta = int(0.1 * sides_values[2]) min_delta = 1 if min_delta > max_delta: max_delta = min_delta chosen_delta = randomly.pop( [i + min_delta for i in range(max_delta - min_delta + 1)]) sides_values = [sides_values[0], sides_values[1], sides_values[2] + chosen_delta] if use_decimals: sides_values = [Decimal(str(Decimal(sides_values[0]) / 10)), Decimal(str(Decimal(sides_values[1]) / 10)), Decimal(str(Decimal(sides_values[2]) / 10))] self.right_triangle = \ RightTriangle((vertices_names, 'sketch'), rotate_around_isobarycenter=rotation_option) self.right_triangle.leg[0].label = Value(sides_values[0], unit=sides_units[0]) self.right_triangle.leg[1].label = Value(sides_values[1], unit=sides_units[1]) self.right_triangle.hypotenuse.label = Value(sides_values[2], unit=sides_units[2]) self.right_triangle.right_angle.mark = ""