One of the important tenants of Rktcr is that -- while it is very hard -- it isn't impossible. So how do I keep the game possible, given the hundreds of generated worlds and tens of levels? As expected, the answer is extensive (semi-automatic) testing.
The core of this testing revolves around a database of paths -- recordings of player input that take the vehicle from portal [to gem] to portal, under different gravity directions and mirrorings, in each level. As of this writing, there are 1093 paths in the database. That's a lot of gameplay (in fact, it's all the gameplay I think is possible).
These paths have a few functions, but the most important is to make sure that any changes I make to the game don't (unintentionally) change what is possible in the game.
I have a helper program
test_paths that runs every path in the database and prints a hash of the game states along each path.
The output of
test_paths gets stored in my main git repository; before releasing a build (and, generally, after any change that I think might have messed with the physics), I run
test_paths and compare to the stored output.
If there are any differences, I know there is trouble afoot.
Of course, the paths aren't just for testing.
They also get converted into par times for the levels; for this I have a pair of utility modes --
rktcr update-claims updates the par times to reflect the current paths database,
rktcr check-claims check the current par times against the paths database to make sure they are consistent
(this comes in handy when I change level geometry or physics, invalidating existing paths, as it lets me know what paths I need to recreate).
Aside: why not distribute paths instead of par times? Philosophical reasons, mainly. I prefer that games not know the answers they are asking you to provide.
These par times, in turn, are used by the aptly named
world_gen to generate worlds (groups of connected levels).
Of course, I want to hedge against the possibility that a world becomes unwinnable owing to new paths and par times.
For this, I have yet another utility program,
world_test, which loads each world in turn and makes sure that it is solvable in a reasonable time, given the current par times.
And that's how I keep Rktcr honest.