Problem Statement
Obviously, an exercise needs to state the actual problem that has to be
solved. This is the purpose of the problem() method, the only
mandatory method of an exercise. Let’s first give a simple example with a
single input field and a static answer.
class Multiplication(pyrope.Exercise):
def problem(self):
return pyrope.Problem(
r'What is $6 \times 7$? <<answer>>',
answer=pyrope.Natural()
)
def the_solution(self):
return 42
The problem statement consists of a template with placeholders for input and
output fields, together with a specification of the input field types. It is
is created by calling pyrope.Problem() with appropriate parameters.
pyrope.Problem(template, **ifields)
Template
An exercise template is a string with placeholders for input and output fields. The string is interpreted as Markdown to allow for basic formatting such as
Template strings will usually span multiple lines and Python’s triple quoted strings are best suited for that. In order to allow for a consistent source code indentation, PyRope will eliminate any common leading whitespace from every line in the template string.
When the template is rendered, line breaks are ignored, since text is wrapped
dynamically. To enforce a line break use a backslash at the end of a line.
Note that the backslash has to be escaped as \\ unless you use raw
strings.
An empty line in the template will insert a small vertical space and start a new paragraph.
For mathematical expressions, PyRope admits the use of \(\LaTeX\) if it
is properly enclosed in $ respectively $$ delimiters.
Tip
Using raw strings
for template strings containing \(\LaTeX\) will prevent Python from
interpreting the backslashes in \(\LaTeX\) commands as escape
sequences.
For example, write r'... $\beta$ ...' to avoid that \b is understood
as a backspace. Otherwise you would have to write '...$\\beta$...'.
Placeholders
The syntax for a placeholder is <<name>>, where name is the name of
the input or output field. The delimiters << and >> were chosen to
interfere as little as possible with markup, \(\LaTeX\), HTML or Python.
Placeholders can be placed within most Markdown elements, but only output
fields can be inserted into \(\LaTeX\) environments in the following manner
<<name:latex>>. Note that there is no syntactical difference between
placeholders for input and output fields. In the exercise below, for example,
a and b are output fields whereas answer is an input field.
import random
class Multiplication(pyrope.Exercise):
def parameters(self):
return dict(
a=random.randint(2, 9),
b=random.randint(2, 9),
)
def problem(self, a, b):
return pyrope.Problem(
r'$<<a:latex>> \times <<b:latex>> =$ <<answer>>',
answer=pyrope.Natural()
)
def the_solution(self, a, b):
return a * b
Input Fields
Input fields in PyRope are typed. This assures two important facts:
The learner gets immediate visual feedback on syntactically invalid input.
The instructor is guaranteed that variables coming from user input have the correct type.
Input field |
Python Type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The keyword arguments to pyrope.Problem() define which placeholders
stand for input fields. The keys are the names of the input fields and the
values are the input fields, created by calling the corresponding constructor.
Attention
Currently it is not possible to place input fields within \(\LaTeX\) environments, although this is planned for the future. For the time being, there are two options to deal with this:
Break up the \(\LaTeX\) environment for the input fields.
Use variables instead and ask for them in separate input fields outside the \(\LaTeX\) environment.
For example, you can not use r'... $\frac{<<a>>}{<<b>>}$ ...' to ask
for a fraction with separated input fields for numerator \(a\) and
denominator \(b\). Instead, use:
pyrope.Problem(
r'... $\frac{a}{b}$ with $a=$ <<a>> and $b=$ <<b>> ...',
a=pyrope.Int(),
b=pyrope.Int()
)
Note that PyRope also provides a pyrope.Rational input field
for fractions. With the elementwise=True option, numerator and
denominator have separate input fields.
Output Fields
Any placeholder whose name is not a keyword argument to
pyrope.Problem() is considered an output field and will be replaced
by the corresponding parameter when the problem is rendered. Therefore any
output parameter must be part of the parameters returned
by the parameters() method. PyRope takes care to properly render
output fields according to the corresponding parameter’s type. In this way
you can, for instance, embed dynamically generated Pyplot figures into your
problem statement.
Note that it is not necessary to specify the output parameters as keyword
parameters to the problem() method if they only appear in the
template string. Your linter or IDE will probably complain about unused
variables if you do so.
Output fields can be placed in all Markdown elements, even
within \(\LaTeX\) environments. However, you have to indicate when an
output field name is placed inside a \(\LaTeX\) environment to the
frontend by using the special syntax <<name:latex>> so that it can be
rendered properly.
import random
class SquareRoot(pyrope.Exercise):
def parameters(self):
root = random.randint(1, 9)
return dict(root=root, square=root**2)
def problem(self):
return pyrope.Problem(
r'The square root $\sqrt{<<square:latex>>}$ equals <<root>>.',
root=pyrope.Natural()
)
def the_solution(self, root):
return root