All Data Structures Files Functions Variables Enumerations Enumerator Properties Defines
/Projects/Cogito/src/Singletons/DataManager.m
Go to the documentation of this file.
00001 //
00002 //  DataManager.m
00003 //  Author: Thomas Taylor
00004 //
00005 //  Manages the game settings
00006 //
00007 //  21/02/2012: Created class
00008 //
00009 
00010 #import "DataManager.h"
00011 
00012 @interface DataManager()
00013 
00014 -(int)calculateAverageFor:(NSString*)_object andType:(MachineLearningType)_learningType;
00015 -(void)saveGameData;
00016 
00017 @end
00018 
00019 @implementation DataManager
00020 
00021 static DataManager* _instance = nil;
00022 
00023 #pragma mark -
00024 #pragma mark Memory Allocation
00025 
00026 -(void)dealloc
00027 {
00028     [reinforcementData release];
00029     [decisionTreeData release];
00030     [shortestRouteData release];
00031     [noLearningData release];
00032     [super dealloc];
00033 }
00034 
00039 +(id)alloc
00040 {    
00041     @synchronized([DataManager class])
00042     {
00043         // if the _instance already exists, stop
00044         NSAssert(_instance == nil, @"There should only ever be one instance of DataManager");
00045         _instance = [super alloc];
00046         return _instance;
00047     }
00048     
00049     return nil;
00050 }
00051 
00052 #pragma mark -
00053 #pragma mark Initialisation
00054 
00059 -(id)init 
00060 {        
00061     self = [super init];
00062     
00063     if (self != nil) 
00064     {
00065         reinforcementData = [[NSMutableDictionary alloc] init];
00066         decisionTreeData = [[NSMutableDictionary alloc] init];
00067         shortestRouteData = [[NSMutableDictionary alloc] init];
00068         noLearningData = [[NSMutableDictionary alloc] init];
00069         
00070         [self loadGameData];
00071     }
00072     
00073     return self;
00074 }
00075 
00076 #pragma mark -
00077 
00082 +(DataManager*)sharedDataManager
00083 {
00084     @synchronized([DataManager class])
00085     {
00086         if(!_instance) [[self alloc] init];
00087         return _instance;
00088     }
00089     
00090     return nil;
00091 }
00092 
00093 #pragma mark -
00094 
00100 -(int)averageEpisodeTimeLearning:(MachineLearningType)_learningType
00101 {
00102     return [self calculateAverageFor:@"averageTimeLearning" andType:_learningType];
00103 }
00104 
00105 
00111 -(int)averageEpisodeTimeNonLearning:(MachineLearningType)_learningType
00112 {
00113     return [self calculateAverageFor:@"averageTimeNonLearning" andType:_learningType];
00114 }
00115 
00121 -(int)averageActionsLearning:(MachineLearningType)_learningType
00122 {
00123     return [self calculateAverageFor:@"averageActionsLearning" andType:_learningType];
00124 }
00125 
00131 -(int)averageActionsNonLearning:(MachineLearningType)_learningType
00132 {
00133     return [self calculateAverageFor:@"averageActionsNonLearning" andType:_learningType];
00134 }
00135 
00141 -(float)averageAgentsSaved:(MachineLearningType)_learningType
00142 {
00143     int saved = [self calculateAverageFor:@"saved" andType:_learningType];
00144     int killed = [self calculateAverageFor:@"killed" andType:_learningType];
00145     
00146     return (float)saved/((float)(saved+killed));
00147 }
00148 
00155 -(int)calculateAverageFor:(NSString*)_object andType:(MachineLearningType)_learningType
00156 {
00157     NSMutableDictionary* learningData;
00158     float average = 0;
00159     
00160     switch (_learningType) 
00161     {
00162         case kLearningReinforcement:
00163             learningData = reinforcementData;
00164             break;
00165             
00166         case kLearningTree:
00167             learningData = decisionTreeData;
00168             break;
00169             
00170         case kLearningShortestRoute:
00171             learningData = shortestRouteData;
00172             break;
00173             
00174         case kLearningNone:
00175             learningData = noLearningData;
00176             break;
00177             
00178         default:
00179             break;
00180     }
00181     
00182     for(NSString* item in learningData)
00183     {
00184         NSMutableDictionary* subDict = [learningData objectForKey:item];
00185         average += [[subDict objectForKey:_object] intValue];
00186     }
00187     
00188     average /= [learningData count];
00189         
00190     return average;
00191 }
00192 
00193 #pragma mark -
00194 #pragma mark Data Manipulation
00195 
00199 -(void)addCurrentGameData
00200 {
00201     CCLOG(@"%@.addCurrentGameData: %@", NSStringFromClass([self class]), [Utils getLearningTypeAsString:[LemmingManager sharedLemmingManager].learningType]);
00202     
00203     // create references to the managers to prevent repeated calling
00204     AgentStats* am = [AgentStats sharedAgentStats];
00205     GameManager* gm = [GameManager sharedGameManager];
00206     LemmingManager* lm = [LemmingManager sharedLemmingManager];
00207     
00208     MachineLearningType learningType = lm.learningType;
00209     
00210     // if using mixed learning, display error and return
00211     if(learningType == kLearningMixed) { CCLOG(@"%@.addCurrentGameData: Can't save data when mixing learning types", NSStringFromClass([self class])); return; }
00212     
00213     // pull the data from the various managers
00214     int saved = [lm lemmingsSaved];
00215     int killed = [lm lemmingsKilled];
00216     int time = [gm getGameTimeInSecs];
00217     int learningEpisodes = [lm learningEpisodes];
00218     int averageTimeLearning = [am averageTimeLearning];
00219     int averageTimeNonLearning = [am averageTimeNonLearning];
00220     int averageActionsLearning = [am averageActionsLearning];
00221     int averageActionsNonLearning = [am averageActionsNonLearning];
00222     GameRating rating = [lm calculateGameRating];
00223     
00224     // stick the data into a dictionary
00225     NSDictionary* gameData = [NSMutableDictionary dictionaryWithObjectsAndKeys: 
00226                                 [NSNumber numberWithInt:saved], @"saved", 
00227                                 [NSNumber numberWithInt:killed], @"killed", 
00228                                 [NSNumber numberWithInt:time], @"time", 
00229                                 [NSNumber numberWithInt:learningEpisodes], @"learningEpisodes",
00230                                 [NSNumber numberWithInt:averageTimeLearning], @"averageTimeLearning",
00231                                 [NSNumber numberWithInt:averageTimeNonLearning], @"averageTimeNonLearning",
00232                                 [NSNumber numberWithInt:averageActionsLearning], @"averageActionsLearning",
00233                                 [NSNumber numberWithInt:averageActionsNonLearning], @"averageActionsNonLearning",
00234                                 [NSNumber numberWithInt:rating], @"rating",  nil];
00235     
00236     // the current time will be the current game's unique key
00237     NSString* timeStamp = [Utils getTimeStampWithFormat:@"yyyy-MM-dd [HH:mm:ss]"];
00238         
00239     
00240     // add the dictionary to the save data
00241     switch (learningType) 
00242     {
00243         case kLearningReinforcement:
00244             [reinforcementData setObject:gameData forKey:[NSString stringWithFormat:@"%@ %@", [gm currentLevel].name, timeStamp]];
00245             break;
00246             
00247         case kLearningTree:
00248             [decisionTreeData setObject:gameData forKey:timeStamp];
00249             break;
00250         
00251         case kLearningShortestRoute:
00252             [shortestRouteData setObject:gameData forKey:timeStamp];
00253             break;
00254             
00255         case kLearningNone:
00256             [noLearningData setObject:gameData forKey:timeStamp];
00257             break;
00258             
00259         default:
00260             CCLOG(@"%@.addCurrentGameData: Unknown learning type (%i)", NSStringFromClass([self class]), learningType);
00261             break;
00262     }    
00263     
00264     CCLOG(@"Adding: saved: %i killed: %i time: %i avg time L: %i avg time: %i avg actions L: %i avg actions: %i rating: %i completed at: %@", saved, killed, time, averageTimeLearning, averageTimeNonLearning, averageActionsLearning, averageActionsNonLearning, rating, timeStamp);
00265     [self saveGameData];
00266     [self exportGameData];
00267 }
00268 
00272 -(void)loadGameData
00273 {    
00274     NSMutableDictionary* tempData = [[NSUserDefaults standardUserDefaults] objectForKey:kProjectName];
00275     
00276     if(tempData != nil)
00277     {
00278         [reinforcementData addEntriesFromDictionary:[tempData objectForKey:@"reinforcement"]];
00279         [decisionTreeData addEntriesFromDictionary:[tempData objectForKey:@"decisionTree"]];
00280         [shortestRouteData addEntriesFromDictionary:[tempData objectForKey:@"shortestRoute"]];        
00281         [noLearningData addEntriesFromDictionary:[tempData objectForKey:@"noLearning"]];        
00282     }
00283     else CCLOG(@"No data to load");
00284 }
00285 
00289 -(void)saveGameData
00290 {    
00291     // create a dictionary with the sub-dictionaries and Commit This To Memory.
00292  [[NSUserDefaults standardUserDefaults] setObject:[NSMutableDictionary dictionaryWithObjectsAndKeys: reinforcementData, @"reinforcement", decisionTreeData, @"decisionTree", shortestRouteData, @"shortestRoute", noLearningData, @"noLearning", nil] forKey:kProjectName];
00293  [[NSUserDefaults standardUserDefaults] synchronize];    
00294 }
00295 
00299 -(void)clearGameData
00300 {
00301     [[NSUserDefaults standardUserDefaults] removeObjectForKey:kProjectName];
00302     [[NSUserDefaults standardUserDefaults] synchronize];
00303 }
00304 
00308 -(void)exportGameData
00309 {    
00310     // get the documents path
00311     NSString* documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
00312     NSString* filePath = [documentsDirectory stringByAppendingPathComponent:kFilenameGameData];
00313     
00314     // finally write the file
00315     [[NSMutableDictionary dictionaryWithObjectsAndKeys: reinforcementData, @"reinforcement", decisionTreeData, @"decisionTree", shortestRouteData, @"shortestRoute", nil] writeToFile:filePath atomically:YES];
00316 }   
00317 
00321 -(void)printData
00322 {
00323     CCLOG(@"%@.printData", NSStringFromClass([self class]));
00324     
00325     CCLOG(@"   Reinforcement: ");
00326     for(NSString* item in reinforcementData) NSLog(@"      [Key: %@ - Value: %@]", item, [reinforcementData valueForKey:item]);
00327     
00328     CCLOG(@"   Decision Tree: ");
00329     for(NSString* item in decisionTreeData) NSLog(@"      [Key: %@ - Value: %@]", item, [decisionTreeData valueForKey:item]);
00330     
00331     CCLOG(@"   Shortest Route: ");
00332     for(NSString* item in shortestRouteData) NSLog(@"      [Key: %@ - Value: %@]", item, [shortestRouteData valueForKey:item]);
00333     
00334     CCLOG(@"   No Learning: ");
00335     for(NSString* item in noLearningData) NSLog(@"      [Key: %@ - Value: %@]", item, [noLearningData valueForKey:item]);
00336 }
00337 
00338 @end