I have modified the code of one of my own posts on Wolfram Community in order to obtain a multiple-choice online quiz that selects a random question and keeps the same question until the right answer has been inputted. This is a link to the online quiz: https://wolfr.am/vzhPnbzO
It can be taken by different students at the same time, provided that each one enters a different student id number. Student's progress is stored in the Wolfram Cloud (CloudPut) using string labels (uri) that include the student id number. In the source code, the correct answer to each question is always the first choice in the list, however different students will see the multiple choice answers in different order (RandomPermutation) when the quiz is online. The quiz looks very nice in my iPhone, but students can also work in a computer or tablet. This is the code:
fopa =
With[{
numchoices = 5,
idini = "ID000000",
letrasporlinea = 30,
estilobase = {Large, FontFamily -> "Calibri"},
estiloincisos = {FontColor -> Darker[Red]},
estilotituloprincipal = {FontWeight -> Bold},
estiloautores = {FontSize -> Medium},
opcionestitulos = Sequence[
Medium, FontColor -> Darker[Red],
Background -> Lighter[Gray, 0.9]],
opcionesplot = Sequence[
ImageSize -> Medium,
FrameTicksStyle -> Italic,
PlotTheme -> "FullAxesGrid"]
},
listaDeSecciones = {
(*In this source code the correct answer to each question is always the first choice.
Options will be shown in a random oder to each student,
see the RandomPermutation command at the end of this code *)
{"Integration by parts",
{Column[{
InsertLinebreaks["Select the evaluation of the integral:",
letrasporlinea],
TraditionalForm[HoldForm[Integrate[x*E^-x, x]]]
}],
{TraditionalForm[Expand[Integrate[x*E^-x, x]]],
TraditionalForm[Expand[Integrate[x, x]*Integrate[E^-x, x]]],
TraditionalForm[Expand[Integrate[x*E^-x^2, x]]],
TraditionalForm[Expand[Integrate[x^2*E^x/2, x]]],
TraditionalForm[Expand[Integrate[x^2*E^-x, x]]]}}},
{"Function tanslations",
{Column[{
Plot[Exp[-(x - 3)^2], {x, 0, 6},
PlotLabel -> Style["Graph of f(x)", Large],
PlotStyle -> Black,
opcionesplot],
InsertLinebreaks["Select the graph of f(x-1)",
letrasporlinea]}],
{Plot[Exp[-((x - 1) - 3)^2], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-((x - 2) - 3)^2], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-((x + 1) - 3)^2], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-((x + 2) - 3)^2], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-((x + 3) - 3)^2], {x, 0, 2 Pi}, opcionesplot]}}},
{"Graphs of functions",
{InsertLinebreaks["Select the graph of sin(x)", letrasporlinea],
{Plot[Sin[x], {x, 0, 2 Pi}, opcionesplot],
Plot[Cos[x], {x, 0, 2 Pi}, opcionesplot],
Plot[Log[x + 1], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-x], {x, 0, 2 Pi}, opcionesplot],
Plot[Exp[-x^2/6], {x, 0, 2 Pi}, opcionesplot]}}},
{"Graphs of functions",
{InsertLinebreaks["Select the graph of sin(x) and cos(x)",
letrasporlinea],
{Plot[{Sin[x], Cos[x]}, {x, 0, 2 Pi}, opcionesplot],
Plot[{Sin[x], -Sin[x]}, {x, 0, 2 Pi}, opcionesplot],
Plot[{Cos[x], -Cos[x]}, {x, 0, 2 Pi}, opcionesplot],
Plot[{-Sin[x], -Cos[x]}, {x, 0, 2 Pi}, opcionesplot],
Plot[{-Sin[x], Cos[x]}, {x, 0, 2 Pi}, opcionesplot]}}},
{"Integration by parts",
{Column[{
InsertLinebreaks["Select the evaluation of the integral:",
letrasporlinea],
TraditionalForm[HoldForm[Integrate[x*Sin[x], x]]]
}],
{TraditionalForm[Expand[Integrate[x*Sin[x], x]]],
TraditionalForm[Expand[Integrate[x, x]*Integrate[Sin[x], x]]],
TraditionalForm[Expand[Integrate[x*Sin[x^2], x]]],
TraditionalForm[Expand[Integrate[x^2*Sin[x]/2, x]]],
TraditionalForm[Expand[Integrate[x^2*Cos[x], x]]]}}}
};
FormPage[{
{"choice", "Options:"} -> <|
"Interpreter" ->
Join[MapIndexed[
Function[FromCharacterCode[#2[[1]] + 96] -> #1],
Range[numchoices]], {"update" -> -1,
"clear quiz history" -> -2}], "Control" -> RadioButtonBar,
"Input" -> -1|>,
{"matricula", "Student id number:"} -> <|
"Interpreter" -> "String", "Input" -> idini,
"Help" ->
"If you change the student id number you must select UPDATE" |>
},
Function[
ExportForm[
With[{id =
ToUpperCase[
StringReplace[
RemoveDiacritics[#matricula, Language -> "English"],
Whitespace -> ""]]},
With[
{respcorrecta = StringJoin[id, "respcorrecta"],
fallos = StringJoin[id, "fallos"],
contadorseccion = StringJoin[id, "contadorseccion"],
ordensecciones = StringJoin[id, "ordensecciones"]
},
Column[Flatten[{
Style["Online Quiz", estilotituloprincipal],
Style["Jose Luis Gomez-Munoz", estiloautores],
(* Message *)
Style[Framed["Messages",
FrameStyle -> Opacity[0]], opcionestitulos],
Which[ (* update student progress and write messages *)
#matricula == idini,
InsertLinebreaks[
"Select update, write your student ID number and press the button", letrasporlinea],
TrueQ[Or[
#choice == -2,
FailureQ[Quiet[CloudGet[respcorrecta]]],
FailureQ[Quiet[CloudGet[fallos]]],
FailureQ[Quiet[CloudGet[contadorseccion]]],
FailureQ[Quiet[CloudGet[ordensecciones]]]
]],
(* reset student progress and order of questions *)
CloudPut[0, respcorrecta];
CloudPut[0, fallos];
CloudPut[1, contadorseccion];
CloudPut[RandomSample[Range[Length[listaDeSecciones]]],
ordensecciones];
InsertLinebreaks[
"The quiz history of " <> ToString[id] <>
" was initialized", letrasporlinea],
TrueQ[And[#choice > 0,
CloudGet[contadorseccion] <= Length[listaDeSecciones],
#choice == CloudGet[respcorrecta]
]], (* correct answer: update student progress *)
With[{valseccion = CloudGet[contadorseccion]},
CloudPut[1 + valseccion, contadorseccion];
Column[{"Your answer was correct", ToString[id]}]
],
TrueQ[And[#choice > 0,
CloudGet[contadorseccion] <= Length[listaDeSecciones],
#choice != CloudGet[respcorrecta]
]], (* incorrect answer: update student progress *)
With[{valfallos = CloudGet[fallos],
valseccion = CloudGet[contadorseccion]},
CloudPut[1 + valfallos, fallos];
(*
Next line inactive if we want to keep the same question until the right answer has been inputted *)
(* CloudPut[1+valseccion,contadorseccion]; *)
Column[{"Your answer was incorrect", ToString[id]}]
],
True, (*default: do not change student progress *)
InsertLinebreaks[
"Updated " <> DateString[] <> " " <> ToString[id],
letrasporlinea]
],
With[{ (* CloudGet student progress *)
valcontadorseccion = CloudGet[contadorseccion],
valordensecciones = CloudGet[ordensecciones],
valfallos = CloudGet[fallos]},
Which[(* Next question, or end-of-quiz message *)
#matricula == idini, Nothing,
TrueQ[valcontadorseccion > Length[listaDeSecciones]],
(* end-of-quiz message *)
{InsertLinebreaks[
"You have finished this quiz. If you want to do it again, select clear history", letrasporlinea],
InsertLinebreaks["Errors: " <> ToString[valfallos],
letrasporlinea]},
True,
{
Style[Framed["History",
FrameStyle -> Opacity[0]], opcionestitulos],
InsertLinebreaks["Errors: " <> ToString[valfallos],
letrasporlinea],
InsertLinebreaks[
"Question: " <> ToString[valcontadorseccion] <>
" of " <> ToString[Length[listaDeSecciones]],
letrasporlinea],
(*Topic:*)
Style[Framed[
listaDeSecciones[[
valordensecciones[[valcontadorseccion]], 1]],
FrameStyle -> Opacity[0]], opcionestitulos],
(*Question:*)
listaDeSecciones[[
valordensecciones[[valcontadorseccion]], 2, 1]],
(*Multiple choice options, in random order:*)
permutacion = RandomPermutation[numchoices];
opciones =
Take[Permute[
listaDeSecciones[[
valordensecciones[[valcontadorseccion]], 2, 2]],
permutacion], numchoices];
correcta = PermutationReplace[1, permutacion];
CloudPut[correcta, respcorrecta];
Column[MapIndexed[
Function[
Row[{Style[FromCharacterCode[#2[[1]] + 96] <> ") ",
estiloincisos], #1}]], opciones], Dividers -> All]}
]]
}], BaseStyle -> estilobase]]],
"GIF"]
], "ResultAbove"
]];
In order to deploy:
$Permissions = "Public";
cdeploy = CloudDeploy[fopa]; (* Deploy *)
SystemOpen[cdeploy]; (* Open in the browser *)
URLShorten[cdeploy]
Hope that helps!
part
is undefined. $\endgroup$Delayed
AppearanceRules
. But then what if someone calls the form before someone who called it earlier answers? How both answers should be managed if the first is correct and the second isn't. etc etc. You could track progress based on information fromHTTPRequestData[]
. $\endgroup$