Commit 285737793e41c26cb755229456943354128ee906
1 parent
8f643ad6
Exists in
master
and in
1 other branch
- changes checkbox correct list to the same semantics as radio with
interval values in the interval [0,1]
Showing
3 changed files
with
30 additions
and
24 deletions
Show diff stats
BUGS.md
| @@ -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. |