mathmaker
0.4(alpha)
|
00001 # -*- coding: utf-8 -*- 00002 00003 # Mathmaker creates automatically maths exercises sheets 00004 # with their answers 00005 # Copyright 2006-2014 Nicolas Hainaux <nico_h@users.sourceforge.net> 00006 00007 # This file is part of Mathmaker. 00008 00009 # Mathmaker is free software; you can redistribute it and/or modify 00010 # it under the terms of the GNU General Public License as published by 00011 # the Free Software Foundation; either version 3 of the License, or 00012 # any later version. 00013 00014 # Mathmaker is distributed in the hope that it will be useful, 00015 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 # GNU General Public License for more details. 00018 00019 # You should have received a copy of the GNU General Public License 00020 # along with Mathmaker; if not, write to the Free Software 00021 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00022 00023 from lib import * 00024 from lib.common import default 00025 import question 00026 # ------------------------------------------------------------------------------ 00027 # -------------------------------------------------------------------------- 00028 # ------------------------------------------------------------------------------ 00029 ## 00030 # @class X_Structure 00031 # @brief Mother class of all exercises objects. Not instanciable. 00032 # This class suggests two default methods which are also in the exercise.Model 00033 # class : write_text and write_answer. In a new exercise, they can either be 00034 # kept untouched (then it would be wise to delete them from the new exercise) 00035 # or rewritten. 00036 class X_Structure(object): 00037 00038 00039 00040 00041 00042 # -------------------------------------------------------------------------- 00043 ## 00044 # @brief /!\ Must be redefined. Constructor. 00045 # @warning Exception NotInstanciableObject. 00046 # @param embedded_machine The machine to be used 00047 # @param **options Any options 00048 def __init__(self, embedded_machine, 00049 x_kind, AVAILABLE_X_KIND_VALUES, X_LAYOUTS, 00050 X_LAYOUT_UNIT, **options): 00051 try: 00052 self.derived 00053 except AttributeError: 00054 raise error.NotInstanciableObject(self) 00055 00056 self.machine = embedded_machine.clone(embedded_machine.language_code) 00057 self.machine.set_redirect_output_to_str(True) 00058 00059 self.questions_list = list() 00060 00061 # OPTIONS ------------------------------------------------------------- 00062 # It is necessary to define an options field to pass the 00063 # possibly modified value to the child class 00064 self.options = options 00065 00066 try: 00067 AVAILABLE_X_KIND_VALUES[x_kind] 00068 except KeyError: 00069 raise error.OutOfRangeArgument(x_kind, str(AVAILABLE_X_KIND_VALUES)) 00070 00071 x_subkind = 'default' 00072 if 'x_subkind' in options: 00073 x_subkind = options['x_subkind'] 00074 # let's remove this option from the options 00075 # since we re-use it recursively 00076 temp_options = dict() 00077 for key in options: 00078 if key != 'x_subkind': 00079 temp_options[key] = options[key] 00080 self.options = temp_options 00081 00082 if not x_subkind in AVAILABLE_X_KIND_VALUES[x_kind]: 00083 raise error.OutOfRangeArgument(x_subkind, 00084 str(AVAILABLE_X_KIND_VALUES[x_kind])) 00085 00086 self.x_kind = x_kind 00087 self.x_subkind = x_subkind 00088 00089 # Start number 00090 self.start_number = 0 00091 if 'start_number' in options: 00092 if not is_.an_integer(options['start_number']): 00093 raise error.UncompatibleType(options['start_number'], 00094 "integer") 00095 if not (options['start_number'] >= 1): 00096 raise error.OutOfRangeArgument(options['start_number'], 00097 "should be >= 1") 00098 00099 self.start_number = options['start_number'] 00100 00101 # Number of questions 00102 self.q_nb = default.NUMBER_OF_QUESTIONS 00103 if 'number_of_questions' in options: 00104 if not is_.an_integer(options['number_of_questions']): 00105 raise error.UncompatibleType(options['number_of_questions'], 00106 "integer") 00107 if not (options['number_of_questions'] >= 1): 00108 raise error.OutOfRangeArgument(options['number_of_questions'], 00109 "should be >= 1") 00110 00111 self.q_nb = options['number_of_questions'] 00112 00113 00114 self.x_layout_unit = X_LAYOUT_UNIT 00115 00116 if (self.x_kind, self.x_subkind) in X_LAYOUTS: 00117 self.x_layout = X_LAYOUTS[(self.x_kind, self.x_subkind)] 00118 00119 else: 00120 self.x_layout = X_LAYOUTS['default'] 00121 00122 00123 # END OF OPTIONS ------------------------------------------------------ 00124 00125 00126 00127 00128 00129 00130 00131 # -------------------------------------------------------------------------- 00132 ## 00133 # @brief Writes the text of the exercise|answer to the output. 00134 def to_str(self, ex_or_answers): 00135 M = self.machine 00136 layout = self.x_layout[ex_or_answers] 00137 00138 result = "" 00139 if self.text[ex_or_answers] != "": 00140 result += self.text[ex_or_answers] 00141 result += M.write_new_line() 00142 00143 q_n = 0 00144 00145 for k in xrange(len(layout)/2): 00146 if layout[2*k] is None: 00147 how_many = layout[2*k+1] 00148 if layout[2*k+1] == 'all_left' or layout[2*k+1] == 'all': 00149 how_many = len(self.questions_list) - q_n 00150 for i in xrange(how_many): 00151 result += self.questions_list[q_n].to_str(ex_or_answers) 00152 if ex_or_answers == 'ans': 00153 result += M.write_new_line(check=result[len(result)-2:]) 00154 q_n += 1 00155 else: 00156 nb_of_cols = len(layout[2*k]) - 1 00157 col_widths = layout[2*k][1:len(layout[2*k])] 00158 nb_of_lines = layout[2*k][0] 00159 if nb_of_lines == '?': 00160 nb_of_lines = len(self.questions_list) / nb_of_cols + \ 00161 (0 if not len(self.questions_list) % nb_of_cols else 1) 00162 content = [] 00163 for i in xrange(nb_of_lines): 00164 for j in xrange(nb_of_cols): 00165 if layout[2*k+1] == 'all': 00166 nb_of_q_in_this_cell = 1 00167 else: 00168 nb_of_q_in_this_cell = layout[2*k+1][i*nb_of_cols+j] 00169 cell_content = "" 00170 for n in xrange(nb_of_q_in_this_cell): 00171 empty_cell = False 00172 if q_n >= len(self.questions_list): 00173 cell_content += " " 00174 empty_cell = True 00175 else: 00176 cell_content += self.questions_list[q_n].\ 00177 to_str(ex_or_answers) 00178 if ex_or_answers == 'ans' and not empty_cell: 00179 cell_content += M.write_new_line(\ 00180 check=cell_content[len(cell_content)-2:]) 00181 q_n += 1 00182 content += [cell_content] 00183 00184 result += M.write_layout((nb_of_lines, nb_of_cols), 00185 col_widths, 00186 content) 00187 00188 return result