Commit ea4ff4d218842199457631b7c4a09bd7b19caba4
1 parent
e5b363cc
Exists in
master
and in
1 other branch
- radio: added support for multiple right/wrong options, where only a random sel…
…ection is taken (with only 1 correct option)
Showing
4 changed files
with
59 additions
and
75 deletions
Show diff stats
BUGS.md
| ... | ... | @@ -11,41 +11,6 @@ |
| 11 | 11 | |
| 12 | 12 | # TODO |
| 13 | 13 | |
| 14 | -```yaml | |
| 15 | -# constroi pergunta com opções indicadas e pontuação dada em baixo caso resposta | |
| 16 | -# marque essa opção ou o seu simétrico se não marcar | |
| 17 | -type: checkbox | |
| 18 | -options: | |
| 19 | - - option1 | |
| 20 | - - option2 | |
| 21 | - - option3 | |
| 22 | -correct: [1, -1, 1] | |
| 23 | - | |
| 24 | - | |
| 25 | -# Para cada opção escolhe aleatoriamente right ou wrong e controi pergunta como | |
| 26 | -# em cima. A ideia é wrongN ser a mesma pergunta mas ao contrário de rightN. | |
| 27 | -type: checkbox | |
| 28 | -options: | |
| 29 | - - [right1, wrong1] | |
| 30 | - - [right2, wrong2] | |
| 31 | - - [right3, wrong3] | |
| 32 | -correct: [1, 1.5, 1] | |
| 33 | - | |
| 34 | - | |
| 35 | -# randomly choose 1 right_option and choose more 2 from wrong_options. | |
| 36 | -type: radio | |
| 37 | -right_options: | |
| 38 | - - right1 | |
| 39 | - - right2 | |
| 40 | - - right3 | |
| 41 | -wrong_options: | |
| 42 | - - wrong1 | |
| 43 | - - wrong2 | |
| 44 | - - wrong3 | |
| 45 | - - wrong4 | |
| 46 | -choose: 3 | |
| 47 | -``` | |
| 48 | - | |
| 49 | 14 | - servir imagens/ficheiros. |
| 50 | 15 | - session management. close after inactive time. |
| 51 | 16 | - each topic only loads a sample of K questions (max) in random order. |
| ... | ... | @@ -65,6 +30,7 @@ choose: 3 |
| 65 | 30 | |
| 66 | 31 | # FIXED |
| 67 | 32 | |
| 33 | +- radio: suporte para multiplas opcoes correctas e erradas, escolhendo-se uma selecção aleatoria destas (so com 1 certa). | |
| 68 | 34 | - checkbox: cada opção pode ser uma dupla (certo, errado) sendo escolhida uma aleatória. |
| 69 | 35 | - async/threadpool no bcrypt do initdb. |
| 70 | 36 | - numero de estrelas depende da proporcao entre certas e erradas. | ... | ... |
README.md
demo/math/questions.yaml
| 1 | -- ref: numbers | |
| 2 | - type: checkbox | |
| 3 | - title: Números pares e primos | |
| 4 | - text: Indique as afirmações verdadeiras. | |
| 1 | +# --------------------------------------------------------------------------- | |
| 2 | +- ref: distributive_property | |
| 3 | + type: radio | |
| 4 | + title: Propriedade distributiva | |
| 5 | + text: | | |
| 6 | + Qual das seguintes opções usa a propriedade distributiva para calcular $9\times 2 - 2\times 3$? | |
| 5 | 7 | options: |
| 6 | - - ['3 é primo', '4 é primo'] | |
| 7 | - - ['2 é par', '3 é par'] | |
| 8 | - - ['1 é ímpar', '2 é ímpar'] | |
| 9 | - correct: [1,1,1] | |
| 8 | + # correct | |
| 9 | + - $2\times(9 - 3)$ | |
| 10 | + - $(9-3)\times 2$ | |
| 11 | + # wrong | |
| 12 | + - $18 - 6 = 12$ | |
| 13 | + - $2\times 9 - 2\times 3$ | |
| 14 | + - $2\times(9-2\times 3)$ | |
| 15 | + correct: [1,1,0,0,0] | |
| 16 | + choose: 3 | |
| 10 | 17 | |
| 11 | -- | |
| 12 | - ref: prime_numbers | |
| 13 | - type: radio | |
| 14 | - title: Números primos | |
| 15 | - text: Qual dos seguintes números é primo? | |
| 16 | - options: | |
| 17 | - - 13 | |
| 18 | - - 12 | |
| 19 | - - 14 | |
| 20 | - - 1, a **unidade** | |
| 18 | +# - ref: numbers | |
| 19 | +# type: checkbox | |
| 20 | +# title: Números pares e primos | |
| 21 | +# text: Indique as afirmações verdadeiras. | |
| 22 | +# options: | |
| 23 | +# - ['3 é primo', '4 é primo'] | |
| 24 | +# - ['2 é par', '3 é par'] | |
| 25 | +# - ['1 é ímpar', '2 é ímpar'] | |
| 26 | +# correct: [1,1,1] | |
| 21 | 27 | |
| 22 | -# # --------------------------------------------------------------------------- | |
| 23 | 28 | # - |
| 24 | -# ref: distributive_property | |
| 29 | +# ref: prime_numbers | |
| 25 | 30 | # type: radio |
| 26 | -# title: Propriedade distributiva | |
| 27 | -# text: | | |
| 28 | -# Qual das seguintes opções usa a propriedade distributiva para calcular $9\times 2 - 2\times 3$? | |
| 31 | +# title: Números primos | |
| 32 | +# text: Qual dos seguintes números é primo? | |
| 29 | 33 | # options: |
| 30 | -# - $2\times(9 - 3)$ | |
| 31 | -# - $18 - 6 = 12$ | |
| 32 | -# - $2\times 9 - 2\times 3$ | |
| 33 | -# - $2\times(9-2\times 3)$ | |
| 34 | +# - 13 | |
| 35 | +# - 12 | |
| 36 | +# - 14 | |
| 37 | +# - 1, a **unidade** | |
| 38 | + | |
| 34 | 39 | |
| 35 | 40 | # # --------------------------------------------------------------------------- |
| 36 | 41 | # - | ... | ... |
questions.py
| ... | ... | @@ -61,16 +61,19 @@ class QuestionRadio(Question): |
| 61 | 61 | type (str) |
| 62 | 62 | text (str) |
| 63 | 63 | options (list of strings) |
| 64 | - shuffle (bool, default=True) | |
| 65 | 64 | correct (list of floats) |
| 66 | 65 | discount (bool, default=True) |
| 67 | 66 | answer (None or an actual answer) |
| 67 | + shuffle (bool, default=True) | |
| 68 | + choose (int) # only used if shuffle=True | |
| 68 | 69 | ''' |
| 69 | 70 | |
| 70 | 71 | #------------------------------------------------------------------------ |
| 71 | 72 | def __init__(self, q): |
| 72 | 73 | super().__init__(q) |
| 73 | 74 | |
| 75 | + n = len(self['options']) | |
| 76 | + | |
| 74 | 77 | # set defaults if missing |
| 75 | 78 | self.set_defaults({ |
| 76 | 79 | 'text': '', |
| ... | ... | @@ -79,23 +82,33 @@ class QuestionRadio(Question): |
| 79 | 82 | 'discount': True, |
| 80 | 83 | }) |
| 81 | 84 | |
| 82 | - n = len(self['options']) | |
| 83 | - | |
| 84 | 85 | # always convert to list, e.g. correct: 2 --> correct: [0,0,1,0,0] |
| 85 | 86 | # correctness levels from 0.0 to 1.0 (no discount here!) |
| 86 | 87 | if isinstance(self['correct'], int): |
| 87 | 88 | self['correct'] = [1.0 if x==self['correct'] else 0.0 for x in range(n)] |
| 88 | 89 | |
| 89 | - elif len(self['correct']) != n: | |
| 90 | - logger.error(f'Number of options and correct mismatch in "{self["ref"]}", file "{self["filename"]}".') | |
| 91 | - | |
| 92 | - # generate random permutation, e.g. [2,1,4,0,3] | |
| 93 | - # and apply to `options` and `correct` | |
| 94 | 90 | if self['shuffle']: |
| 95 | - perm = list(range(n)) | |
| 96 | - random.shuffle(perm) | |
| 97 | - self['options'] = [ str(self['options'][i]) for i in perm ] | |
| 98 | - self['correct'] = [ float(self['correct'][i]) for i in perm ] | |
| 91 | + # separate right from wrong options | |
| 92 | + right = [i for i in range(n) if self['correct'][i] == 1] | |
| 93 | + wrong = [i for i in range(n) if self['correct'][i] < 1] | |
| 94 | + | |
| 95 | + self.set_defaults({'choose': 1+len(wrong)}) | |
| 96 | + | |
| 97 | + # choose 1 correct option | |
| 98 | + r = random.choice(right) | |
| 99 | + options = [ self['options'][r] ] | |
| 100 | + correct = [ 1.0 ] | |
| 101 | + | |
| 102 | + # choose remaining wrong options | |
| 103 | + random.shuffle(wrong) | |
| 104 | + nwrong = self['choose']-1 | |
| 105 | + options.extend(self['options'][i] for i in wrong[:nwrong]) | |
| 106 | + correct.extend(self['correct'][i] for i in wrong[:nwrong]) | |
| 107 | + | |
| 108 | + # final shuffle of the options | |
| 109 | + perm = random.sample(range(self['choose']), self['choose']) | |
| 110 | + self['options'] = [ str(options[i]) for i in perm ] | |
| 111 | + self['correct'] = [ float(correct[i]) for i in perm ] | |
| 99 | 112 | |
| 100 | 113 | #------------------------------------------------------------------------ |
| 101 | 114 | # can return negative values for wrong answers | ... | ... |