Allow students to select from multiple options.
A simple implementation of this example only requires writing a question.html
file. Note that the question parameters, such as the ball mass , the angle , the height , the initial velocity and the distance , have fixed values.
Consequently, the correct answer is also fixed.
<pl-question-panel><p>A cannon ball with mass $m = 1.8 \rm\ kg$ is fired downward from a cliff at a height$h = 2.67 \rm\ m$, at an angle $\theta = 31^o$ with respect to the horizontal, andan initial velocity $v_0 = 20 \rm\ m/s$, as illustrated in the figure below.</p><p><pl-figure file-name="image.png" directory="clientFilesQuestion" width="300"></pl-figure></p><p>Suppose the ball hits the ground a distance $d = 4 \rm\ m$ from the base of the cliff. How long is the ball in the air?Assume the acceleration due to gravity is $g=9.8 \rm\ m/s^2$.</p></pl-question-panel><pl-multiple-choice answers-name="t" none-of-the-above="true"><pl-answer correct="false">$t = 0.2 \rm\ s$</pl-answer><pl-answer correct="false">$t = 0.388 \rm\ s$</pl-answer><pl-answer correct="true" >$t = 0.233 \rm\ s$</pl-answer><pl-answer correct="false">$t = 0.259 \rm\ s$</pl-answer><pl-answer correct="false">$t = 0.738 \rm\ s$</pl-answer></pl-multiple-choice>
This question uses the attribute none-of-the-above="true"
in the pl-multiple-choice
element. This attribute adds the option "None of the above" as an alternative among the other options defined by the pl-answer
tags. The answer "None of the above" will be true (replacing the correct answer) with probability.
Unfortunately, this implementation only creates one unique version of the question, with the same set of parameters and answers. The only level of randomization comes from the order in which the answers are displayed and the choice of the "None of the above" option as correct answer.
To add variability to the question, we can include dynamically-generated values in question.html
using Mustache template syntax.
In this example, we can randomly generate the parameters , , , , and and compute the corresponding correct answers and distractors.
The modified question.html
file that supports the randomization is:
<pl-question-panel><p>A cannon ball with mass $m ={{params.m}}\rm\ kg$ is fired downward from a cliff at a height$h = {{params.h}}\rm\ m$, at an angle $\theta = {{params.theta}}^o$ with respect to the horizontal, andan initial velocity $v_0 = {{params.v0}} \rm\ m/s$, as illustrated in the figure below.</p><p><pl-figure file-name="image.png" directory="clientFilesQuestion" width="300"></pl-figure></p><p>Suppose the ball hits the ground a distance $d = {{params.d}} \rm\ m$ from the base of the cliff.How long is the ball in the air?Assume the acceleration due to gravity is $g=9.8 \rm\ m/s^2$.</p></pl-question-panel><pl-multiple-choice answers-name="t" none-of-the-above={{params.none}}><pl-answer correct="true" >$t = {{params.t_c}}\rm\ s$</pl-answer><pl-answer correct="false">$t = {{params.t_x1}}\rm\ s$</pl-answer><pl-answer correct="false">$t = {{params.t_x2}}\rm\ s$</pl-answer><pl-answer correct="false">$t = {{params.t_x3}}\rm\ s$</pl-answer><pl-answer correct="false">$t = {{params.t_x4}}\rm\ s$</pl-answer></pl-multiple-choice>
To generate the parameters, we can use the following Python code in server.py
:
import random, mathdef generate(data):# gravity (m/s^2)g = 9.8# mass of the ball (kg)m = random.choice([3, 1.4, 1.6, 1.8])# horizontal distance (m)d = random.randint(4,16)# angle with horizontal (in degrees)theta = random.randint(20,40)# initial velocity (m/s)v0 = random.randint(18,25)# initial velocity components (m/s)v0x = v0*math.cos(theta*math.pi/180)v0y = v0*math.sin(theta*math.pi/180)# time in the air (s)t = round(d/v0x)# height of the cliff (m)h = round(v0y*t + 0.5*g*t**2,3)# storing the parametersdata["params"]["m"] = mdata["params"]["h"] = hdata["params"]["d"] = ddata["params"]["v0"] = v0data["params"]["theta"] = theta# determines if the option "none of the above" will be used or notdata["params"]["none"] = random.choice(["false","true"])# this is the correct answerdata["params"]["t_c"] = t# these are the distractorsdata["params"]["t_x1"] = round(math.sqrt(2*h/g), 3)data["params"]["t_x2"] = round(d/v0, 3)data["params"]["t_x3"] = round(d/v0y, 3)data["params"]["t_x4"] = round(h/v0y, 3)
The above script randomizes and computes several aspects of the question:
random
none-of-the-above
is selected at randomThese values are stored in the data["params"]
dictionary, which are used in the question.html
template.
With the addition of server.py
and templated values in question.html
, we can now generate many unique variants of this question.
Feeling adventurous? We can add even more variation to this question:
The modified question.html
file that supports this additional randomization is:
<pl-question-panel><p>A cannon ball with mass $m ={{params.m}}\rm\ kg$ is fired downward from a cliff at a height$h = {{params.h}}\rm\ m$, at an angle $\theta = {{params.theta}}^o$ with respect to the horizontal, andan initial velocity $v_0 = {{params.v0}} \rm\ m/s$, as illustrated in the figure below.</p><p><pl-drawing gradable="false" grid-size="0" width="300" height=300><pl-drawing-initial><pl-rectangle x1=20 y1=180 width="40" height="240" color="brown"></pl-rectangle><pl-circle x1=40 y1=50 radius="10" color="blue"></pl-circle><pl-vector x1=40 y1=50 angle={{params.theta}} width="80" label="v_0"></pl-vector><pl-arc-dimensions x1=40 y1=50 radius="40" start-angle="0" end-angle={{params.theta}} label="\\theta" offsetx="10" offsety="5" start-support-line="true"></pl-arc-dimensions><pl-dimensions x1="40" y1="300" x2="40" y2="50" dim-offset="200" end-support-line="true" label="h" ></pl-dimensions><pl-dimensions x1="40" y1="200" x2="100" y2="200" label="d" ></pl-dimensions></pl-drawing-initial></pl-drawing></p><p>{{params.question_text}} Assume the acceleration due to gravity is $g=9.8 \rm\ m/s^2$.</p></pl-question-panel><pl-multiple-choice answers-name="t" none-of-the-above={{params.none}}><pl-answer correct="true" >{{params.t_c}}</pl-answer><pl-answer correct="false">{{params.t_x1}}</pl-answer><pl-answer correct="false">{{params.t_x2}}</pl-answer><pl-answer correct="false">{{params.t_x3}}</pl-answer><pl-answer correct="false">{{params.t_x4}}</pl-answer></pl-multiple-choice>
By using the <pl-drawing>
element instead of <pl-figure>
, we can create a dynamic image where the orientation of the arrow is consistent with the provided angle . The image could be easily adapted such that the height of the cliff would also vary with the value of the parameter .
Also note the use of {{params.question_text}}
to display the randomly-picked problem statement.
As before, we'll use server.py
to generate parameters for the question:
import random, mathdef generate(data):# gravity (m/s^2)g = 9.8# mass of the ball (kg)m = random.choice([3, 1.4, 1.6, 1.8])# angle with horizontal (in degrees)theta = random.randint(20,40)# initial velocity (m/s)v0 = random.randint(18,25)# initial velocity components (m/s)v0x = v0*math.cos(theta*math.pi/180)v0y = v0*math.sin(theta*math.pi/180)# storing the parametersdata["params"]["m"] = mdata["params"]["v0"] = v0data["params"]["theta"] = theta# determines if the option "none of the above" will be used or notdata["params"]["none"] = "false" #random.choice(["false","true"])if random.choice([0,1]): # This variant provides the distance and asks for the time# horizontal distance (m)d = random.randint(4,16)# time in the air (s)t = d/v0x# height of the cliff (m)h = round(v0y*t + 0.5*g*t**2,3)data["params"]["h"] = h# question statementdata["params"]["question_text"] = 'Suppose the ball hits the ground a distance $d = ' + str(d) + '\\rm\\ m$ from the base of the cliff. How long is the ball in the air?'# this is the correct answerdata["params"]["t_c"] = '$t = ' + str(round(t,3)) + '\\rm\\ s$'# these are the distractorsdata["params"]["t_x1"] = '$t = ' + str(round(math.sqrt(2*h/g), 3)) + '\\rm\\ s$'data["params"]["t_x2"] = '$t = ' + str(round(d/v0, 3)) + '\\rm\\ s$'data["params"]["t_x3"] = '$t = ' + str(round(d/v0y, 3)) + '\\rm\\ s$'data["params"]["t_x4"] = '$t = ' + str(round(h/v0y, 3)) + '\\rm\\ s$'else: # This variant provides the time and asks for the distance# time in the air (s)t = round(random.uniform(0.5,0.8),2)# horizontal distance (m)d = v0x*t# height of the cliff (m)h = round(v0y*t + 0.5*g*t**2,3)data["params"]["h"] = h# question statementdata["params"]["question_text"] = 'Suppose the ball hits the ground after $t = ' + str(t) + '\\rm\\ s$. What is the distance from the base of the cliff that the ball hits the ground?'# this is the correct answerdata["params"]["t_c"] = '$d = ' + str(round(d,3)) + '\\rm\\ m$'# these are the distractorsdata["params"]["t_x1"] = '$d = ' + str(round(v0*t,3)) + '\\rm\\ m$'data["params"]["t_x2"] = '$d = ' + str(round(v0y*t,3)) + '\\rm\\ m$'data["params"]["t_x3"] = '$d = ' + str(round(0.5*g*t**2,3)) + '\\rm\\ m$'data["params"]["t_x4"] = '$d = ' + str(round(d + 0.5*g*t**2,3)) + '\\rm\\ m$'
Note the addition of code to generate a question and answers for the secondary problem statement.
Here's one instance of this fully randomized question: