HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

Decision Table for the Movement AI in a Game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
themovementdecisiongamefortable

Problem

I posted a question on Stack Overflow about how to implement Decision Tables in Objective-C after reading about them for the first time in chapter 18 of Code Complete. Nobody provided an answer, so after puzzling it out for a while longer, I created the following code for the movement AI of the enemies in my strategy game.

The basic way it works is that there are a number of string constants, one for each value in the enum EnemyMovementState. The dictionary is then filled with these constants as keys, and the string names of methods in the class as objects. Then I run a switch statement that returns the appropriate string constant for the current state, and pull the object out of the dictionary with that key. This is converted into a selector, and the method is called. This replaced the switch statement that previously had a case for each value in the enum.

I truly do not know if there is any advantage to doing things this way. I think that part of the point of decision tables is to be able to input multiple values and determine an outcome based on the combinations of them. This current implementation only handles one input, the state. I think this could be extended to an intermediate method that could take the current state combined with some other values to retrieve other appropriate methods from the dictionary.

The problems I see are that I need all those string constants, and I still need to run a switch over the states of the enum to return the appropriate string to access the dictionary. I would love it if I could directly convert the name of a value of an enum into a string, but I don't know of a way to do this. So even though this functions as a decision table, it still needs a switch statement to work, and needs more supporting code to make the whole thing work. If I used the value of the enum directly, I could avoid the switch statement, but then if I moved the order around inside the enum the code would break, and on the whole this seems le

Solution

-(id) initWithWorldSizeForCharacter:(CGSize)worldSize andStartingFloor:(int)startingFloor;


It's slightly better to use instancetype as the return type here rather than id. What we're actually returning (here) is a DTEnemyMovement object, but explicitly listing this as the return type is problems when subclassing because we're returning the super type instead of the subclass's type.

Using id prevents that problem, but id is just a generic object pointer that the IDE can do no type-checking on. It wouldn't give us a warning if we tried assigning the return from this method into a UIButton object, for example (but it would lead to trouble eventually).

Meanwhile, instancetype is the best of both worlds. It will provide smart type checking, but still be generic and return the appropriate type based on whether it's this class or some subclass.

Beyond the return type, the method name needs some work. There are 3 words that are misleading and confusing. ForCharacter and and don't belong in this method name.

First of all, ForCharacter. What character? Perhaps the result is used for a character, but the method doesn't care how its result is used and it's name shouldn't indicate how its result is supposed to be used. The method name should indicate what the method does and with what parameters.

And and is only used in method names to indicate multiple actions and never used to indicate multiple arguments. The number of arguments is rarely confusing... since they all have names.

So truly, the method name should look like this:

- (instancetype)initWithWorldSize:(CGSize)worldSize startingFloor:(int)startingFloor;


One final note about this method, I'm not sure if you're aware of these class methods or not, but rather than alloc] init], you can just do:

[NSMutableArray array];
[NSDictionary dictionary];


Methods like this exist for numerous Objective-C classes as well. I personally prefer this to alloc] init];

Code Snippets

-(id) initWithWorldSizeForCharacter:(CGSize)worldSize andStartingFloor:(int)startingFloor;
- (instancetype)initWithWorldSize:(CGSize)worldSize startingFloor:(int)startingFloor;
[NSMutableArray array];
[NSDictionary dictionary];

Context

StackExchange Code Review Q#58292, answer score: 11

Revisions (0)

No revisions yet.