questions-tutorial.yaml
22.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
---
# ----------------------------------------------------------------------------
- type: information
ref: tut-test
title: Configuração do teste
text: |
O teste é configurado num ficheiro `yaml`
(ver especificação [aqui](https://yaml.org)).
A configuração contém a identificação do teste, base de dados dos alunos,
ficheiros de perguntas a importar e uma selecção de perguntas e respectivas
cotações.
Exemplo:
```yaml
---
# --------------------------------------------------------------------------
ref: tutorial # referência, pode ser reusada em vários turnos
title: Demonstração # título da prova
database: students.db # base de dados previamente criada com initdb
answers_dir: ans # directório onde ficam os testes dos alunos
# opcional
duration: 60 # duração da prova em minutos (default: inf)
autosubmit: true # submissão automática (default: false)
show_points: true # mostra cotação das perguntas (default: true)
scale: [0, 20] # limites inferior e superior da escala (default: [0,20])
scale_points: true # normaliza cotações para a escala definida
jobe_server: moodle-jobe.uevora.pt # server used to compile & execute code
debug: false # mostra informação de debug no browser
# --------------------------------------------------------------------------
questions_dir: ~/topics # raíz da árvore de directórios das perguntas
# Ficheiros de perguntas a importar (relativamente a `questions_dir`)
files:
- tabelas.yaml
- topic_A/questions.yaml
- topic_B/part_1/questions.yaml
- topic_B/part_2/questions.yaml
# --------------------------------------------------------------------------
# Especificação das perguntas do teste e respectivas cotações.
# O teste é uma lista de perguntas, onde cada pergunta é especificada num
# dicionário com a referência da pergunta e a respectiva cotação.
questions:
- ref: pergunta1
points: 3.5
- ref: pergunta2
points: 2.0
# a cotação é 1.0 por defeito
- ref: pergunta3
# uma string (não dict), é interpretada como referência
- tabela-auxiliar
# escolhe aleatoriamente uma das variantes
- ref: [pergunta3a, pergunta3b]
points: 0.5
# --------------------------------------------------------------------------
```
A ordem das perguntas é mantida quando apresentada no teste.
O mesmo teste pode ser realizado várias vezes em turnos diferentes, não é
necessário alterar nada.
# ----------------------------------------------------------------------------
- type: information
ref: tut-questions
title: Especificação das perguntas
text: |
As perguntas estão definidas num ou mais ficheiros `yaml` como uma lista de
perguntas, onde cada pergunta é um dicionário.
Por exemplo, um ficheiro com o conteúdo abaixo contém duas perguntas, uma
de escolha múltipla e outra apenas informativa:
```yaml
---
#---------------------------------------------------------------------------
- type: radio
ref: chave-unica-1
text: Quanto é $1+1$?
options:
- 1
- 2
- 3
#---------------------------------------------------------------------------
- type: information
ref: chave-unica-2
text: |
Quando o texto da pergunta tem várias linhas, dá jeito usar o símbolo
`|` de pipe, para indicar que tudo o que estiver indentado faz parte do
texto.
É o caso desta pergunta.
O texto das perguntas é escrito em `markdown` e suporta fórmulas em
LaTeX.
#---------------------------------------------------------------------------
```
As chaves são usadas para construir o teste e não se podem repetir, mesmo em
ficheiros diferentes.
De seguida mostram-se exemplos dos vários tipos de perguntas.
# ----------------------------------------------------------------------------
- type: radio
ref: tut-radio
title: Escolha simples, uma opção correcta.
text: |
As perguntas de escolha simples, permitem fazer uma pergunta e apresentar
várias opções de resposta em que apenas uma delas está certa.
A utilização mais simples é a seguinte:
```yaml
- type: radio
ref: pergunta-1
title: Escolha simples, uma opção correcta.
text: |
Bla bla bla.
options:
- Opção 0
- Opção 1
- Opção 2
- Opção 3
- Opção 4
```
Sem outras configurações, assume-se que a primeira opção é a resposta
correcta ("Opção 0" neste caso) e as 5 opções são apresentadas por ordem
aleatória.
Para evitar que os alunos memorizem os textos das opções, podem definir-se
várias opções correctas com escrita ligeiramente diferente, sendo escolhida
apenas uma delas para apresentação.
Por exemplo, se as 2 primeiras opções estiverem correctas e as restantes
erradas, e quisermos apresentar ao aluno 3 opções no total, acrescenta-se:
```yaml
correct: [1, 1, 0, 0, 0]
choose: 3
```
Neste caso, será escolhida uma opção certa e duas erradas.
Os valores em `correct` representam o grau de correcção no intervalo [0, 1]
onde 1 representa 100% certo e 0 representa 0%. Podem ser usados valores
entre 0 e 1, sendo atribuída a respectiva cotação, mas só o valor 1
representa uma opção certa.
Por defeito, as opções são apresentadas por ordem aleatória, mas é possível
usar a ordem predefinida. Por exemplo, para manter a ordem e indicar que a
resposta correcta é a do meio define-se:
```yaml
correct: [0, 0, 1, 0, 0]
shuffle: false
```
As respostas erradas descontam, tendo uma cotação de $-1/(n-1)$ do valor da
pergunta, onde $n$ é o número de opções apresentadas ao aluno (a ideia é o
valor esperado ser zero quando as respostas são aleatórias e uniformemente
distribuídas). Para não descontar acrescenta-se:
```yaml
discount: false
```
options:
- Opção 0 (certa)
- Opção 1 (certa)
- Opção 2
- Opção 3
- Opção 4
correct: [1, 1, 0, 0, 0]
choose: 3
solution: |
A solução correcta é a **Opção 0** ou a **Opção 1**.
# ----------------------------------------------------------------------------
- type: checkbox
ref: tut-checkbox
title: Escolha múltipla, várias opções correctas
text: |
As perguntas de escolha múltipla permitem apresentar um conjunto de opções
podendo ser seleccionadas várias em simultâneo.
Funcionam como múltiplas perguntas independentes de resposta sim/não.
As respostas que devem ou não ser seleccionadas são indicadas com `1` e `0`
ou com booleanos `true` e `false`.
Cada resposta errada desconta um valor que é o simétrico da resposta certa.
Se acertar uma opção ganha `+1`, se errar obtém `-1`.
```yaml
- type: checkbox
ref: tut-checkbox
title: Escolha múltipla, várias opções correctas
text: |
Bla bla bla.
options:
- Opção 0 (certa)
- Opção 1
- Opção 2
- Opção 3 (certa)
- Opção 4
correct: [1, 0, 0, 1, 0]
```
Neste exemplo, seleccionando as opções 0 e 3 obtém-se cotação `+1` em cada
uma, enquanto que seleccionando erradamente as opções 1, 2 e 4 obtém-se
cotação `-1`.
Do mesmo modo, não seleccionando as opções certas 0 e 3 obtém-se a cotação
`-1` em cada uma, e não seleccionando (correctamente) as 1, 2 e 4 obtém-se
`+1` em cada.
*(Neste tipo de perguntas não há forma de responder a apenas algumas delas,
são sempre todas corrigidas. Se um aluno só sabe a resposta a algumas das
opções, deve ter cuidado porque as restantes também serão classificadas e
arrisca-se a ter cotação negativa)*
Cada opção pode opcionalmente ser escrita como uma afirmação e o seu
contrário, de maneira a aumentar a variabilidade dos textos.
Por exemplo:
```yaml
options:
- ['O céu é azul', 'O céu não é azul']
- ['Um triangulo tem 3 lados', 'Um triangulo tem 2 lados']
- O nosso planeta tem um satélite natural
correct: [1, 1, 1]
```
Assume-se que a primeira alternativa de cada opção tem a cotação indicada
em `correct`, enquanto a segunda alternativa tem a cotação contrária.
Tal como nas perguntas do tipo `radio`, podem ser usadas as configurações
`shuffle` e `discount` com valor `false` para as desactivar.
Se `discount` é `false` então as respostas erradas têm cotação 0 em vez do
simétrico.
options:
- ['Opção 0 (sim)', 'Opção 0 (não)']
- ['Opção 1 (não)', 'Opção 1 (sim)']
- Opção 2 (não)
- Opção 3 (sim)
correct: [1, 0, 0, 1]
shuffle: false
# ----------------------------------------------------------------------------
- type: text
ref: tut-text
title: Resposta de texto em linha
text: |
Este tipo de perguntas permite uma resposta numa linha de texto. A resposta
está correcta se coincidir exactamente com alguma das respostas admissíveis.
```yaml
- type: text
ref: tut-text
title: Resposta de texto em linha
text: |
De que cor é o céu?
Escreva a resposta em português.
correct: ['azul', 'Azul', 'AZUL']
```
Neste caso, as respostas aceites são `azul`, `Azul` ou `AZUL`.
Em alguns casos pode ser conveniente transformar a resposta antes de a
comparar, por exemplo para remover espaços ou converter para minúsculas.
A opção `transform` permite dar uma sequência de transformações a aplicar à
resposta do aluno, por exemplo:
```yaml
transform: ['trim', 'lower']
correct: ['azul']
```
Estão disponíveis as seguintes transformações:
* `trim` remove os espaços do início e fim da resposta, os espaços do meio
mantêm-se inalterados.
* `remove_space` remove todos os espaços (início, meio e fim).
* `normalize_space` remove espaços do início e fim (trim), e substitui
múltiplos espaços por um único espaço (no meio).
* `lower` e `upper` convertem respectivamente para minúsculas e maiúsculas.
transform: ['trim', 'lower']
correct: ['azul']
solution: |
O céu é `azul`, pelo menos durante o dia e se estiver bom tempo...
# ---------------------------------------------------------------------------
- type: text-regex
ref: tut-text-regex
title: Resposta de texto em linha, expressão regular
text: |
Este tipo de pergunta é semelhante à linha de texto da pergunta anterior.
A única diferença é que esta é validada por uma expressão regular.
```yaml
- type: text-regex
ref: tut-text-regex
title: Resposta de texto em linha
text: |
Bla bla bla
correct: '(VERDE|[Vv]erde)'
```
Neste exemplo a expressão regular é `(VERDE|[Vv]erde)`.
Também se pode dar uma lista de expressões regulares. Nesse caso a resposta
é considerada correcta se fizer match com alguma delas.
No exemplo acima, poder-se-ia ter usado uma lista
```yaml
correct:
- 'VERDE'
- '[Vv]erde'
```
---
**Atenção:** A expressão regular deve seguir as convenções da suportadas em
python (ver
[Regular expression operations](https://docs.python.org/3/library/re.html)).
Em particular, a expressão regular acima também aceita a resposta
`verde, azul`.
Deve marcar-se o início e final `^(VERDE|[Vv]erde)$` para evitar estas
situações.
correct: '(VERDE|[Vv]erde)'
solution: |
Deveria ter escrito `VERDE` ou `Verde` ou `verde`.
# ---------------------------------------------------------------------------
- type: numeric-interval
ref: tut-numeric-interval
title: Resposta numérica em linha de texto
text: |
Este tipo de perguntas esperam uma resposta numérica (vírgula flutuante).
O resultado é considerado correcto se estiver dentro do intervalo fechado
indicado.
```yaml
- type: numeric-interval
ref: tut-numeric-interval
title: Resposta numérica em linha de texto
text: |
Escreva o número $\pi$ com pelo menos duas casa decimais.
correct: [3.14, 3.15]
```
Neste exemplo o intervalo de respostas correctas é o intervalo fechado
[3.14, 3.15].
Se em vez de dar um intervalo, apenas for indicado um valor numérico $n$,
este é automaticamente convertido para para um intervalo $[n,n]$.
**Atenção:** as respostas têm de usar o ponto como separador decimal.
Em geral são aceites números inteiros, como `123`,
ou em vírgula flutuante, como em `0.23`, `1e-3`.
correct: [3.14, 3.15]
solution: |
Sabemos que $\pi\approx 3.14159265359$.
Portanto, um exemplo de uma resposta correcta é `3.1416`.
# ---------------------------------------------------------------------------
- type: textarea
ref: tut-textarea
title: Resposta em múltiplas linhas de texto
text: |
Este tipo de perguntas permitem respostas em múltiplas linhas de texto e
são as mais flexíveis.
A resposta é enviada para um programa externo para ser avaliada.
O programa externo é um programa que tem de ser executável pelo pelo
sistema operativo (pode ser um binário ou script desde que o respectivo
interpretador instalado).
Este programa externo recebe a resposta submetida pelo aluno via `stdin` e
devolve a classificação via `stdout`.
Exemplo:
```yaml
- type: textarea
ref: tut-textarea
title: Resposta em múltiplas linhas de texto
text: |
Bla bla bla
correct: correct/correct-question.py # programa a executar
timeout: 5
```
Neste exemplo, o programa de avaliação é um script python que verifica se a
resposta contém as três palavras red, green e blue, e calcula uma nota no
intervalo 0.0 a 1.0.
O programa externo é executado num processo separado e a interacção faz-se
via stdin/stdout.
Se o programa externo exceder o `timeout` indicado (em segundos),
este é automaticamente terminado e é atribuída a classificação de 0.0
valores na pergunta.
Após terminar a correcção, o programa externo deve enviar a classificação
para o stdout.
Pode simplesmente fazer `print` da classificação como um número em vírgula
flutuante, por exemplo
```yaml
0.75
```
ou opcionalmente escrever em formato json ou yaml, eventualmente com um
comentário que será arquivado com o teste.
Exemplo:
```yaml
grade: 0.5
comments: |
Esqueceu-se de algumas cores.
A resposta correcta era `red green blue`.
```
O comentário é mostrado na revisão de prova.
answer: |
Aqui o aluno escreve a resposta.
Esta caixa aumenta de tamanho automaticamente e
pode estar previamente preenchida como neste caso (use `answer: texto`).
correct: correct/correct-question.py
timeout: 5
# ---------------------------------------------------------------------------
- type: information
ref: tut-information
title: Texto informativo
text: |
As perguntas deste tipo não contam para avaliação. O objectivo é fornecer
instruções para os alunos, por exemplo tabelas para consulta, fórmulas, etc.
Nesta, tal como em todos os tipos de perguntas podem escrever-se fórmulas
em LaTeX. Exemplo:
A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
definida pela função densidade de probabilidade
$$
p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
\exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
$$
---
```yaml
- type: information
ref: tut-information
title: Texto informativo
text: |
A distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é
definida pela função densidade de probabilidade
$$
p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}
\exp\Big({-\frac{(x-\mu)^2}{2\sigma^2}}\Big).
$$
```
# ---------------------------------------------------------------------------
- type: success
ref: tut-success
title: Texto informativo (sucesso)
text: |
Não conta para avaliação. É apenas o aspecto gráfico que muda.
Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com uma
fonte e cor diferente.
Também se podem escrever troços de código coloridos conforme a linguagem:
```C
int main() {
printf("Hello world!");
return 0; // comentario
}
```
---
```yaml
- type: success
ref: tut-success
title: Texto informativo (sucesso)
text: |
Não conta para avaliação. É apenas o aspecto gráfico que muda.
Um pedaço de código em linha, por exemplo `x = sqrt(z)` é marcado com
uma fonte e cor diferente.
Também se podem escrever troços de código coloridos conforme a
linguagem:
```C
int main() {
printf("Hello world!");
return 0; // comentario
}
```
```
# ---------------------------------------------------------------------------
- type: warning
ref: tut-warning
title: Texto informativo (aviso)
text: |
Não conta para avaliação.
Neste exemplo mostramos como se pode construir uma tabela como a seguinte:
Left | Center | Right
-----------------|:----------------:|----------:
*hello* | $\sin(x^2)$ | $1600.00
**world** | $\frac{1}{2\pi}$ | $12.50
`code` | $\sqrt{\pi}$ | $1.99
As tabelas podem conter Markdown e LaTeX e permitem alinhamento das colunas,
mas o markdown é muito simples e não permite mais funcionalidades.
---
```yaml
- type: warning
ref: tut-warning
title: Texto informativo (aviso)
text: |
Bla bla bla
Left | Center | Right
-----------------|:----------------:|----------:
*hello* | $\sin(x^2)$ | $1600.00
**world** | $\frac{1}{2\pi}$ | $12.50
`code` | $\sqrt{\pi}$ | $1.99
```
# ----------------------------------------------------------------------------
- type: alert
ref: tut-alert1
title: Texto informativo (perigo) - versão 1
text: |
Não conta para avaliação. Texto importante.

As imagens podem ser adicionadas usando a notação standard em markdown. Há
duas possibilidads:
- Imagens inline: não têm título definido e podem ser incluídas no meio de
uma linha de texto usando``.
- Imagens centradas com título: ``.
O título é colocado por baixo da imagem. Pode ser uma string vazia.
- type: alert
ref: tut-alert2
title: Texto informativo (perigo) - versão 2
text: |
Não conta para avaliação. Texto importante.

As imagens podem ser adicionadas usando a notação standard em markdown. Há
duas possibilidads:
- Imagens inline: não têm título definido e podem ser incluídas no meio de
uma linha de texto usando ``.
- Imagens centradas com título: ``.
O título é colocado por baixo da imagem. Pode ser uma string vazia.
# ----------------------------------------------------------------------------
- type: information
text: |
This question is not included in the test and will not show up.
It also lacks a "ref" and is automatically named
`questions/questions-tutorial.yaml:0013`.
A warning is shown on the console about this.
The number at the end is the index position of this question.
Indices start at 0.
# ----------------------------------------------------------------------------
- type: generator
ref: tut-generator
script: generate-question.py
args: [1, 100]
# ----------------------------------------------------------------------------
- type: information
ref: tut-yamllint
title: Sugestões para validar yaml
text: |
Como os testes e perguntas são ficheiros `yaml`, é conveniente validar se
estão correctamente definitos. Um *linter* recomendado é o `yamllint`. Pode
ser instalado com `pip install yamllint` e usado do seguinte modo:
```sh
yamllint test.yaml
yamllint questions.yaml
```
No caso de programas geradores de perguntas e programas de correcção de
respostas pode usar-se um *pipe*:
```sh
generate-question | yamllint -
correct-answer | yamllint -
```
# ----------------------------------------------------------------------------
# - type: code
# ref: tut-code
# title: Submissão de código (JOBE)
# text: |
# É possível enviar código para ser compilado e executado por um servidor
# JOBE instalado separadamente, ver [JOBE](https://github.com/trampgeek/jobe).
# ```yaml
# - type: code
# ref: tut-code
# title: Submissão de código (JOBE)
# text: |
# Escreva um programa em C que recebe uma string no standard input e
# mostra a mensagem `hello ` seguida da string.
# Por exemplo, se o input for `Maria`, o output deverá ser `hello Maria`.
# language: c
# correct:
# - stdin: 'Maria'
# stdout: 'hello Maria'
# - stdin: 'xyz'
# stdout: 'hello xyz'
# ```
# Existem várias linguagens suportadas pelo servidor JOBE (C, C++, Java,
# Python2, Python3, Octave, Pascal, PHP).
# O campo `correct` deverá ser uma lista de casos a testar.
# Se um caso incluir `stdin`, este será enviado para o programa e o `stdout`
# obtido será comparado com o declarado. A pergunta é considerada correcta se
# todos os outputs coincidirem.
# Por defeito é o usado o servidor JOBE declarado no teste. Para usar outro
# diferente nesta pergunta usa-se a opção `server: 127.0.0.1` com o endereço
# apropriado.
# answer: |
# #include <stdio.h>
# int main() {
# char name[20];
# scanf("%s", name);
# printf("hello %s", name);
# }
# # server: 192.168.1.85
# language: c
# correct:
# - stdin: 'Maria'
# stdout: 'hello Maria'
# - stdin: 'xyz'
# stdout: 'hello xyz'