2014-07-22 4 views
0

Я начинающий программист, и я только начал читать таблицы решений. Я прочитал главу 18 в «Code Complete», и это было очень поучительно. Я просмотрел веб-страницы, чтобы попытаться найти какой-либо пример таблиц решений в Objective-C, и мне не удалось найти примеры шаблонов или реальных примеров того, как это реализовать.Как реализовать таблицу принятия решений в Objective-C

Я программирую игру в Objective-C в свое свободное время, и я занимаюсь усложнением правил игры. Существует несколько глубоко вложенных операторов if-else, а также несколько операторов switch, которые уже имеют 10 или более случаев. Я думаю, было бы легче работать с таблицами решений, но я не знаю, как реализовать это в Objective-C для чего-то нетривиального, как логика игры.

Например, для разных комбинаций состояний мне нужны разные методы. Как реализовать таблицу решений в Objective-C, которая могла бы использовать разные комбинации состояний в качестве ключей и запускать определенную логику на основе их комбинации?

+0

Я заметил, что вы отправили некоторый пример кода, связанного с этим вопросом, на [Code Review SE] (http://codereview.stackexchange.com/questions/58292/decision-table-for-the-movement-ai-in- игра). Вы должны [отправить его здесь как ответ] (http://stackoverflow.com/help/self-answer) - это может помочь кому-то другому! – Malcolm

ответ

0

Ну, я еще немного подумал о таблицах решений в Objective-C и придумал решение для реализации базового. Я не буду публиковать весь код здесь, просто фрагменты, которые делают работу таблицы решений и их основной целью. Я опубликовал это по адресу Code Review SE, если вы хотите увидеть полный код и некоторые полезные советы по его улучшению. Я публикую это сейчас, потому что кто-то отправил комментарий с просьбой о том, чтобы я это сделал, но я, безусловно, в конечном итоге улучшу это и интегрирую предложения из обзора. Во всяком случае, вот код.

Прежде чем использовать метод инициализации, я устанавливаю ряд констант NSString, которые будут использоваться в качестве ключей в NSDictionary.

//Two options for the decision table, either access the dictionary directly with 0-x, the enum values, or make strings for their names 
//the advantage of strings is that it is more extensible, and the position in the enum doesnt matter 
NSString* const kEnemyMovementStateJustSpawned = @"enemyMovementStateJustSpawned"; 
NSString* const kEnemyMovementStateIdle = @"enemyMovementStateIdle"; 
NSString* const kEnemyMovementStateNeedsMoving = @"enemyMovementStateNeedsMoving"; 
NSString* const kEnemyMovementStateToFloor = @"enemyMovementStateToFloor"; 
NSString *const kEnemyMovementStateAtDestinationFloor = @"enemyMovementStateAtDestinationFloor"; 
NSString* const kEnemyMovementStateToFloorExit = @"enemyMovementStateToFloorExit"; 
NSString* const kEnemyMovementStateToAttackWalls = @"enemyMovementStateToAttackWalls"; 
NSString* const kEnemyMovementStateToAttackFloor = @"enemyMovementStateToAttackFloor"; 
NSString* const kEnemyMovementStateToAttackRoom = @"enemyMovementStateToAttackRoom"; 

Затем я использую эти константы наряду с именами методов в классе, чтобы построить NSDictionary:

-(void) setupDecisionTable { 
    //the string objects are the names of methods in the class 
    _decisionTable = @{kEnemyMovementStateJustSpawned: @"doEnemyJustSpawned", 
         kEnemyMovementStateIdle: @"doEnemyIdle", 
         kEnemyMovementStateNeedsMoving: @"doEnemyNeedsMoving", 
         kEnemyMovementStateToFloorExit: @"doFloorMovement", 
         kEnemyMovementStateToFloor: @"doVerticalMovement", 
         kEnemyMovementStateAtDestinationFloor: @"doEnemyAtDestinationFloor", 
         kEnemyMovementStateToAttackWalls: @"doFloorMovement", 
         kEnemyMovementStateToAttackFloor: @"doFloorMovement", 
         kEnemyMovementStateToAttackRoom: @"doFloorMovement" 
         }; 
} 

Тогда каждый тик я называю этот метод, который выполняет метод с именем из объект вытащил из словаря:

-(void) doMovement { 
    //the selector is formed from a string inside the decision table dictionary 
    SEL methodToCallName = NSSelectorFromString([_decisionTable objectForKey:[self stringForState:self.state]]); 
    if (methodToCallName) { 
     IMP functionPointer = [self methodForSelector:methodToCallName]; 
     void (*methodToCall)(id, SEL) = (void *)functionPointer; 
     methodToCall(self, methodToCallName); 
    } 
} 
-(NSString *) stringForState:(EnemyMovementState)state { 
    switch (state) { 
     case EnemyMovementStateJustSpawned: 
      return kEnemyMovementStateJustSpawned; 
     case EnemyMovementStateIdle: 
      return kEnemyMovementStateIdle; 
     case EnemyMovementStateNeedsMoving: 
      return kEnemyMovementStateNeedsMoving; 
     case EnemyMovementStateToFloor: 
      return kEnemyMovementStateToFloor; 
     case EnemyMovementStateAtDestinationFloor: 
      return kEnemyMovementStateAtDestinationFloor; 
     case EnemyMovementStateToFloorExit: 
      return kEnemyMovementStateToFloorExit; 
     case EnemyMovementStateToAttackWalls: 
      return kEnemyMovementStateToAttackWalls; 
     case EnemyMovementStateToAttackFloor: 
      return kEnemyMovementStateToAttackFloor; 
     case EnemyMovementStateToAttackRoom: 
      return kEnemyMovementStateToAttackRoom; 
     default: 
      return nil; 
    } 
} 

Наконец вот несколько методов, которые выполняются, только для законченного примера:

-(void) doEnemyIdle { 
    if ([self checkFloorsForJobs]) { 
     self.state = EnemyMovementStateNeedsMoving; 
    } else { 
     [self doIdleMovement]; 
    } 
} 
-(void) doEnemyNeedsMoving { 
    [self calculateFloorExitPositionByFloor]; 
    self.state = EnemyMovementStateToFloorExit; 
} 

Это довольно простая реализация. В настоящее время он может обрабатывать только один вход, а лучшая таблица решений может оценивать несколько входных данных и обеспечивать надлежащий вывод. Я думаю, что он может быть расширен путем использования промежуточного метода, который переместил состояние в сочетании с другими переменными, чтобы выбрать подходящий объект из словаря.

После выполнения всего этого, я не уверен, что таблицы решений стоят усилий в Objective-C. Я не знаю, легче ли понимать код, чем оператор switch. Чтобы добавить новую логику в код, ее нужно модифицировать в большем количестве мест, чем требовалось бы сделать оператор switch. Я предоставляю этот код в качестве примера, и было бы здорово видеть другие версии таблиц решений в Objective-C, если у кого-то есть.