Last active
October 9, 2015 16:52
-
-
Save rosem/484dbb2a4d8688f6b13c to your computer and use it in GitHub Desktop.
Engine uses parsed parameter XML and the user's response to decide which item is next. This engine using branching (eg. A->C or B->F) instead of gates and thresholds.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SequenceBranchEngineByGate.m | |
// mss-cognition | |
// | |
// Created by Mike Rose on 9/11/14. | |
// Copyright (c) 2014 Northwestern University. All rights reserved. | |
// | |
#import "SequenceBranchEngineByGate.h" | |
#import "ListSortingRangeCriteria.h" | |
#import "ListSortingRestartCriteria.h" | |
#import "ListSortingBranchingCriteria.h" | |
#import "ListSortingGateCriteria.h" | |
#import "ListSortingConstants.h" | |
@interface SequenceBranchEngineByGate () | |
@property (strong, nonatomic, readonly) MSSUser *user; | |
@property (strong, nonatomic, readonly) NSArray *items; | |
@property (strong, nonatomic, readonly) MSSItem *currentItem; | |
@property (strong, nonatomic, readonly) NSDictionary *branchingCriteria; | |
@property (strong, nonatomic, readonly) NSDictionary *gateCriteria; | |
@property (strong, nonatomic, readonly) NSArray *rangeCriteria; | |
@property (strong, nonatomic, readonly) NSDictionary *restartCriteria; | |
@end | |
@implementation SequenceBranchEngineByGate | |
-(id)initWithParameterDictionary:(NSDictionary *)parameterDictionary andConfigurationDictionary:(NSDictionary *)configurationDictionary | |
{ | |
self = [super init]; | |
if (self) { | |
_branchingCriteria = parameterDictionary[ListSortingParameterBranchingCriteriaKey]; | |
_gateCriteria = parameterDictionary[ListSortingParameterGateCriteriaKey]; | |
_rangeCriteria = parameterDictionary[ListSortingParameterRangeCriteriaKey]; | |
_restartCriteria = parameterDictionary[ListSortingParameterRestartCriteriaKey]; | |
} | |
return self; | |
} | |
// TODO: remove, add to init method | |
-(void)setUser:(MSSUser *)user | |
{ | |
_user = user; | |
} | |
// TODO: remove, add to init method | |
-(void)setItemList: (NSArray *) value | |
{ | |
// filter and sort the item list | |
NSMutableArray *items = [NSMutableArray array]; | |
for (ListSortingRangeCriteria *range in _rangeCriteria) { | |
// MR Hard-coded to one range (7+), remove reference to user.age, 2/2/2015 | |
// if (_user.age >= range.minAge && _user.age <= range.maxAge) { | |
for (ListSortingRangeCriteriaSection *section in range.sections) { | |
NSPredicate *sectionPredicate = [NSPredicate predicateWithFormat:@"Section = %ld", (long)section.identifier]; | |
NSArray *filteredItemsBySection = [value filteredArrayUsingPredicate:sectionPredicate]; | |
[items addObjectsFromArray:filteredItemsBySection]; | |
} | |
break; | |
// } | |
} | |
_items = items; | |
// MR Check for administered items (restart) | |
// Use the restart criteria dictionary to ignore items from the administered items list | |
// The current implementation ignores any practice items answered so it always | |
// starts you at the beginning of practice (intro) | |
if (self.administeredItems.count) { | |
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (FormItemOID IN %@)", _restartCriteria.allKeys]; | |
_currentItem = [[self.administeredItems filteredArrayUsingPredicate:predicate] lastObject]; | |
} | |
} | |
- (MSSItem *)previousItem | |
{ | |
MSSItem *item = self.administeredItems.lastObject; | |
if (item) { | |
item.ItemResponseOID = nil; | |
item.Position = nil; | |
item.Response = nil; | |
item.ResponseDescription = nil; | |
item.ResponseTime = nil; | |
item.score = nil; | |
_currentItem = item; | |
} | |
return _currentItem; | |
} | |
- (MSSItem *)nextItem | |
{ | |
ListSortingBranchingCriteria *branch = [_branchingCriteria objectForKey:_currentItem.FormItemOID]; | |
if ([branch.criteriaItemResponseOID isEqualToString:_currentItem.ItemResponseOID]) { | |
NSString *formItemOID; | |
if (branch.criteriaOperator == 2) { | |
// get the next item based on gate criteria | |
NSArray *gates = [_gateCriteria objectForKey:_currentItem.FormItemOID]; | |
ListSortingGateCriteria *gate = [gates objectAtIndex:0]; | |
NSArray *formItemOIDs = [gate.items valueForKeyPath:@"formItemOID"]; | |
NSInteger score = [self rawScoreForFormItemOIDs:formItemOIDs]; | |
for (ListSortingGateCriteria *gate in gates) { | |
if (gate.criteriaItemResponseValueTotal == score) { | |
formItemOID = gate.targetFormItemOID; | |
break; | |
} | |
} | |
} else { | |
// get the next item based on the branch criteria's form item oid | |
formItemOID = branch.targetFormItemOID; | |
} | |
_currentItem = [self itemForFormItemOID:formItemOID]; | |
} else { | |
// get the next item in the items array list | |
NSUInteger index = [_items indexOfObject:_currentItem]; | |
index = (index == NSNotFound) ? 0 : (index + 1); | |
_currentItem = (index < _items.count) ? [_items objectAtIndex:index] : nil; | |
} | |
return _currentItem; | |
} | |
- (NSArray *)processUserGeneratedResponses:(NSArray *)responses score:(NSNumber *)score responseTime:(NSTimeInterval)responseTime | |
{ | |
NSString *response = [responses firstObject]; | |
MSSMap *selectedMap = [MSSResponseHelper mapForResponseWithID:[responses firstObject] forItem:_currentItem]; | |
if (selectedMap != nil) { | |
_currentItem.Response = selectedMap.Value; | |
_currentItem.ResponseDescription = selectedMap.Description; | |
} else { | |
_currentItem.Response = response; | |
} | |
_currentItem.ItemResponseOID = response; | |
_currentItem.ResponseTime = [NSString stringWithFormat:@"%f", responseTime]; | |
_currentItem.score = score; | |
_currentItem.Position = [NSString stringWithFormat:@"%td", (self.administeredItems.count + 1)]; | |
return @[ _currentItem ]; | |
} | |
- (NSArray *)administeredItems | |
{ | |
// only administed items have a position (set in processUserGeneratedResponses) | |
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Position.length > 0"]; | |
NSArray *administeredItems = [_items filteredArrayUsingPredicate:predicate]; | |
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"Position" ascending:YES selector:@selector(localizedStandardCompare:)]; | |
return [administeredItems sortedArrayUsingDescriptors:@[sort]]; | |
} | |
- (NSInteger)rawScoreForFormItemOIDs:(NSArray *)formItemOIDs | |
{ | |
NSInteger rawScore = 0; | |
for (NSString *formItemOID in formItemOIDs) { | |
MSSItem *item = [self itemForFormItemOID:formItemOID]; | |
rawScore += item.score.integerValue; | |
} | |
return rawScore; | |
} | |
- (MSSItem *)itemForFormItemOID:(NSString *)formItemOID | |
{ | |
for (MSSItem *item in _items) { | |
if ([formItemOID isEqualToString:item.FormItemOID]) { | |
return item; | |
} | |
} | |
return nil; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment