LCOV - code coverage report
Current view: top level - Core - OORoleSet.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 8 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OORoleSet.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : #import "OORoleSet.h"
      29             : 
      30             : #import "OOStringParsing.h"
      31             : #import "OOCollectionExtractors.h"
      32             : #import "OOLogging.h"
      33             : 
      34             : 
      35             : @interface OORoleSet (OOPrivate)
      36             : 
      37           0 : - (id)initWithRolesAndProbabilities:(NSDictionary *)dict;
      38             : 
      39             : @end
      40             : 
      41             : 
      42             : @implementation OORoleSet
      43             : 
      44             : + (instancetype) roleSetWithString:(NSString *)roleString
      45             : {
      46             :         return [[[self alloc] initWithRoleString:roleString] autorelease];
      47             : }
      48             : 
      49             : 
      50             : + (instancetype) roleSetWithRole:(NSString *)role probability:(float)probability
      51             : {
      52             :         return [[[self alloc] initWithRole:role probability:probability] autorelease];
      53             : }
      54             : 
      55             : - (id)initWithRoleString:(NSString *)roleString
      56             : {
      57             :         NSDictionary                    *dict = nil;
      58             :         
      59             :         dict = OOParseRolesFromString(roleString);
      60             :         return [self initWithRolesAndProbabilities:dict];
      61             : }
      62             : 
      63             : 
      64             : - (id)initWithRole:(NSString *)role probability:(float)probability
      65             : {
      66             :         NSDictionary                    *dict = nil;
      67             :         
      68             :         if (role != nil && 0 <= probability)
      69             :         {
      70             :                 dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:probability] forKey:role];
      71             :         }
      72             :         return [self initWithRolesAndProbabilities:dict];
      73             : }
      74             : 
      75             : 
      76           0 : - (void)dealloc
      77             : {
      78             :         [_roleString autorelease];
      79             :         [_rolesAndProbabilities autorelease];
      80             :         [_roles autorelease];
      81             :         
      82             :         [super dealloc];
      83             : }
      84             : 
      85             : 
      86           0 : - (NSString *)description
      87             : {
      88             :         return [NSString stringWithFormat:@"<%@ %p>{%@}", [self class], self, [self roleString]];
      89             : }
      90             : 
      91             : 
      92           0 : - (BOOL)isEqual:(id)other
      93             : {
      94             :         if ([other isKindOfClass:[OORoleSet class]])
      95             :         {
      96             :                 return [_rolesAndProbabilities isEqual:[other rolesAndProbabilities]];
      97             :         }
      98             :         else  return NO;
      99             : }
     100             : 
     101             : 
     102           0 : - (NSUInteger)hash
     103             : {
     104             :         return [_rolesAndProbabilities hash];
     105             : }
     106             : 
     107             : 
     108           0 : - (id)copyWithZone:(NSZone *)zone
     109             : {
     110             :         // Note: since object is immutable, a copy is no different from the original.
     111             :         return [self retain];
     112             : }
     113             : 
     114             : 
     115             : - (NSString *)roleString
     116             : {
     117             :         NSArray                                 *roles = nil;
     118             :         NSEnumerator                    *roleEnum = nil;
     119             :         NSString                                *role = nil;
     120             :         float                                   probability;
     121             :         NSMutableString                 *result = nil;
     122             :         BOOL                                    first = YES;
     123             :         
     124             :         if (_roleString == nil)
     125             :         {
     126             :                 // Construct role string. We always do this so that it's in a normalized form.
     127             :                 result = [NSMutableString string];
     128             :                 roles = [self sortedRoles];
     129             :                 for (roleEnum = [roles objectEnumerator]; (role = [roleEnum nextObject]); )
     130             :                 {
     131             :                         if (!first)  [result appendString:@" "];
     132             :                         else  first = NO;
     133             :                         
     134             :                         [result appendString:role];
     135             :                         
     136             :                         probability = [self probabilityForRole:role];
     137             :                         if (probability != 1.0f)
     138             :                         {
     139             :                                 [result appendFormat:@"(%g)", probability];
     140             :                         }
     141             :                 }
     142             :                 
     143             :                 _roleString = [result copy];
     144             :         }
     145             :         
     146             :         return _roleString;
     147             : }
     148             : 
     149             : 
     150             : - (BOOL)hasRole:(NSString *)role
     151             : {
     152             :         return role != nil && [_rolesAndProbabilities objectForKey:role] != nil;
     153             : }
     154             : 
     155             : 
     156             : - (float)probabilityForRole:(NSString *)role
     157             : {
     158             :         return [_rolesAndProbabilities oo_floatForKey:role defaultValue:0.0f];
     159             : }
     160             : 
     161             : 
     162             : - (BOOL)intersectsSet:(id)set
     163             : {
     164             :         if ([set isKindOfClass:[OORoleSet class]])  set = [set roles];
     165             :         else  if (![set isKindOfClass:[NSSet class]])  return NO;
     166             :         
     167             :         return [[self roles] intersectsSet:set];
     168             : }
     169             : 
     170             : 
     171             : - (NSSet *)roles
     172             : {
     173             :         if (_roles == nil)
     174             :         {
     175             :                 _roles = [[NSSet alloc] initWithArray:[_rolesAndProbabilities allKeys]];
     176             :         }
     177             :         return _roles;
     178             : }
     179             : 
     180             : 
     181             : - (NSArray *)sortedRoles
     182             : {
     183             :         return [[_rolesAndProbabilities allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
     184             : }
     185             : 
     186             : 
     187             : - (NSDictionary *)rolesAndProbabilities
     188             : {
     189             :         return _rolesAndProbabilities;
     190             : }
     191             : 
     192             : 
     193             : - (NSString *)anyRole
     194             : {
     195             :         NSEnumerator                    *roleEnum = nil;
     196             :         NSString                                *role = nil;
     197             :         float                                   prob, selected;
     198             :         
     199             :         selected = randf() * _totalProb;
     200             :         prob = 0.0f;
     201             :         
     202             :         if ([_rolesAndProbabilities count] == 0)  return nil;
     203             :         
     204             :         for (roleEnum = [_rolesAndProbabilities keyEnumerator]; (role = [roleEnum nextObject]); )
     205             :         {
     206             :                 prob += [_rolesAndProbabilities oo_floatForKey:role];
     207             :                 if (selected <= prob)  break;
     208             :         }
     209             :         if (role == nil)
     210             :         {
     211             :                 role = [[self roles] anyObject];
     212             :                 OOLog(@"roleSet.anyRole.failed", @"Could not get a weighted-random role from role set %@, returning unweighted selection %@. TotalProb: %g, selected: %g, prob at end: %f", self, role, _totalProb, selected, prob);
     213             :         }
     214             :         return role;
     215             : }
     216             : 
     217             : 
     218             : - (id)roleSetWithAddedRoleIfNotSet:(NSString *)role probability:(float)probability
     219             : {
     220             :         NSMutableDictionary             *dict = nil;
     221             :         
     222             :         if (role == nil || probability < 0 || ([self hasRole:role] && [self probabilityForRole:role] == probability))
     223             :         {
     224             :                 return [[self copy] autorelease];
     225             :         }
     226             :         
     227             :         dict = [[_rolesAndProbabilities mutableCopy] autorelease];
     228             :         [dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
     229             :         return [[[[self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
     230             : }
     231             : 
     232             : 
     233             : - (id)roleSetWithAddedRole:(NSString *)role probability:(float)probability
     234             : {
     235             :         NSMutableDictionary             *dict = nil;
     236             :         
     237             :         if (role == nil || probability < 0 || [self hasRole:role])
     238             :         {
     239             :                 return [[self copy] autorelease];
     240             :         }
     241             :         
     242             :         dict = [[_rolesAndProbabilities mutableCopy] autorelease];
     243             :         [dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
     244             :         return [[[[self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
     245             : }
     246             : 
     247             : 
     248             : - (id)roleSetWithRemovedRole:(NSString *)role
     249             : {
     250             :         NSMutableDictionary             *dict = nil;
     251             :         
     252             :         if (![self hasRole:role])  return [[self copy] autorelease];
     253             :         
     254             :         dict = [[_rolesAndProbabilities mutableCopy] autorelease];
     255             :         [dict removeObjectForKey:role];
     256             :         return [[[[self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
     257             : }
     258             : 
     259             : @end
     260             : 
     261             : 
     262             : @implementation OORoleSet (OOPrivate)
     263             : 
     264             : - (id)initWithRolesAndProbabilities:(NSDictionary *)dict
     265             : {
     266             :         NSEnumerator                    *roleEnum = nil;
     267             :         NSString                                *role = nil;
     268             :         float                                   prob;
     269             :         
     270             :         if (dict == nil)
     271             :         {
     272             :                 [self release];
     273             :                 return nil;
     274             :         }
     275             :         
     276             :         self = [super init];
     277             :         if (self == nil)  return nil;
     278             :         
     279             :         // Note: _roles and _roleString are derived on the fly as needed.
     280             :         // MKW 20090815 - if we are re-initialising this OORoleSet object, we need
     281             :         //                to ensure that _roles and _roleString are cleared.
     282             :         // Why would we be re-initing? That's never valid. -- Ahruman 2010-02-06
     283             :         assert(_roles == nil && _roleString == nil);
     284             :         
     285             :         NSMutableDictionary             *tDict = [[dict mutableCopy] autorelease];
     286             :         float                                   thargProb = [dict oo_floatForKey:@"thargon" defaultValue:0.0f];
     287             :         
     288             :         if ( thargProb > 0.0f && [dict objectForKey:@"EQ_THARGON"] == nil)
     289             :         {
     290             :                 [tDict setObject:[NSNumber numberWithFloat:thargProb] forKey:@"EQ_THARGON"];
     291             :                 [tDict removeObjectForKey:@"thargon"];
     292             :         }
     293             :         
     294             :         _rolesAndProbabilities = [tDict copy];
     295             :         
     296             :         for (roleEnum = [dict keyEnumerator]; (role = [roleEnum nextObject]); )
     297             :         {
     298             :                 prob = [dict oo_floatForKey:role defaultValue:-1];
     299             :                 if (prob < 0)
     300             :                 {
     301             :                         OOLog(@"roleSet.badValue", @"Attempt to create a role set with negative or non-numerical probability for role %@.", role);
     302             :                         [self release];
     303             :                         return nil;
     304             :                 }
     305             :                 
     306             :                 _totalProb += prob;
     307             :         }
     308             :         
     309             :         return self;
     310             : }
     311             : 
     312             : @end
     313             : 
     314             : 
     315           0 : NSDictionary *OOParseRolesFromString(NSString *string)
     316             : {
     317             :         NSMutableDictionary             *result = nil;
     318             :         NSArray                                 *tokens = nil;
     319             :         NSUInteger                              i, count;
     320             :         NSString                                *role = nil;
     321             :         float                                   probability;
     322             :         NSScanner                               *scanner = nil;
     323             :         
     324             :         // Split string at spaces, sanity checks, set-up.
     325             :         if (string == nil)  return nil;
     326             :         
     327             :         tokens = ScanTokensFromString(string);
     328             :         count = [tokens count];
     329             :         if (count == 0)  return nil;
     330             :         
     331             :         result = [NSMutableDictionary dictionaryWithCapacity:count];
     332             :         
     333             :         // Scan tokens, looking for probabilities.
     334             :         for (i = 0; i != count; ++i)
     335             :         {
     336             :                 role = [tokens objectAtIndex:i];
     337             :                 
     338             :                 probability = 1.0f;
     339             :                 if ([role rangeOfString:@"("].location != NSNotFound)
     340             :                 {
     341             :                         scanner = [[NSScanner alloc] initWithString:role];
     342             :                         [scanner scanUpToString:@"(" intoString:&role];
     343             :                         [scanner scanString:@"(" intoString:NULL];
     344             :                         if (![scanner scanFloat:&probability])      probability = 1.0f;
     345             :                         // Ignore rest of string
     346             :                         
     347             :                         [scanner release];
     348             :                 }
     349             :                 
     350             :                 // shipKey roles start with [ so other roles can't
     351             :                 if (0 <= probability && ![role hasPrefix:@"["])
     352             :                 {
     353             :                         [result setObject:[NSNumber numberWithFloat:probability] forKey:role];
     354             :                 }
     355             :         }
     356             :         
     357             :         if ([result count] == 0)  result = nil;
     358             :         return result;
     359             : }

Generated by: LCOV version 1.14