This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
I'm working on the foundation of a text-based RPG platform, and have been turning over how to most effectively identify commands from player input and execute the corresponding code statements. There's two separate contexts I want to use this in, which are independent and do not have to use the same design:
a) executing commands entered, which should allow for abbreviations (although I may wind up putting that aside).
b) parsing an internal scripting language, which should not permit abbreviations
I've thought of three ways to do this:
1) Use a gigantic switch/case statement to parse one character of the command at a time, e.g.
I don't like this one because it'll be really unpretty once a large number of commands are coded in, even with the commands called as methods and not embedded directly here. But it's the only way I can think of to do partial matching on a string without marching through the whole list of functions in an equally big if/else block, and this seems superior for handling ambiguous input (e.g. 'g' which could be 'get' or 'go').
2) Use an enum and switch/case to match whole words, e.g.
Doesn't do partial matching, does do whole-string matching; might be applied in the interpreter. The enum also provides an instant overview of what functions are already coded for and which aren't. The downside of this one that I can identify is that in adding new functions, you have to a) write the appropriate code, b) update the switch statement, and c) update the enum. True, a and b could be combined if the code was contained in the body of the switch statement, which the skeletal snippet above implies, but I expect they'll largely be their own methods or objects. I'm currently leaning towards the latter, because while the particulars of each function will be different, they all fit the same template and need to do some common things that inheritance or an interface could easily define.
3) Use a Map of some sort for lookup, with String keys and Function object values.
I haven't coded even a basic 'this is how it would work' snippet for this option yet, so it's all conceptual. The benefit of this design is that with Reflection, I could arrange for the program to initialize all available Functions and fill in the Map upon startup, meaning all I or any other programmer would have to do to add new ones is write the class and not worry about updating the lookup table. What I don't have any real idea of is how practical this is in terms of performance and memory. I gather that Reflection is Decidedly Not Good in the performance arena, although that would only really be an issue for generating the lookup table on restart, typically a rare event. But the Map will permanently take up memory, and having functions as their own objects is also going to get big fast (a drawback not necessarily specific to this design).
I'd welcome any input or suggestions others have on this. Particularly alternative methods I haven't thought of, as well as any other pros or cons of the above three designs.
I've done a few command interpreters in PHP but I'd imagine it's roughly the same in any programming language. I start by using a a few functions that will read the next word in the command line and move the read pointer forward. If it's expecting a command then it would convert the word to upper case. I'd have a another function to put the current word back. If there's a string in quotes then I'd treat the whole string as one word.
Then I just loop round reading the commands and processing each command in switch statement. The idea is to try and make things reasonably easy to follow (and to add new command in future).
Doing it this way it's quite easy to build up quite complex languages. In my early days I used to use the Unix tools LEX and YACC to process commands but that was a pain in the butt.
I've done this a few times also, but with small programs that start with params, not games.
I usually do it as following, this is for a single command, started from the main. So really only the basics.
In your game the principle is the same but you'll have a loop (while not end of game) of course...
then the Commands all have the same parent 'Command'
which does the parsing work (the init method) and does callbacks to the child to set the params. But you can do this your own way..