Skip to content

Decimal places

Examples on this site use -- annotations for readability

The rule language has no comment syntax. Strip anything from -- onward before pasting an expression into the editor.

Almost every real rule in this system is about a technique at a decimal place, not about a specific number. "Add 8 when the affected digit is 2" and "add 80 when the tens digit is 2" are the same technique performed one place apart. Writing those as separate rules would multiply your work for no benefit.

So the language derives three variables for you, describing where the candidate acts:

VariableMeaningFor current_value = -70, prev_sum = 325
placeThe decimal place affected: 1, 10, 100, …10
formulaThe normalized 1–9 digit, ignoring sign and place7
digitBeforeThe digit of prev_sum at that same place, before the step2

digitBefore is the important one. It tells you what the abacus looks like at the affected place right now, which is what decides whether a technique is even possible.

The standard shape of a pattern rule

Nearly every canonical rule follows one three-clause template:

current_value > 0 AND formula = 8 AND digitBefore IN (0, 1)

Read left to right:

  • current_value > 0 — the operation is an addition. Use current_value < 0 for subtraction.
  • formula = 8 — the technique is an 8.
  • digitBefore IN (0, 1) — the affected digit is currently 0 or 1.

Because formula and digitBefore are place-relative, that one rule matches 2 + 8, 12 + 8, 120 + 80, and 3100 + 800 alike. See the rule catalog for the full set built this way.

Atomic and composite values

These three variables only make sense when the candidate touches exactly one decimal place. Such a value is called atomic:

ValueAtomic?Why
+7yesone non-zero digit, at the ones place
-40yesone non-zero digit, at the tens place
+300yesone non-zero digit, at the hundreds place
+47notwo non-zero digits: 4 at tens and 7 at ones
-89notwo non-zero digits

For a composite value like +47 there is no single place, no single formula digit, and no single "digit before" — so place, formula, and digitBefore are all null.

Composite values are not hypothetical: a recipe can be configured to produce them deliberately, so a step like +47 is a real thing your rule may be asked about. See multi-place combo steps.

The null trap

This is the most common source of a rule that looks right but behaves strangely.

When these variables are null, comparisons still evaluate — they just do not do what you would expect. Positive tests fail, and negative tests pass.

Given a composite candidate like +47:

ExpressionResultEffect on the step
formula = 8failsrejects it
formula >= 1failsrejects it
place IN (1, 10)failsrejects it
digitBefore = 2failsrejects it
formula != 8passesallows it
formula < 1passesallows it
place NOT IN (1, 10)passesallows it
digitBefore != 2passesallows it

Two consequences worth internalizing:

A rule meant to exclude something can stop excluding it. formula != 9, intended as "never a 9", quietly permits every composite value — null is not 9, so the test passes.

A rule meant to restrict place can reject everything. place = 10, intended as "tens only", quietly rejects every composite value, even one whose tens digit is exactly what you wanted.

Neither is a bug. A composite value genuinely has no single formula or place, and the comparison is answering honestly. Both are just easy to write by accident.

Rule of thumb

If a rule uses place, formula, or digitBefore, it is a rule about atomic steps. That is usually exactly what you want. Reach for digitAt below only when you deliberately need to inspect one place of a value that may touch several.

Inspecting a specific place with digitAt

digitAt(value, place) reads the digit at any place you name, and does not care whether the value is atomic. It is the composite-safe way to talk about places:

digitAt(current_value, 10) = 4      -- the tens digit of the candidate is 4
digitAt(current_value, 1) != 9      -- the ones digit of the candidate is not 9
digitAt(prev_sum, 100) IN (0, 5)    -- hundreds digit of the running total is 0 or 5

For current_value = 47, digitAt(current_value, 10) is 4 and digitAt(current_value, 1) is 7 — while place, formula, and digitBefore are all null.

A common use is pinning the opening position, where digitBefore would not help because it only ever describes the place the candidate itself affects:

IF step_index = 0 THEN digitAt(prev_sum, 1) = 0   -- start from a clean ones digit

Choosing between them

You want to sayUse
"This technique, at whatever place it occurs"formula + digitBefore
"Only steps in the ones place"place = 1
"This digit of a value, whatever else the value touches"digitAt(x, place)
"Never a 9 anywhere, including in composite steps"digitAt(current_value, 1) != 9 and so on per place, not formula != 9

A rule scoped to one place-channel of a recipe may not reference current_sum.

Inside a single channel, "the sum after this step" is not a state the exercise ever actually passes through, so it is rejected when the recipe is compiled. Put whole-step sum conditions in an ordinary, unscoped constraint rule instead. See multi-place combo steps.

See also

Reference and cookbook for mental-math rule and recipe authoring.