Commit 285737793e41c26cb755229456943354128ee906

Authored by Miguel Barão
1 parent 8f643ad6
Exists in master and in 1 other branch dev

- changes checkbox correct list to the same semantics as radio with

interval values in the interval [0,1]
@@ -14,7 +14,6 @@ @@ -14,7 +14,6 @@
14 14
15 # TODO 15 # TODO
16 16
17 -- checkbox devia ter correct no intervalo [0,1] tal como radio. em caso de desconto a correccção faz 2*x-1. isto permite a mesma semantica nos dois tipos de perguntas.  
18 - registar last_seen e remover os antigos de cada vez que houver um login. 17 - registar last_seen e remover os antigos de cada vez que houver um login.
19 - indicar qtos topicos faltam (>=50%) para terminar o curso. 18 - indicar qtos topicos faltam (>=50%) para terminar o curso.
20 - ao fim de 3 tentativas com password errada, envia email com nova password. 19 - ao fim de 3 tentativas com password errada, envia email com nova password.
@@ -35,6 +34,7 @@ @@ -35,6 +34,7 @@
35 34
36 # FIXED 35 # FIXED
37 36
  37 +- checkbox devia ter correct no intervalo [0,1] tal como radio. em caso de desconto a correccção faz 2*x-1. isto permite a mesma semantica nos dois tipos de perguntas.
38 - marking all options right in a radio question breaks! 38 - marking all options right in a radio question breaks!
39 - implementar servidor http com redirect para https. 39 - implementar servidor http com redirect para https.
40 - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. 40 - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question.
aprendizations/questions.py
@@ -113,8 +113,8 @@ class QuestionRadio(Question): @@ -113,8 +113,8 @@ class QuestionRadio(Question):
113 # check grade boundaries 113 # check grade boundaries
114 if self['discount'] and not all(0.0 <= x <= 1.0 114 if self['discount'] and not all(0.0 <= x <= 1.0
115 for x in self['correct']): 115 for x in self['correct']):
116 - msg = (f'If discount=true, correct values must be in the '  
117 - f'interval [0.0, 1.0] in "{self["ref"]}"') 116 + msg = (f'Correct values must be in the interval [0.0, 1.0] in '
  117 + f'"{self["ref"]}"')
118 raise QuestionException(msg) 118 raise QuestionException(msg)
119 119
120 # at least one correct option 120 # at least one correct option
@@ -217,12 +217,18 @@ class QuestionCheckbox(Question): @@ -217,12 +217,18 @@ class QuestionCheckbox(Question):
217 f'booleans in "{self["ref"]}"') 217 f'booleans in "{self["ref"]}"')
218 raise QuestionException(msg) 218 raise QuestionException(msg)
219 219
220 - # check grade boundaries (FUTURE)  
221 - # if self['discount'] and not all(0.0 <= x <= 1.0  
222 - # for x in self['correct']):  
223 - # msg = (f'If discount=true, correct values must be in the '  
224 - # f'interval [0.0, 1.0] in "{self["ref"]}"')  
225 - # raise QuestionException(msg) 220 + # check grade boundaries
  221 + if self['discount'] and not all(0.0 <= x <= 1.0
  222 + for x in self['correct']):
  223 + logger.warning(' * * * BEHAVIOR CHANGE NOTICE * * *')
  224 + msg = (f'Correct values must be in the interval [0.0, 1.0] in '
  225 + f'"{self["ref"]}"')
  226 + logger.warning(msg)
  227 + logger.warning('I will convert "correct" to the new behavior, but '
  228 + 'you should change it in the questions')
  229 + logger.warning(' * * * END OF NOTICE * * *')
  230 + # normalize to [0,1]
  231 + self['correct'] = [(x+1)/2 for x in self['correct']]
226 232
227 # if an option is a list of (right, wrong), pick one 233 # if an option is a list of (right, wrong), pick one
228 options = [] 234 options = []
@@ -232,9 +238,10 @@ class QuestionCheckbox(Question): @@ -232,9 +238,10 @@ class QuestionCheckbox(Question):
232 r = random.randint(0, 1) 238 r = random.randint(0, 1)
233 o = o[r] 239 o = o[r]
234 if r == 1: 240 if r == 1:
235 - c = -c 241 + # c = -c
  242 + c = 1.0 - c
236 options.append(str(o)) 243 options.append(str(o))
237 - correct.append(float(c)) 244 + correct.append(c)
238 245
239 # generate random permutation, e.g. [2,1,4,0,3] 246 # generate random permutation, e.g. [2,1,4,0,3]
240 # and apply to `options` and `correct` 247 # and apply to `options` and `correct`
@@ -252,21 +259,20 @@ class QuestionCheckbox(Question): @@ -252,21 +259,20 @@ class QuestionCheckbox(Question):
252 super().correct() 259 super().correct()
253 260
254 if self['answer'] is not None: 261 if self['answer'] is not None:
255 - sum_abs = sum(abs(p) for p in self['correct'])  
256 - if sum_abs < 1e-6: # case correct [0,...,0] avoid div-by-zero  
257 - self['grade'] = 1.0  
258 - 262 + x = 0.0
  263 + if self['discount']:
  264 + sum_abs = sum(abs(2*p-1) for p in self['correct'])
  265 + for i, p in enumerate(self['correct']):
  266 + x += 2*p-1 if str(i) in self['answer'] else 1-2*p
259 else: 267 else:
260 - x = 0.0  
261 -  
262 - if self['discount']:  
263 - for i, p in enumerate(self['correct']):  
264 - x += p if str(i) in self['answer'] else -p  
265 - else:  
266 - for i, p in enumerate(self['correct']):  
267 - x += p if str(i) in self['answer'] else 0.0 268 + sum_abs = sum(abs(p) for p in self['correct'])
  269 + for i, p in enumerate(self['correct']):
  270 + x += p if str(i) in self['answer'] else 0.0
268 271
  272 + try:
269 self['grade'] = x / sum_abs 273 self['grade'] = x / sum_abs
  274 + except ZeroDivisionError:
  275 + self['grade'] = 1.0 # limit p->0
270 276
271 277
272 # ============================================================================ 278 # ============================================================================
demo/math/addition/questions.yaml
@@ -18,6 +18,6 @@ @@ -18,6 +18,6 @@
18 - Propriedade comutativa, $x+y=y+x$. 18 - Propriedade comutativa, $x+y=y+x$.
19 # wrong 19 # wrong
20 - Existência de elemento absorvente, $x+1=1$. 20 - Existência de elemento absorvente, $x+1=1$.
21 - correct: [1, 1, 1, 1, -1] 21 + correct: [1, 1, 1, 1, 0]
22 solution: | 22 solution: |
23 A adição não tem elemento absorvente. 23 A adição não tem elemento absorvente.