When a valid solution has been found, we will create a Solution
structure. The values assigned to the puzzle variables can be
accessed using the indexing notation: solution[var].
Candidates are always an i32 (rather than a generic integer type) to
more easily perform arithmetic. The puzzles we will deal with should
always be small enough such that we do not exceed the limits of i32.
Candidate groups are separated into an enum. This is to help us keep
it general, as we would like to include a range option in the future.
We have chosen to return a variable token for every variable created,
instead of referencing puzzle variables by string or something else.
Puzzle variables should only be used in the puzzle that created it,
though this is neither checked nor enforced.
Eventually, we would also like to overload the standard arithmetic
symbols to ergonomically build constraint expressions.