Template context#
Every value a statement prints, and every value the template that
wraps it reaches for, comes from one of a handful of namespaces exposed to
\VAR{...} and to the %- ... Jinja2 statements. This page is the
reference for what lives in each one.
Where a value comes from#
Three namespaces carry almost everything you will print, and each answers a different question:
paramsholds the presentation knobs of the statement entry being rendered.varsholds the package's data: the problem'svarsin a problem render, the contest's in a contest join.contestholds the contest's metadata, with the contest's own variables one level down, undercontest.vars.
Each namespace keeps its own names, so a key in one never shadows a key in another. Reaching a value means knowing which namespace it belongs to:
\VAR{params.show_limits} %# the statement's own param
\VAR{vars.author} %# a problem/package var
\VAR{contest.title} %# contest metadata
\VAR{contest.vars.year} %# a contest var
That costs you a prefix, and it buys a statement whose numbers you can trace: a value prints wrong, and the namespace in front of it says which file to open.
The exact set of top-level names depends on what is being rendered:
| Namespace | Contents | Available in |
|---|---|---|
params |
this render's own statement params |
all renders |
vars |
the problem/package vars (problem render) or the contest vars (contest join) |
all renders |
contest |
contest.title, contest.vars.*, and when set contest.location / contest.date |
all renders |
problem |
title, limits, profiles, groups, samples, vars, params, blocks, and when set short_name, import_dir, import_file |
problem renders |
problems |
a list of the above, full in a contest join and metadata-only in a document | contest join; documents |
lang, languages, keyed_languages |
environment languages | all renders |
problem vs problems
A problem render (rbx st b, and each problem inside a contest join)
exposes the singular problem, and there is no problems. The
contest joining document exposes the list problems, and there is no
singular problem. Documents also
get problems, but metadata-only: per-problem title, short_name,
limits, profiles and groups, with no blocks, samples or import
handles.
params vs vars#
They answer two different questions, which is why they sit in two different namespaces.
varsis your problem's own data: constraints, an author name, a flag your statement text keys off. It comes fromvarsinproblem.rbx.yml, or from the contest'svarsin a contest join.paramsare knobs for the presentation, such as whether to draw the limits box. They come from theparamsof the statement entry being rendered.
Let's put them side by side. The author name is data; the "show limits" toggle is a presentation knob:
Notice that author and show_limits sit in the same problem.rbx.yml, and
the template reaches each one under the namespace that owns it: vars.author
and params.show_limits.
The contest's variables sit one level down, under contest.vars, while
top-level vars means the problem's vars in a problem render. So these two
point at different values in a single render:
The problem namespace#
In a problem render, problem is the problem you are building. Its most-used
fields:
\VAR{problem.title} %# the problem title
\VAR{problem.limits.timeLimit} ms %# time limit (ms)
\VAR{problem.limits.memoryLimit} MB %# memory limit (MB)
problem.short_name (the letter, A) is conditional. It may be unset, so
guard it:
problem.vars and problem.params hold that problem's own vars and params, the
same data as the top-level vars and params in a standalone render. They
matter mostly when iterating problems in a contest join, where
each member exposes its own problem.vars.*.
Pulling blocks into a template#
problem.blocks is a dict of block-name to rendered LaTeX. This is how a
template places the statement's content: each %- block legend in the source
becomes problem.blocks.legend. So a template drops the legend in, and the
input section only when it exists, like this:
\VAR{problem.blocks.legend}
%- if problem.blocks.input is defined
\section*{Input}
\VAR{problem.blocks.input}
%- endif
Block names are free-form. See Writing statements for the conventional set.
Printing the samples#
Samples are handed to the template as problem.samples, a list you iterate.
Each item is a sample handle:
| Field | Meaning |
|---|---|
sample.index |
0-based position (int) |
sample.input |
root-relative path to the input file |
sample.output |
root-relative path to the output file |
sample.has_output |
whether an output file exists (bool) |
sample.dir |
import-base directory for the explanation |
sample.explanation_file |
explanation file to \subimport, when present |
sample.interaction |
interaction protocol for interactive problems |
sample.input and sample.output are path strings meant for verbatim
printing, so feed them straight to \VerbatimInput. The explanation is a
separate file you \subimport from sample.dir, and you should guard it, since
not every sample has one:
%- for sample in problem.samples
\VerbatimInput{\VAR{sample.input}}
%- if sample.has_output
\VerbatimInput{\VAR{sample.output}}
%- endif
%- if sample.explanation_file is defined
\subimport{\VAR{sample.dir}}{\VAR{sample.explanation_file}}
%- endif
%- endfor
Why two path anchorings
sample.input and sample.output are root-relative, because
\VerbatimInput ignores the \subimport base. sample.dir and
sample.explanation_file are import-base-relative, for \subimport.
You don't have to think about it; use each handle as shown above.
Filters#
Any \VAR{...} value can be piped through a filter with |, as in
Jinja2. On top of the standard Jinja2 filters, rbx registers a few
LaTeX-aware ones you will reach for constantly:
scirenders a round integer in scientific notation:\VAR{N.max | sci}prints1000000000as10^9.rsciissciwith the remainder kept:\VAR{MOD | rsci}prints1000000007as10^9 + 7.escapeLaTeX-escapes a string (_,%,&, ...):\VAR{author | escape}.parenttakes a path's parent directory:\VAR{sample.input | parent}.stemtakes a path's filename without its extension:\VAR{sample.input | stem}.
The standard Jinja2 filters (upper, join, default, ...) work too.
Building a subtasks table from testgroup vars#
A scored problem usually wants a table of its subtasks, and the constraints in
that table are the ones the validator enforces for each group. rbx exposes
them: the variables of each testgroup, after applying its per-testgroup
overrides, are
available as problem.groups.<name>.vars.<key>.
So the whole table is a loop:
The loop above prints 50 for small and 1000 for large. These are the
resolved values, so a testgroup that overrides nothing still renders the
package-level number, and you never have to restate a constraint you did not
change. \VAR{g.N.max} reads that group's own vars, the same way \VAR{N.max}
reads the package's.
Import handles#
problem.import_dir and problem.import_file are the \subimport handle for a
problem being pulled into a contest book. They exist only in a contest-join
fragment, and are absent in a standalone rbx st b render, so guard them:
%- if problem.import_dir is defined
\subimport{\VAR{problem.import_dir}}{\VAR{problem.import_file}}
%- endif
See Contest statements for the full join pattern.
Interactive samples#
For an interactive problem, a sample is a
conversation rather than an input and an output file. Iterate
sample.interaction.chunks instead of printing plain I/O, and each chunk carries
.path, .pipe and .data:
%- for sample in problem.samples
%- if sample.interaction is not none
%- for chunk in sample.interaction.chunks
\interactionchunk{\VAR{chunk.path}}{\VAR{chunk.pipe}}
%- endfor
%- endif
%- endfor
Full field reference#
The tables above cover what you reach for day to day. For the exhaustive field
list, every attribute on limits, profiles, groups and the statement entry
itself, consult the auto-generated schemas rather than a restatement of them
here:
- Package schema for problems, statements,
vars,params, samples and limits. - Contest schema for contest statements,
documents and the contest
vars.
And once you know what is in the context, Contest statements is the page that puts it to work.