Let's create a short test for the Pythagorean theorem!
The command line is:
mathmaker pythagorean-short-test
After checking everything's fine, mathmaker will use the write() method of the (LaTeX) Machine to write the sheet to the output:
M.write(str(sheet.AVAILABLE[args[0]][0](M)))
sheet.AVAILABLE[args[0]]0 is, in this case, PythagoreanTheoremShortTest.
The __str__() method of S_Structure turns the sheet into a string.
The Machine is given in argument in order to call its methods from inside the sheets', exercises' and questions' methods.
The global defined at the beginning of PythagoreanTheoremShortTest will be used:
FONT_SIZE_OFFSET = -1
SHEET_LAYOUT_TYPE = 'short_test'
SHEET_LAYOUT_UNIT = "cm"
#EXAMPLE OF A SHEET NOT USING ANY LAYOUT
# ----------------------- lines_nb col_widths exercises
SHEET_LAYOUT = { 'exc' : [ None, 'all'
],
'ans' : [ None, 'all'
]
}
If you look into PythagoreanTheoremShortTest.__init__(), you'll see some fields redefined (the title etc.) and also which Exercise is created and added to the object's exercises_list field:
ex1 = exercise.X_RightTriangle(self.machine,
x_kind='short_test',
x_subkind='pythagorean_theorem_one_of_each')
self.exercises_list.append(ex1)
X_RightTriangle defines some globals:
AVAILABLE_X_KIND_VALUES = \
{'short_test' : ['pythagorean_theorem_one_of_each',
'converse_of_pythagorean_theorem',
'contrapositive_of_pythagorean_theorem']
#'preformatted' : [''],
#'bypass' : ['']
}
X_LAYOUT_UNIT = "cm" #[1, 9, 9], (1, 1)
# ---------------------- lines_nb col_widths questions
X_LAYOUTS = {'default' :
{ 'exc' : [ None, 'all'
],
'ans' : [ None, 'all'
]
}
}
Note that the x_kind and x_subkind options written in the PythagoreanTheoremShortTest sheet match the possible kinds of Exercise to create.
Then in X_RightTriangle.__init__(), the section matching our request is:
if self.x_kind == 'short_test':
if self.x_subkind == 'pythagorean_theorem_one_of_each':
q_subkinds = ['calculate_hypotenuse', 'calculate_one_leg']
if randomly.heads_or_tails():
self.questions_list.append(default_question(
self.machine,
q_kind='pythagorean_theorem',
q_subkind=randomly.pop(q_subkinds),
use_pythagorean_triples=True,
use_decimals=True,
final_unit=randomly.pop(units),
number_of_the_question='a',
figure_in_the_text='no',
rotate_around_barycenter=\
randomly.pop(angles) + random_signs[0]*randomly.integer(0,
20)
)
)
self.questions_list.append(default_question(
self.machine,
q_kind='pythagorean_theorem',
q_subkind=randomly.pop(q_subkinds),
use_pythagorean_triples=False,
round_to=randomly.pop([TENTH,
HUNDREDTH]),
final_unit=randomly.pop(units),
number_of_the_question='b',
figure_in_the_text='no',
rotate_around_barycenter=\
randomly.pop(angles) + random_signs[1]*randomly.integer(0,
20)
)
)
else:
etc. (same but reversed order)
It defines randomly the order of the two questions: the first will be either to calculate one leg and the other one will be to calculate the hypotenuse. It is also randomly decided if the result should be rounded or not (in one of the questions, the result must be rounded, in the other one, the result is an exact decimal result).
Each call to the matching question is made with several options defining more precisely which kind of question to create.
What happens in Q_RightTriangle? First, AVAILABLE_Q_KIND_VALUES is defined and you can check that the given argument belongs to the possible kinds:
AVAILABLE_Q_KIND_VALUES = {'pythagorean_theorem' : ['calculate_hypotenuse',
'calculate_one_leg'],
'converse_of_pythagorean_theorem' : ['default'],
'contrapositive_of_pythagorean_theorem': ['default'],
'cosinus' : ['calculate_hypotenuse',
'calculate_one_leg',
'calculate_angle'],
'sinus' : ['calculate_hypotenuse',
'calculate_one_leg',
'calculate_angle'],
'tangente' : ['calculate_hypotenuse',
'calculate_one_leg',
'calculate_angle'],
}
In Q_RightTriangle.__init__(), many different variables are set according to the values of the options given in argument (or by default).
Then it will set some variables according to the type of question and according to the values of the options, again:
if self.q_kind == 'pythagorean_theorem':
sides_values = [None, None, None]
if use_pythagorean_triples:
etc.
.
.
.
Once this is done, at the end, it creates the RightTriangle that will be used in the question:
.
.
.
self.right_triangle = \
RightTriangle((vertices_names,
'sketch'
),
rotate_around_isobarycenter=rotation_option
)
self.right_triangle.leg0.set_label(Value(sides_values[0],
unit=sides_units[0])
)
self.right_triangle.leg1.set_label(Value(sides_values[1],
unit=sides_units[1])
)
self.right_triangle.hypotenuse.set_label(Value(sides_values[2],
unit=sides_units[2])
)
for side in self.right_triangle.sides:
if side.label.raw_value == "":
self.unknown_side = side.clone()
else:
self.known_sides += [side.clone()]