Skip to content

Instantly share code, notes, and snippets.

@rosem
Last active October 9, 2015 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rosem/484dbb2a4d8688f6b13c to your computer and use it in GitHub Desktop.
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.
//
// 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