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 | ... | ... |