Skip to main content
Mathdle

The math behind Mathdle

Mathdle looks like a casual word game with numbers, but the engine underneath is unusually strict. Every expression you submit is parsed into a tree, evaluated in exact arithmetic, checked against a set of domain and identity rules, and then hashed into a canonical form that decides whether you've found something new. This page walks through exactly what happens, in the same order the engine does it.

The expression tree

When you submit 3 + 4 × 5, the engine doesn't see a string. It sees a small tree: a + node with a leaf 3 on the left and a × node on the right, and that × node has leaves 4 and 5. Leaves are tagged by tile ID, not by value. That distinction matters: if a puzzle hands you two tiles that both show a 5, they are still different tiles, and the engine never lets you double-spend a single tile under the cover of its value matching another.

Every check downstream — the value, the canonical hash, the duplicate-tile guard — operates on this tree. The pretty string you see on screen is rendered from it, not the other way around.

Exact rational arithmetic over BigInt

Every value in Mathdle is a rational number, represented as a pair of arbitrary-precision integers: a numerator and a denominator, both BigInt. There is no floating-point math anywhere in the engine. 3 ÷ 7 × 7 equals exactly 3, not 2.9999999999or 3.0000000001.

Each rational is stored in lowest terms. The constructor divides numerator and denominator by their greatest common divisor and pins the sign onto the numerator, so the same value always has the same internal representation. 2/4, 1/2, and -3/-6 all collapse to one canonical form. Equality is a single integer comparison on each component.

Operations are textbook fraction arithmetic. Addition cross- multiplies and adds numerators; multiplication multiplies straight across; division flips and multiplies; subtraction is addition with a negated right side. Division by zero throws; the engine catches it and reports a domain failure rather than crashing.

Canonicalization: when two expressions are “the same”

The catalogue of solutions for each puzzle is keyed by a canonical string. If two expression trees produce the same key, they count as the same expression and only one of them earns points. The rules:

The practical consequence: every multiplicative expression you find has a distributed cousin, and every distributed sum has a factored cousin. Both score. The tips page covers how to milk this for points.

Identity rejection

The engine walks the tree and refuses any sub-expression whose only effect is to consume a tile without changing the value. These would otherwise be a trivial way to pad a pangram. The full list:

The check is recursive. An identity anywhere — top of the tree, deep inside a parenthesized fragment, hidden under a square root — kills the whole submission. The error message tells you which one tripped it.

Impossible-mode operators

Easy, Medium, and Hard use only the base four (+ − × ÷). Impossible adds four more, each with its own domain restrictions.

mod (Euclidean modulo)

a mod b is the remainder of integer division. Both operands must be integers — if either is a fraction, the engine throws. The result is the Euclidean remainder: it has the same sign as the divisor and lies in the half-open interval [0, |b|) for positive divisors. So 17 mod 5 is 2, and (−7) mod 3 is 2, not −1. Mod by zero throws; x mod 1 is an identity and rejected.

√ (integer square root)

√x requires x to be a non-negative integer anda perfect square. The engine computes the integer square root with Newton's method on bigints, then verifies the result squares back exactly. If it doesn't, the expression is rejected. √49 = 7 is fine; √50 is not, and neither is √(1/4). The reason is precision: irrational roots can't be represented as rationals, and approximating them would break the “√x × √x = x” guarantee everything else relies on.

^ (integer exponent)

a ^ b requires b to be an integer with |b| ≤ 4. The cap exists because exponents grow fast: 9^5 is already 59049, and Mathdle targets sit in the low thousands at most. Negative exponents invert (2^−3 = 1/8); 0^0 throws as undefined; 0 to any negative power throws. a^1, a^0, and 1^a are identities and rejected. The base can be any rational, so (1/2)^3 = 1/8 is well-defined.

! (factorial)

n! requires n to be a non-negative integer with n ≤ 8. The cap is hard: 8! = 40320 and 9! = 362880, well past anything a puzzle target asks for. 0!, 1!, and 2! are identities and rejected — they consume a tile without producing anything new. 3! = 6, 4! = 24, 5! = 120, 6! = 720, 7! = 5040, 8! = 40320. Factorials of fractions or negatives throw.

Why exact rationals, not floats

JavaScript's native numbertype is a 64-bit IEEE 754 float. It can't exactly represent 0.1, much less 1/3 or 1/7. The familiar embarrassments — 0.1 + 0.2 === 0.30000000000000004— are harmless when you're rendering a temperature, and a small disaster when you're comparing puzzle solutions for equality.

Mathdle needs three things from its arithmetic, and floats can't deliver any of them on their own:

The cost of all this is mild: every binary operation does a couple of bigint multiplications and a GCD reduction. Rationals are slower than floats on a hot loop, but Mathdle's hot loop is “evaluate one expression a human just typed,” not anything performance-critical. The catalogue enumeration that runs offline can take a few seconds per puzzle; on the playing client, every check is instantaneous.

Putting it together

When you submit an expression, the engine does six things in order: parse it into a tree, walk the tree to enforce one-use-per-tile and require the center tile, evaluate it exactly with rational arithmetic, compare the value to the target, scan for identity sub-expressions, and finally hash the tree into a canonical key. If the key is already in your found set, you've resubmitted a known shape. If it's new andit's in the puzzle's catalogue, you score.

That's the whole engine. Everything else — the tier curve, the pangram bonus, the streak freeze — is bookkeeping on top.

For practical advice on exploiting these rules at the board, see tips & strategy. For short definitions of the terms used here, see the glossary.