Statements#
A statement is the document a contestant reads: the story, the input and
output format, the constraints, the samples. In rbx it is part of the
package, declared in problem.rbx.yml next to the solutions and the testset,
and built into a PDF by a command.
Think of the last contest you prepared without a tool like this. You lowered
N from $10^9$ to $10^5$ two days before the contest, changed the validator,
changed the generators, and forgot the statement. Or you had an English and a
Portuguese version, and fixed a typo in one of them. Or you spent the last night
pasting eight problems into a single .tex by hand, and the samples went stale
the moment someone regenerated the tests.
rbx takes those three jobs off your hands. Constraints come from the same
vars your validator reads, so the bounds cannot disagree. Samples are pulled
from the testset every time you build. And the contest book is assembled from
the problems themselves, in as many languages as you declare.
In the sections below, we'll build the mental model first, then walk through the commands, and finish with the flags you'll reach for once the basics are in place.
Building your first statement#
Let's start from the smallest thing that works. A statement entry needs a language and a file:
And the file itself holds the content, in named blocks:
%- block legend
Given two integers $A$ and $B$, compute $A + B$.
%- endblock
%- block input
A single line with two integers $A$ and $B$.
%- endblock
%- block output
A single line with the sum of $A$ and $B$.
%- endblock
Notice there is no \documentclass in there, and no section titles. The blocks
carry what the problem says; a template decides how it looks, and the
template is not your problem's business. Build it:
The PDF lands in build/statement-en.pdf. The recording above runs the command
from inside problem A of a contest, which is why it builds two languages and
picks up the contest's own layout; we get to contest
statements further down.
Tip
Keep the sources and their images in a subdirectory such as statements/,
so they don't clutter the package root.
What a statement is#
Under the hood, a statement is a (language, variant) source of some type,
rendered to a PDF. Four fields carry all of it:
languageis an ISO 639-1 code (en,pt, ...). You declare one entry per(language, variant)pair.variantis an optional label that defaults todefault. It lets you keep more than one recipe for the same language, and we come back to it below.typeis the source format. It defaults torbx-tex, so most of the time you leave it out.fileis the source file, relative to the package root.
Everything else is optional.
Info
See the package schema for the exhaustive field list. This guide covers what you reach for; the schema covers everything.
Where statements are declared#
Problem statements live in problem.rbx.yml, keyed only by (language,
variant):
statements:
- language: en
file: statements/statement-en.rbx.tex # (1)!
- language: pt
file: statements/statement-pt.rbx.tex
- The source file, relative to the package root.
typedefaults torbx-texandvariantdefaults todefault, so both are omitted. Problem statements have noname.
That is the whole problem side: point at a file, name a language.
Contest statements live in contest.rbx.yml instead. They carry everything a
problem statement does, plus the templates that wrap each problem into the book,
because the contest owns the chrome:
statements:
- name: main-en # (1)!
language: en
file: statements/contest-en.rbx.tex # (2)!
standaloneProblemTemplate: statements/problem-standalone.rbx.tex # (3)!
contestProblemTemplate: statements/problem-in-contest.rbx.tex # (4)!
- Contest statements and documents require a
name. It identifies the entry and keys the output PDF. - The joining document, which is the contest book itself.
- Full-document template used to render each problem on its own (
rbx st b). - Fragment template used when problems are joined into the book
(
rbx contest st b).
Those two templates are where contest statements get interesting, and Contest statements walks through both of them.
The three kinds#
A contest build stitches every problem's statement into one booklet: a cover, then problem A, then B, and so on. That stitching is the join. Some kinds of statement take part in it and one does not.
The one that does not is a document: a contest-only page that stands on its own and never pulls in a problem's statement. It is how you make the extra pages a contest needs but a single problem cannot produce, such as an infosheet with every problem's limits, or a cover page. A tutorial, meanwhile, is an editorial: the write-up explaining how to solve a problem rather than how to read it.
Each of the three is its own list:
| Kind | Where | Joined into the contest? | Purpose |
|---|---|---|---|
statements |
problem + contest | yes | the problem/contest statement |
tutorials |
problem + contest | yes | editorials |
documents |
contest only | no | infosheets, cover pages |
Notice that statements and tutorials are the same thing under the hood. Same
source model, same build pipeline. They live in different lists and produce
differently named PDFs, and that is the extent of it.
Formats at a glance#
You pick one type per statement, and the choice matters: only the rbx-*
types carry blocks and can join into a contest book. The rest are simpler
passthroughs.
type |
When to use | Joins? |
|---|---|---|
rbx-tex |
Default. LaTeX with blocks + Jinja2. | yes |
rbx-md |
Markdown with blocks + Jinja2. | yes |
jinja-tex |
LaTeX with Jinja2 only, no blocks. | no |
jinja-md |
Markdown with Jinja2 only. | no |
tex |
Plain LaTeX, passed through untouched. | no |
md |
Plain Markdown, passed through untouched. | no |
pdf |
A pre-built PDF, copied through as-is. | no |
Writing in a format other than rbxTeX covers when each one earns its place.
Note
type is case- and hyphen-insensitive, and you can omit it entirely for the
default rbx-tex. One caveat: documents may only use jinja-tex,
jinja-md, tex, md or pdf, never the joining rbx-* types.
Building#
Each list has its own builder, and every command ships with a short alias:
Built PDFs land in the build/ directory:
- Standalone:
build/statement-<lang>[-<variant>][-<profile>].pdf, and tutorials usebuild/tutorial-…. - Contest:
build/<statement-name>[-<profile>].pdf, keyed by the contest statement'sname, not by its language.
The pipeline#
Whatever the format, every statement flows through the same pipeline on its way to a PDF, and you can stop at the intermediate LaTeX if that is all you need:
graph LR
Source["Source<br/>(language, variant)"] -->|Builder + template| TeX["LaTeX / Markdown"]
TeX -->|pdfLaTeX / pandoc| PDF["PDF"]
The contest owns the chrome
The template that wraps a problem into a full document lives on the
contest statement, not on the problem. Run rbx st b with no contest,
or with no matching standalone template, and rbx falls back to a bundled
default template and warns. It will not fail on you. See
Contest statements for the details.
Building only some languages#
Once a problem has three or four languages, rebuilding all of them to proofread
one gets slow. --languages restricts the build, and it is repeatable:
# Build only the English statement.
rbx st b --languages en
# Build English and Portuguese, skipping the rest.
rbx st b --languages en --languages pt
The flag works the same way on rbx contest st b and rbx tut b.
Rendering against a timing profile#
The time limit printed in a statement is whichever limit the package carries. If
you package the same problem for two judges with different limits, you want each
PDF to say the right number. The -p / --profile flag renders the statement
against a saved limits profile:
The profile name is appended to the output filename, so
build/statement-en-icpc.pdf sits next to build/statement-en.pdf instead of
overwriting it. See Profiling for how profiles are
estimated and saved.
Warning
The profile must exist in the problem. On a contest build, problems missing the profile are skipped with a warning rather than silently rendered against the package limits.
Keeping two recipes for one language#
variant is the second half of a statement's identity, and it defaults to
default. Declare a second entry with the same language and a different
variant when you want two renderings of the same problem in the same language:
a full version and a short one for the onsite booklet, say.
statements:
- language: en
file: statements/statement-en.rbx.tex
- language: en
variant: short # (1)!
file: statements/statement-en-short.rbx.tex
(en, default)and(en, short)are two distinct statements. Declaring the same pair twice is an error.
Build one variant by naming it positionally:
The variant also lands in the filename, so the two entries above build to
build/statement-en.pdf and build/statement-en-short.pdf. On the contest side
the variant is half of the join key, so a
contest statement declared as (en, short) joins each problem's short variant.
When a statement fails to build#
Statements are built independently of each other. If your problem has an English and a Portuguese statement and the English one fails, the Portuguese one is still built. The command lists everything that failed at the end and exits non-zero. One broken language never blocks the others.
Inside a contest build the rule tightens, deliberately: a problem that cannot
be rendered fails the whole statement rather than quietly dropping out of the
book. See When a problem cannot be
rendered for that story, and for
the --partial escape hatch.
Where to go next#
From here, pick the guide that matches what you are doing.
-
Write your statement
The source side, rbxTeX-first: blocks, constraints pulled from
vars, sample explanations and images. -
Look up what's in scope
Every value a statement or a template can reach: the
params,vars,problemandcontestnamespaces, the per-sample handles and the filters. -
Build the contest book
The two problem templates, the
(language, variant)join, and the cover pages and infosheets that never join a problem. -
Write the editorial
Tutorials are the same model in a separate list. Here is what carries over and the one thing that doesn't.