 ## Simple example

A simple implementation of this example only requires writing a question.html file. Note that the question parameters, such as the ball mass $m$, the angle $\theta$, the height $h$, the initial velocity $v_0$ and the distance $d$, 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, and    an 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 $50\%$ 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.

## Complex example

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 $m$, $h$, $\theta$, $v_0$, and $d$ 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, and  an 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, math
def 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 parameters    data["params"]["m"] = m    data["params"]["h"] = h    data["params"]["d"] = d    data["params"]["v0"] = v0    data["params"]["theta"] = theta
# determines if the option "none of the above" will be used or not    data["params"]["none"] = random.choice(["false","true"])
# this is the correct answer    data["params"]["t_c"] = t    # these are the distractors    data["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:

• The parameters $m$, $d$, $\theta$, and $v_0$ are generated using the Python module random
• The parameter $h$ is computed based on $m$, $d$, $\theta$, and $v_0$
• The choice of using the attribute none-of-the-above is selected at random
• The correct answer and distractors are computed using the input parameters

These 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.

## More randomization!

• We can dynamically create an image to reflect the randomly selected parameters.
• In addition to asking about the length of time the ball is in the air, we can add a second problem statement that asks the student to compute the distance the ball travels. We can then also randomly pick between the original problem statement and this new problem statement.

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, and  an 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 $\theta$. The image could be easily adapted such that the height of the cliff would also vary with the value of the parameter $h$.

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, math
def 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 parameters    data["params"]["m"] = m
data["params"]["v0"] = v0    data["params"]["theta"] = theta        # determines if the option "none of the above" will be used or not    data["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 statement        data["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 answer        data["params"]["t_c"] = '$t = ' + str(round(t,3)) + '\\rm\\ s$'        # these are the distractors        data["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 statement        data["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 answer        data["params"]["t_c"] = '$d = ' + str(round(d,3)) + '\\rm\\ m$'        # these are the distractors        data["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: 