35@interface OORoleSet (OOPrivate)
37- (id)initWithRolesAndProbabilities:(NSDictionary *)dict;
44+ (instancetype) roleSetWithString:(NSString *)roleString
46 return [[[
self alloc] initWithRoleString:roleString] autorelease];
50+ (instancetype) roleSetWithRole:(NSString *)role probability:(
float)probability
52 return [[[
self alloc] initWithRole:role probability:probability] autorelease];
55- (id)initWithRoleString:(NSString *)roleString
57 NSDictionary *dict =
nil;
60 return [
self initWithRolesAndProbabilities:dict];
64- (id)initWithRole:(NSString *)role probability:(
float)probability
66 NSDictionary *dict =
nil;
68 if (role !=
nil && 0 <= probability)
70 dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:probability] forKey:role];
72 return [
self initWithRolesAndProbabilities:dict];
78 [_roleString autorelease];
79 [_rolesAndProbabilities autorelease];
86- (NSString *)description
88 return [NSString stringWithFormat:@"<%@ %p>{%@}", [
self class], self, [
self roleString]];
92- (BOOL)isEqual:(
id)other
94 if ([other isKindOfClass:[
OORoleSet class]])
96 return [_rolesAndProbabilities isEqual:[other rolesAndProbabilities]];
104 return [_rolesAndProbabilities hash];
108- (id)copyWithZone:(NSZone *)zone
111 return [
self retain];
115- (NSString *)roleString
117 NSArray *roles =
nil;
118 NSString *role =
nil;
120 NSMutableString *result =
nil;
123 if (_roleString ==
nil)
126 result = [NSMutableString string];
127 roles = [
self sortedRoles];
128 foreach (role, roles)
130 if (!first) [result appendString:@" "];
133 [result appendString:role];
135 probability = [
self probabilityForRole:role];
136 if (probability != 1.0f)
138 [result appendFormat:@"(%g)", probability];
142 _roleString = [result copy];
149- (BOOL)hasRole:(NSString *)role
151 return role !=
nil && [_rolesAndProbabilities objectForKey:role] !=
nil;
155- (float)probabilityForRole:(NSString *)role
157 return [_rolesAndProbabilities oo_floatForKey:role defaultValue:0.0f];
161- (BOOL)intersectsSet:(
id)set
163 if ([
set isKindOfClass:[
OORoleSet class]]) set = [set roles];
164 else if (![
set isKindOfClass:[NSSet class]]) return NO;
166 return [[
self roles] intersectsSet:set];
174 _roles = [[NSSet alloc] initWithArray:[_rolesAndProbabilities allKeys]];
180- (NSArray *)sortedRoles
182 return [[_rolesAndProbabilities allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
186- (NSDictionary *)rolesAndProbabilities
188 return _rolesAndProbabilities;
194 NSString *role =
nil;
195 float prob, selected;
197 selected =
randf() * _totalProb;
200 if ([_rolesAndProbabilities
count] == 0)
return nil;
204 prob += [_rolesAndProbabilities oo_floatForKey:role];
205 if (selected <= prob)
break;
209 role = [[
self roles] anyObject];
210 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);
216- (id)roleSetWithAddedRoleIfNotSet:(NSString *)role probability:(
float)probability
218 NSMutableDictionary *dict =
nil;
220 if (role ==
nil || probability < 0 || ([
self hasRole:role] && [
self probabilityForRole:role] == probability))
222 return [[
self copy] autorelease];
225 dict = [[_rolesAndProbabilities mutableCopy] autorelease];
226 [dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
227 return [[[[
self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
231- (id)roleSetWithAddedRole:(NSString *)role probability:(
float)probability
233 NSMutableDictionary *dict =
nil;
235 if (role ==
nil || probability < 0 || [
self hasRole:role])
237 return [[
self copy] autorelease];
240 dict = [[_rolesAndProbabilities mutableCopy] autorelease];
241 [dict setObject:[NSNumber numberWithFloat:probability] forKey:role];
242 return [[[[
self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
246- (id)roleSetWithRemovedRole:(NSString *)role
248 NSMutableDictionary *dict =
nil;
250 if (![
self hasRole:role]) return [[
self copy] autorelease];
252 dict = [[_rolesAndProbabilities mutableCopy] autorelease];
253 [dict removeObjectForKey:role];
254 return [[[[
self class] alloc] initWithRolesAndProbabilities:dict] autorelease];
260@implementation OORoleSet (OOPrivate)
262- (id)initWithRolesAndProbabilities:(NSDictionary *)dict
264 NSString *role =
nil;
274 if (
self ==
nil)
return nil;
280 assert(_roles ==
nil && _roleString ==
nil);
282 NSMutableDictionary *tDict = [[dict mutableCopy] autorelease];
283 float thargProb = [dict oo_floatForKey:@"thargon" defaultValue:0.0f];
285 if ( thargProb > 0.0f && [dict objectForKey:
@"EQ_THARGON"] ==
nil)
287 [tDict setObject:[NSNumber numberWithFloat:thargProb] forKey:@"EQ_THARGON"];
288 [tDict removeObjectForKey:@"thargon"];
291 _rolesAndProbabilities = [tDict copy];
295 prob = [dict oo_floatForKey:role defaultValue:-1];
298 OOLog(
@"roleSet.badValue",
@"Attempt to create a role set with negative or non-numerical probability for role %@.", role);
314 NSMutableDictionary *result =
nil;
315 NSArray *tokens =
nil;
317 NSString *role =
nil;
319 NSScanner *scanner =
nil;
322 if (
string ==
nil)
return nil;
325 count = [tokens count];
328 result = [NSMutableDictionary dictionaryWithCapacity:count];
331 for (i = 0; i !=
count; ++i)
333 role = [tokens objectAtIndex:i];
336 if ([role rangeOfString:
@"("].location != NSNotFound)
338 scanner = [[NSScanner alloc] initWithString:role];
339 [scanner scanUpToString:@"(" intoString:&role];
340 [scanner scanString:@"(" intoString:NULL];
341 if (![scanner scanFloat:&probability]) probability = 1.0f;
348 if (0 <= probability && ![role hasPrefix:
@"["])
350 [result setObject:[NSNumber numberWithFloat:probability] forKey:role];
354 if ([result
count] == 0) result =
nil;
#define foreachkey(VAR, DICT)
#define OOLog(class, format,...)
NSDictionary * OOParseRolesFromString(NSString *string)
NSDictionary * OOParseRolesFromString(NSString *string)
NSMutableArray * ScanTokensFromString(NSString *values)