-
MathType
-
WirisQuizzes
-
LearningLemur
-
CalcMe
-
MathPlayer
-
Store FAQ
-
VPAT for the electronic documentation
-
MathFlow
-
BF FAQ
-
Miscellaneous
-
Wiris Integrations
Common Patterns and Best Practices
Reading time: 2minAdvanced Logic enables powerful dynamic questions, but poorly structured algorithms can make questions difficult to maintain, debug, or extend. This article explains common patterns and best practices that help you write clearer, safer, and more reusable logic when creating LearningLemur questions.
What It Is
When writing algorithms for LearningLemur questions, the same types of logic appear repeatedly across different exercises:
- Generating valid random values
- Enforcing mathematical constraints
- Guaranteeing specific properties of solutions
- Avoiding invalid edge cases
Over time, several reusable patterns have emerged that make question algorithms easier to write and maintain. These patterns are not strict rules but recommended approaches that improve reliability and readability.
Why It Matters
Without consistent patterns, question algorithms can become:
- Difficult to debug
- Fragile when random values change
- Hard to understand months later
- Difficult for colleagues to reuse
Using common patterns helps ensure that:
- Algorithms remain readable
- Constraints are clearly enforced
- Question generation stays stable
- Logic can be reused across different exercises
This becomes especially important when creating large collections of dynamic questions.
How It Works
Most LearningLemur algorithms follow a similar conceptual structure.
Stage 1: Generate values first
Start by generating base random variables. Example concept:
a = random(1,9)
b = random(2,9)These variables act as the foundation for the rest of the algorithm.
Stage 2: Enforce constraints with loops
When mathematical properties must be guaranteed, use loops to validate them. Example cases include:
- Ensuring numbers are coprime
- Avoiding repeated denominators
- Guaranteeing perfect square discriminants
Typical structure:
repeat
generate values
until condition_is_satisfiedor
while condition_not_met
regenerate values
endStage 3: Compute solutions after constraints
Once valid values are established, compute the solution variables. Example:
solution = a/b + c/dKeeping solution logic separate improves readability and reduces errors.
Stage 4: Control edge cases early
Avoid problematic values from the start. Common examples:
- Excluding zero
- Avoiding repeated denominators
- Restricting ranges
Example:
random([-10..10]/[0])This prevents invalid calculations later in the algorithm.
Stage 5: Use helper functions when logic repeats
If the same logic appears multiple times, define a small function. Example:
r() := random([-10..10]/[0])This improves readability and simplifies future changes.
Key Rules or Behaviours
- Generate variables before computing solutions
- Enforce mathematical constraints explicitly
- Keep solution calculations separate from generation logic
- Avoid unnecessary nested loops
- Prefer readable logic over overly compact expressions
Examples
Example 1: Controlled GCD
Instead of generating two numbers and hoping their GCD matches a target, generate coprime numbers and scale them. Result: the GCD is guaranteed.
Example 2: Guaranteed integer solutions
Instead of solving equations randomly, generate the solution first and derive the equation coefficients. Result: the system always has the desired solution.
Common Misunderstandings
Misconception: shorter algorithms are better
Clarification: Clarity and reliability are more important than compact code.
Misconception: random values automatically produce good exercises
Clarification: Without constraints, random generation often creates invalid or undesirable cases.