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,41 +11,6 @@ | ||
11 | 11 | ||
12 | # TODO | 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 | - servir imagens/ficheiros. | 14 | - servir imagens/ficheiros. |
50 | - session management. close after inactive time. | 15 | - session management. close after inactive time. |
51 | - each topic only loads a sample of K questions (max) in random order. | 16 | - each topic only loads a sample of K questions (max) in random order. |
@@ -65,6 +30,7 @@ choose: 3 | @@ -65,6 +30,7 @@ choose: 3 | ||
65 | 30 | ||
66 | # FIXED | 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 | - checkbox: cada opção pode ser uma dupla (certo, errado) sendo escolhida uma aleatória. | 34 | - checkbox: cada opção pode ser uma dupla (certo, errado) sendo escolhida uma aleatória. |
69 | - async/threadpool no bcrypt do initdb. | 35 | - async/threadpool no bcrypt do initdb. |
70 | - numero de estrelas depende da proporcao entre certas e erradas. | 36 | - numero de estrelas depende da proporcao entre certas e erradas. |
README.md
@@ -132,7 +132,7 @@ Edit `rc.conf` | @@ -132,7 +132,7 @@ Edit `rc.conf` | ||
132 | pflog_flags="" | 132 | pflog_flags="" |
133 | pflog_logfile="/var/log/pflog" | 133 | pflog_logfile="/var/log/pflog" |
134 | 134 | ||
135 | -Reboot. | 135 | +Reboot or `sudo service pf start`. |
136 | 136 | ||
137 | ## Troubleshooting | 137 | ## Troubleshooting |
138 | 138 |
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 | options: | 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 | # type: radio | 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 | # options: | 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,16 +61,19 @@ class QuestionRadio(Question): | ||
61 | type (str) | 61 | type (str) |
62 | text (str) | 62 | text (str) |
63 | options (list of strings) | 63 | options (list of strings) |
64 | - shuffle (bool, default=True) | ||
65 | correct (list of floats) | 64 | correct (list of floats) |
66 | discount (bool, default=True) | 65 | discount (bool, default=True) |
67 | answer (None or an actual answer) | 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 | def __init__(self, q): | 72 | def __init__(self, q): |
72 | super().__init__(q) | 73 | super().__init__(q) |
73 | 74 | ||
75 | + n = len(self['options']) | ||
76 | + | ||
74 | # set defaults if missing | 77 | # set defaults if missing |
75 | self.set_defaults({ | 78 | self.set_defaults({ |
76 | 'text': '', | 79 | 'text': '', |
@@ -79,23 +82,33 @@ class QuestionRadio(Question): | @@ -79,23 +82,33 @@ class QuestionRadio(Question): | ||
79 | 'discount': True, | 82 | 'discount': True, |
80 | }) | 83 | }) |
81 | 84 | ||
82 | - n = len(self['options']) | ||
83 | - | ||
84 | # always convert to list, e.g. correct: 2 --> correct: [0,0,1,0,0] | 85 | # always convert to list, e.g. correct: 2 --> correct: [0,0,1,0,0] |
85 | # correctness levels from 0.0 to 1.0 (no discount here!) | 86 | # correctness levels from 0.0 to 1.0 (no discount here!) |
86 | if isinstance(self['correct'], int): | 87 | if isinstance(self['correct'], int): |
87 | self['correct'] = [1.0 if x==self['correct'] else 0.0 for x in range(n)] | 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 | if self['shuffle']: | 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 | # can return negative values for wrong answers | 114 | # can return negative values for wrong answers |