Commit ea4ff4d218842199457631b7c4a09bd7b19caba4

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

- radio: added support for multiple right/wrong options, where only a random sel…

…ection is taken (with only 1 correct option)
@@ -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.
@@ -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 # -
@@ -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