What a constraint does
A normal programming task asks for a result and leaves the method open. A constraint puzzle keeps the result and closes off part of the method. You might be forbidden from using certain characters, required to fit the code into a shape, or limited to a deliberately weak language. The result is the same problem, but the usual solution is no longer available, so you have to find another route.
This is why constraints are popular among people who enjoy esoteric languages. The restrictions are not an obstacle to the fun. They are the fun.
Constraints on the language
The simplest kind limits what you may write in. Examples include:
- A tiny instruction set. Solve a task using only a handful of operations. Minimalist languages are natural for this, and the exercise teaches how much can be built from very little.
- No loops, or no conditionals. Express repetition or choice some other way, such as recursion, data tricks or, in a grid language, geometry.
- A language of someone else’s choosing. Solve the puzzle in a language you do not know well, which forces you to read its documentation properly.
- A language with no obvious way to do the task. Some languages lack input, or lack arithmetic beyond the basics. Working around that is the entire challenge.
A useful first step is to list exactly what the language can do, however limited, and then ask which of those abilities could substitute for what you need. Most constraint solutions are built from this kind of substitution.
Constraints on the character set
Here the code may use only certain characters. Common versions are:
- only letters, or only digits
- no letters at all
- a fixed set of symbols, such as a small number of punctuation marks
- only characters from a single row of the keyboard
- source code that contains no repeated character
In languages where meaning depends on specific symbols, these limits can be severe. Approaches that help include building values from the few characters you have, using the language’s ability to convert between numbers and characters, and generating other code at runtime from simple pieces, where the language permits it. In a grid language, the ability to compute a value and write it into the grid can sometimes be used to produce a forbidden instruction from allowed ones.
A caution: always check the exact wording. Does the rule apply to the source only, or also to its output? Are spaces and newlines counted? Ambiguity here wastes more time than any technical hurdle.
Constraints on the layout
Layout puzzles say something about the shape of the code, not its content. They are especially interesting in two-dimensional languages because shape is already meaningful. Examples:
- Palindromic programs, which read the same forward and backward, or in which every row or column is a palindrome.
- Programs in a fixed rectangle, or in a particular outline.
- Source code that is also a picture, which borders on ASCII art programs.
- Programs that must still work when rotated or reflected, which suits languages where direction is part of the code.
- Polyglot programs, where the same text is valid in two or more languages at once.
For layout puzzles, work from the shape inward. Decide what the constraint forces first, such as which cells must match which, and treat the rest as free space where the real logic lives. Draw the pointer’s path on paper before filling in any characters. When the path is symmetrical, half the work can often be mirrored.
Constraints on size
A size limit forces the program to be small, whether measured in bytes, cells or lines. It is the same idea as the golf format, but it can be applied as a hard cap rather than a ranking. The thinking tends to differ: you stop asking whether the task can be done and start asking what the minimum necessary mechanism is. Thoughts on this appear in the discussion of size limits.
Constraints on resources
A few puzzles limit what the running program can use, for example restricting the number of stack items, the amount of memory or the number of steps. These shift attention from code shape to the algorithm, and they are a good introduction to thinking about efficiency.
A method for approaching any constraint
When you are stuck, a short routine can help.
- Restate the rule in your own words. Check for edge cases and ask whether you have understood the scope correctly.
- List what is still allowed. Be generous: what does the language let you do that you have not used?
- Solve a smaller version. If the full task seems out of reach, solve the easiest case that satisfies the constraint, then extend it.
- Separate the constraint from the logic. Write the logic in a relaxed form first, then transform it to satisfy the rule.
- Look for a pattern in failures. If you keep breaking the same rule in the same place, that is the part to redesign.
- Take a break. Constraint puzzles often yield to a fresh look, which is common experience rather than a guarantee.
Making your own constraint puzzles
Good constraint puzzles share a few qualities: the rule is simple to state, the task is clearly checkable, and there is at least one solution the author has verified. Start with a task people already understand, such as printing a short string or doing a basic calculation, then add one restriction. Test it yourself before sharing. More advice is covered under puzzle design, and the question of how to rank entries fairly belongs to scoring rules.
A familiar task is a good base. The FizzBuzz puzzle, for example, becomes a different challenge as soon as you ban a common operator or require it in a strange language. If a restriction makes the puzzle impossible, loosen it; if it makes it trivial, tighten it.
Why bother
Constraint puzzles train a habit that carries over to ordinary programming: when the obvious tool is not available, look for another. They also tend to produce solutions that are worth reading and sharing, because the route taken is more interesting than the destination. Whether you are solving or setting them, the best ones leave you with a small surprise about what a language can really do.