Skip to content

Question blocks

Introduction

Question blocks add flexibility to STACK questions by adding functional structures to the CASText. These are new from v4.0 onwards.

For example, you can add in a conditional statement to selectively include materials in the version of the CASText depending on values of variables. This is useful in randomly generated contexts, especially within model solutions and randomly generated diagrams/charts.

For maximum flexibility, blocks can be nested and conditionally evaluated. A body of CASText is then repeatedly processed until all blocks have been interpreted into CASText. This is a core part of CASText and so applied to all appropriate parts of the question.

Note: The parameters to blocks in the question body may NOT depend on the student's answers. This means that you cannot reveal an input block based on student input, well not just by using an [[if/]]-block. But you may still adapt PRT feedback as much as you want. Such adaptation requires persistent modifiable question state and is not currently possible in STACK; however, there is work being done to create systems that would allow it.

General syntax

The syntax is quite similar to XML but preserving the style [[ ... ]] used in the inputs and potential response tree declarations.

[[ block_type param1="value1" param2='value2' ... paramN="valueN" ]]
Some content.
[[/ block_type ]]

This syntax avoids issues with the rich text editors used in Moodle but it is still recommended to use the plain text editor to avoid excess line changes and white space generated by the WYSIWYG editors.

Notes

  1. In closing a block you must use [[/ "blockname"]] where "blockname" must be used, and it must match the previous opening block.
  2. White space is tolerated in block definitions and after the / in the closing block, but is not necessary.
  3. The parameters have the following syntax: param1="value1". Blocks define what are valid identifiers and parameters. The identifiers must not be in quotes (and so cannot contain spaces). The parameters must be in quotes, and either param1="value1" or param1='value1' is accepted.
  4. Typically param1 will be a valid Maxima identifier, e.g. a variable name and the value would be a valid Maxima expression.
  5. The parameter value must be surrounded by quotes, and both "value" and 'value' are accepted.

Conditional blocks

The common if statement is written as:

[[ if test="some_CAS_expression_evaluating_to_true_or_false" ]]
The expression seems to be true.
[[/ if ]]

The if block requires a parameter called test and the value must be a Maxima expression which evaluates to true or false.

The if block uses a special syntax expansion that provides it a way to handle else cases. For example,

[[ if test='oddp(rand(5))' ]]
This is an odd block!
[[ else ]]
This is an even block!
[[/ if]]

There is an else if type of structure using elif (Python coders won the syntax selection vote),

[[ if test='oddp(var)' ]]
This is an odd block!
[[ elif test='is(var=0)' ]]
It might be even but it is also zero.
[[ else ]]
This is an even block!
[[/ if]]

Note that you may have to evaluate your expression explicitly. Maxima does not always evaluate predicates to true or false. For example, you might expect p<1 in the following to evaluate to true.

[[ define p="0" /]] \(p\) is now {@p@}.
[[ if test="p<1"]]
\(p\) is less than 1.
[[ else ]]
\(p\) is not less than 1.
[[/ if ]]

However, it remains unevaluated. The true branch is therefore not satisfied. Also, the else branch is literally converted to a condition not(p<1) which in this case is also unevaluated. The overall effect is that neither the if or the else branch is included. This might be not be the expected behaviour!

To address this explicitly evaluate your expressions as predicates.

[[ if test="is(p<1)"]]

Teachers can also use evaluation with simplification and predicates as follows:

[[ if test="ev(p<1,simp,pred)"]]

It is the responsibility of the question author to ensure that every test in an if block evaluates to true or false.

Foreach loop

Foreach blocks iterate over lists or sets and repeat their content redefining variables for each repetition.

[[ foreach x="[1,2,3]" ]]{#x#} [[/ foreach ]]

You may have multiple variables and they will be iterated over in sync and the variables may also come from Maxima. Should one of the lists or set be shorter/smaller the iteration will stop when the first one ends.

[[ foreach x="[1,2,3]" y="makelist(x^2,x,4)" ]] ({#x#},{#y#}) [[/ foreach ]]

Because the foreach block needs to evaluate the lists/sets before it can do the iteration, using foreach blocks will require one additional CAS evaluation for each nested level of foreach blocks.

Define block

The define block is a core component of the foreach block, but it may also be used elsewhere. Its function is to change the value of a CAS variable in the middle of CASText. For example:

[[ define x='1' /]] {#x#}, [[ define x='x+1' /]] {#x#}, [[ define x='x+1' /]] {#x#}

should print "1, 2, 3". You may define multiple variables in the same block and the order of define operations is from left to right so "[[ define a='1' b='a+1' c='a+b' /]] {#a#}, {#b#}, {#c#}" should generate the same output.

Note, the use of define provides an alternative to using the question variables. Variables here are defined on the fly. However, we do not recommend this is done routinely.

  1. the readability of the code will suffer.
  2. question variables are available elsewhere in the question, but define blocks are only available in that CASText. This feature can also be used to your advantage.

Comment blocks

Comment blocks allow you to put content into CASText which will not be seen by students.

[[ comment ]] Place comments here which will not appear to students. [[/ comment ]]

Note that, in the current form the comment block requires that the contents are syntactically correct so no mismatched blocks are possible inside comments. (We intend to change this in the future.)

The debug block

The special "debug" block allows question authors to see all the values of variables created during a session in a table. Do not leave this block in a live question!

[[ debug /]]

Empty blocks

Some blocks do not have content. For example, the [[ define x='1' /]] block above does not include content. The following is correct syntax:

[[ define x='1']] [[/ define]]

But we think the following is much more direct, and clean.

[[ define x='1' /]]

There are other kinds of [[ emptyblocks /]], which are useful in certain cases and developers of new blocks might like to consider this as a possibility.

While the define block does not generate any visible content like all block also empty blocks may be used to generate output. [[ debug /]] is an example of this.

JSXGraph blocks

STACK supports inclusion of dynamic graphs using JSXGraph: http://jsxgraph.uni-bayreuth.de/wiki/. See the specific documentation on including JSXGraph elements.

[[jsxgraph]]
  // boundingbox:[left, top, right, bottom]
  var board = JXG.JSXGraph.initBoard(divid, {boundingbox: [-3, 2, 3, -2], axis: true, showCopyright: false});
  var f = board.jc.snippet('sin(1/x)', true, 'x', true);
  board.create('functiongraph', [f,-3,3]);
[[/jsxgraph]]