Warning: this is an unfiltered stream of thoughts on a hypothetical text game, and isn't by any means good or interesting writing. Proceed with caution.
The program, at its most basic level, does the following:
- Take in user input as text
- Compute changes to the world state, including responses to the user input
- Continuously inform the user of relevant information about the world state
To do this, it must:
- Comprehend the user's text input and transform it into an "intent" understandable by the system
- Attempt to carry out this intent
To comprehend the user's input it should be able to recognise one of several input "types". These classify the user's input into something like this:
- Ditransitive verb phrase: verbs with two arguments
- Monotransitive verb phrase: verb with one argument
- Intransitive verb phrase: verb with no arguments
It should be able to recognise verbs in the sentence not by looking them up, but by recognising their position in a sentence. This should account for proper English sentences, and more abrupt "command phrases" equally.
This has the advantage that any as-yet-unprogrammed verb used in a phrase will correctly be tagged as a verb, and the "verb not found" error will be encountered later down the line when the system attempts to carry out the intent.
As such, the grammar for a verb will simply be that of an English word, and hence it will be a matter of some work to generate the necessary grammars for verb-phrases which involve prepositions and the like.
After a prototype is developed with some basic set of sentence-recognition capabilities (and relatedly, the ability to carry out some meaningful action based upon their contents), the intention is to let as many people as possible try playing the prototype game, and log their attempted commands. Their attempts will almost certainly provide an insight into multiple grammatical structures and phrasings as yet unconsidered.
A major problem with this text game will be that of world-representation. Reuse of code becomes a pressing issue given the sheer number of objects in any sufficiently detailed world, and as such it would be wise to encourage inheritance (whether multiple or single) as much as possible.
As of yet, this project is language-agnostic, but it is worth noting at this point that while some languages (e.g. Python, Ruby) do have support for multiple inheritance or "mixins", others (e.g. C++, Java) do not. In such languages there may well be equivalent design patterns to achieve the same goal, however.
Unfortunately, code reuse also presents a problem in a field not so easily addressed by inheritance: events in the world. As an example, take an electrified lever: many different events (pulling it, touching it, punching it) would all reasonably be expected to result in the same outcome, i.e. receiving an electrical shock. However, taking the naive implementation of one-function-per-action, the code for same would be repeated over and over again. Inserting "checks" into each function for the object in question being electrified is more of a hack than a solution, and given even a small number of reasonable states in which an object might be (wet, frozen, scalding hot) would result in unmaintainably large, identical piles of checks for each function before anything useful is accomplished.
It has been noted that object-oriented programming has no support for the inheritance of methods directly, and -- while this is true -- it does pose some interesting solutions to the problem. One proposed solution is to represent the events themselves as objects, rather than methods. This means that not only is inheritance now available for actions, multiple inheritance is available.
It is also still possible with event-objects to define arbitrarily complex behaviour regarding events of greater or lesser specificity that may also be called for a given event. For example, when designing an electrified lever, one presumably wants to make sure that the lever is not pulled after being touched; the presumptive lever-puller is given a shock of electricity and thrown backwards instead of effecting any change. It is trivially possible to write a base Event class which permits arbitrary ignoring of other relevant events in the chain.
This poses a problem, however, with multiple inheritance. It is often difficult, e.g. in languages such as Python, accurately to estimate which of the parent classes will be used for any given call to "super" or its equivalent.
There is in Python a strictly-defined method resolution order for all objects; however, the linearization algorithm used is extremely complex and (one hopes) not necessary to understand in order effectively to use the Mixin tools available.
Possibly, the problem may involve defining our own method resolution order. In Python this is potentially viable given Python's ability for metaclass-related hacks, but in terms of algorithmic simplicity most likely indicates overengineering.
Effectively, the problem we need to solve is the way in which user-defined events can specify which other events they should supercede or be superceded by. There should be clearly-defined limits to their power; for instance, it may be wise to limit the number of events it is possible to "ignore" for any given event to the events of which it is a subclass: specificity should always be favoured over blanket generalisations. Ideally, the system of prioritization should not rely on numbers; the example of CSS's Z-index abuse elucidates how fraught that path can be.
Consideration should also be given to whether events should "interrupt" other events: a good example of this might be found in the game Magic: The Gathering where (if I'm not mistaken) it's possible to play cards in response to other cards before they take effect. For instance, a poison might harm a player's hit points after they drink it (but still permit the player to drink it), whereas a forcefield around a chest should stop the player opening the chest in the first place. This may tie into as-of-yet unconsidered ideas about the logical "framerate" of the game, and whether events should be synchronised with some kind of internal clock. This would add a lot of complexity, but would also give designers the ability to add effects "X ticks later". It's easy to imagine a set of currently-waiting tasks, over which an iterator passes every frame: checking for completion, decrementing a counter, and firing off "on-complete" events.
I'm trying to avoid writing code before I get a really solid idea of the architecture behind this thing. For the record, the things I'm inspired by most are OASIS from Ready Player One and Improbable.io's SpatialOS: hopefully that gives some insight into why I want to make something so nebulous but text-based. Here's hoping it materialises into something as cool as I'm imagining!