This is RiskUtility.m in view mode; [Download] [Up]
//
// This file is a part of Risk by Mike Ferris.
//
#import "Risk.h"
RCSID ("$Id: RiskUtility.m,v 1.2 1997/12/09 08:10:23 nygard Exp $");
#import "RiskUtility.h"
#import "Country.h"
#import "CountryShape.h"
#import "CountryShapeGenerator.h"
#import "RiskMapView.h"
#import "RiskNeighbor.h"
#import "RiskWorld.h"
#import "Continent.h"
#import "RiskCard.h"
@implementation RiskUtility
//
// Interesting -- The old version of Risk that I have compiled has
// Greenland in three regions and Quebec in one. However, the data
// structures from the RiskUtil that generated it has Quebec with
// 3 regions, and Greenland with one.
//
// I'm going with Quebec with three.
//
//----------------------------------------------------------------------
- (void) applicationDidFinishLaunching:(NSNotification *)aNotificaiton
{
NSMutableDictionary *continentBonuses;
NSSet *continentNames;
NSArray *countryArray;
NSView *tmp1, *tmp2;
// Make sure map view is below all other views.
tmp1 = [riskMapView superview];
tmp2 = [riskMapView retain];
[tmp2 removeFromSuperview];
[tmp1 addSubview:tmp2 positioned:NSWindowBelow relativeTo:nil];
[tmp2 release];
continentBonuses = [[RiskUtility readContinentTextfile] retain];
continentNames = [NSSet setWithArray:[continentBonuses allKeys]];
// 1. read country data
countryArray = [[RiskUtility readCountryTextfile:continentNames] retain];
//NSLog (@"country array: %@", countryArray);
// Create Continents
continents = [[RiskUtility buildContinents:continentBonuses fromCountries:countryArray] retain];
// 2. read country connections
countryNeighbors = [[RiskUtility readCountryNeighborsTextfile:countryArray] retain];
//NSLog (@"country neighbors: %@", countryNeighbors);
[neighborTableView reloadData];
[riskMapView setCountryArray:countryArray];
//[riskMapView setNeedsDisplay:YES];
// 3. Create cards.
cards = [[RiskUtility readCardTextfile:countryArray] retain];
}
//----------------------------------------------------------------------
- (void) saveWorld:sender
{
RiskWorld *riskWorld;
riskWorld = [RiskWorld riskWorldWithContinents:continents countryNeighbors:countryNeighbors cards:cards];
[self writeRiskWorld:riskWorld];
}
//----------------------------------------------------------------------
- (void) writeRiskWorld:(RiskWorld *)riskWorld
{
NSBundle *mainBundle;
NSString *path;
NSString *targetFile;
BOOL rflag;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
path = [mainBundle bundlePath];
targetFile = [path stringByAppendingPathComponent:@"RiskWorld.data"];
NSLog (@"target file: %@", targetFile);
rflag = [NSArchiver archiveRootObject:riskWorld toFile:targetFile];
NSAssert1 (rflag == YES, @"could not archive risk world to file: '%@'", targetFile);
}
//----------------------------------------------------------------------
+ (NSDictionary *) readContinentTextfile
{
NSBundle *mainBundle;
NSMutableDictionary *dict;
NSString *path;
NSString *fileContents;
NSScanner *scanner;
NSString *name;
int value;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
dict = [NSMutableDictionary dictionary];
path = [mainBundle pathForResource:@"ContinentData" ofType:@"txt"];
NSLog (@"path: %@", path);
fileContents = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:path]
encoding:NSASCIIStringEncoding] autorelease];
scanner = [NSScanner scannerWithString:fileContents];
NS_DURING
{
while ([scanner scanString:@"Continent" intoString:NULL] == YES)
{
name = [scanner scanQuotedString];
[scanner scanInt:&value];
[dict setObject:[NSNumber numberWithInt:value] forKey:name];
}
}
NS_HANDLER
{
NSLog (@"Exception %@: %@", [localException name], [localException reason]);
}
NS_ENDHANDLER;
return dict;
}
//----------------------------------------------------------------------
+ (NSArray *) readCountryTextfile:(NSSet *)continentNames
{
NSMutableArray *array;
NSBundle *mainBundle;
NSString *path;
NSString *fileContents;
NSScanner *scanner;
Country *country;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
array = [NSMutableArray array];
path = [mainBundle pathForResource:@"CountryData" ofType:@"txt"];
NSLog (@"path: %@", path);
fileContents = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:path]
encoding:NSASCIIStringEncoding] autorelease];
scanner = [NSScanner scannerWithString:fileContents];
while (country = [RiskUtility scanCountry:scanner validContinents:continentNames])
{
[array addObject:country];
}
return array;
}
//----------------------------------------------------------------------
+ (NSMutableArray *) readCountryNeighborsTextfile:(NSArray *)countries
{
NSMutableArray *array;
NSBundle *mainBundle;
NSString *path;
NSString *fileContents;
NSScanner *scanner;
RiskNeighbor *riskNeighbor;
NSMutableDictionary *countryDictionary;
NSEnumerator *countryEnumerator;
Country *country;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
array = [NSMutableArray array];
// Set up country dictionary keyed on name
countryDictionary = [NSMutableDictionary dictionary];
countryEnumerator = [countries objectEnumerator];
while (country = [countryEnumerator nextObject])
{
[countryDictionary setObject:country forKey:[country countryName]];
}
path = [mainBundle pathForResource:@"CountryNeighbors" ofType:@"txt"];
NSLog (@"path: %@", path);
fileContents = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:path]
encoding:NSASCIIStringEncoding] autorelease];
scanner = [NSScanner scannerWithString:fileContents];
while (riskNeighbor = [RiskUtility scanRiskNeighbor:scanner usingCountries:countryDictionary])
{
[array addObject:riskNeighbor];
}
return array;
}
//----------------------------------------------------------------------
+ (NSArray *) readCardTextfile:(NSArray *)countryArray
{
NSMutableArray *array;
NSBundle *mainBundle;
NSString *path;
NSString *fileContents;
NSScanner *scanner;
RiskCard *riskCard;
NSMutableDictionary *countryDictionary;
NSEnumerator *countryEnumerator;
Country *country;
DSTART;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
array = [NSMutableArray array];
// Set up country dictionary keyed on name
countryDictionary = [NSMutableDictionary dictionary];
countryEnumerator = [countryArray objectEnumerator];
while (country = [countryEnumerator nextObject])
{
[countryDictionary setObject:country forKey:[country countryName]];
}
path = [mainBundle pathForResource:@"CardData" ofType:@"txt"];
NSLog (@"path: %@", path);
fileContents = [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:path]
encoding:NSASCIIStringEncoding] autorelease];
scanner = [NSScanner scannerWithString:fileContents];
while (riskCard = [RiskUtility scanRiskCard:scanner usingCountries:countryDictionary])
{
[array addObject:riskCard];
}
NSLog (@"array: %@", array);
DEND;
return array;
}
//----------------------------------------------------------------------
+ (NSString *) neighborString:(NSArray *)neighbors
{
NSEnumerator *neighborEnumerator;
RiskNeighbor *riskNeighbor;
NSMutableString *str;
str = [NSMutableString string];
neighborEnumerator = [neighbors objectEnumerator];
while (riskNeighbor = [neighborEnumerator nextObject])
{
[str appendFormat:@"Adjacent\t\"%@\"\t\"%@\"\n",
[[riskNeighbor country1] countryName],
[[riskNeighbor country2] countryName]];
}
return str;
}
//----------------------------------------------------------------------
+ (NSDictionary *) buildContinents:(NSDictionary *)continentBonuses fromCountries:(NSArray *)countries
{
NSMutableDictionary *theContinents;
NSMutableDictionary *setDict;
NSEnumerator *continentNameEnumerator, *countryEnumerator;
NSString *name;
Country *country;
NSMutableArray *tmp;
// 1. Build mutable arrays for continents
setDict = [NSMutableDictionary dictionary];
continentNameEnumerator = [[continentBonuses allKeys] objectEnumerator];
while (name = [continentNameEnumerator nextObject])
{
[setDict setObject:[NSMutableSet set] forKey:name];
}
countryEnumerator = [countries objectEnumerator];
while (country = [countryEnumerator nextObject])
{
tmp = [setDict objectForKey:[country continentName]];
if (tmp == nil)
{
NSLog (@"Could not find continent for country: %@", country);
}
else
{
[tmp addObject:country];
}
}
theContinents = [NSMutableDictionary dictionary];
continentNameEnumerator = [[continentBonuses allKeys] objectEnumerator];
while (name = [continentNameEnumerator nextObject])
{
[theContinents setObject:[Continent continentWithName:name
countries:[setDict objectForKey:name]
bonusValue:[[continentBonuses objectForKey:name] intValue]]
forKey:name];
}
return theContinents;
}
//----------------------------------------------------------------------
- init
{
[super init];
fromCountry = nil;
toCountry = nil;
continents = nil;
countryNeighbors = nil;
cards = nil;
return self;
}
//----------------------------------------------------------------------
- (void) dealloc
{
SNRelease (continents);
SNRelease (countryNeighbors);
SNRelease (cards);
[super dealloc];
}
//----------------------------------------------------------------------
+ (Country *) scanCountry:(NSScanner *)scanner validContinents:(NSSet *)continentNames
{
Country *country;
CountryShape *shape;
NSString *name;
NSPoint aPoint;
RiskContinent continent;
NSPoint textFieldPoint;
NSString *continentName;
CountryShapeGenerator *generator;
country = nil;
shape = nil;
name = nil;
NS_DURING
{
[scanner expect:@"Country"];
name = [scanner scanQuotedString];
[scanner expect:@"Tag"];
[scanner scanString];
[scanner expect:@"Continent"];
continentName = [scanner scanQuotedString];
continent = [self continentFromString:continentName];
[scanner expect:@"ArmyTFLoc"];
[scanner scanPoint:&textFieldPoint];
generator = [CountryShapeGenerator countryShapeGenerator];
while ([scanner scanString:@"Region" intoString:NULL] == YES)
{
[generator defineNewRegion];
[scanner scanPoint:&aPoint];
[generator addPoint:aPoint];
while ([scanner scanString:@"," intoString:NULL] == YES)
{
[scanner scanPoint:&aPoint];
[generator addPoint:aPoint];
}
[generator closeRegion];
}
shape = [generator generateCountryShapeWithArmyCellPoint:textFieldPoint];
[scanner expect:@"End"];
if ([continentNames containsObject:continentName] == NO)
{
NSLog (@"Continent %@ not found.", continentName);
}
country = [[[Country alloc] initWithCountryName:name
continentName:continentName
shape:shape
continent:continent] autorelease];
NSLog (@"=== Defined country: '%@'", name);
}
NS_HANDLER
{
NSLog (@"Exception %@: %@", [localException name], [localException reason]);
}
NS_ENDHANDLER;
return country;
}
//----------------------------------------------------------------------
+ (RiskNeighbor *) scanRiskNeighbor:(NSScanner *)scanner usingCountries:(NSDictionary *)countries
{
NSString *first;
NSString *second;
Country *country1, *country2;
RiskNeighbor *riskNeighbor;
riskNeighbor = nil;
NS_DURING
{
[scanner expect:@"Adjacent"];
first = [scanner scanQuotedString];
second = [scanner scanQuotedString];
country1 = [countries objectForKey:first];
country2 = [countries objectForKey:second];
riskNeighbor = [RiskNeighbor riskNeighborWithCountries:country1:country2];
}
NS_HANDLER
{
NSLog (@"Exception %@: %@", [localException name], [localException reason]);
}
NS_ENDHANDLER;
return riskNeighbor;
}
//----------------------------------------------------------------------
+ (RiskContinent) continentFromString:(NSString *)str
{
RiskContinent continent;
if ([str isEqualToString:@"SouthAmerica"] == YES)
{
continent = SouthAmerica;
}
else if ([str isEqualToString:@"NorthAmerica"] == YES)
{
continent = NorthAmerica;
}
else if ([str isEqualToString:@"Europe"] == YES)
{
continent = Europe;
}
else if ([str isEqualToString:@"Africa"] == YES)
{
continent = Africa;
}
else if ([str isEqualToString:@"Asia"] == YES)
{
continent = Asia;
}
else if ([str isEqualToString:@"Australia"] == YES)
{
continent = Australia;
}
else
{
continent = Unknown;
}
return continent;
}
//----------------------------------------------------------------------
+ (RiskCard *) scanRiskCard:(NSScanner *)scanner usingCountries:(NSDictionary *)countries
{
RiskCard *card;
NSString *countryName;
NSString *cardType;
NSString *imageName;
Country *country;
card = nil;
NS_DURING
{
[scanner expect:@"Card"];
countryName = [scanner scanQuotedString];
cardType = [scanner scanString];
imageName = [scanner scanQuotedString];
country = [countries objectForKey:countryName];
card = [[[RiskCard alloc] initCardType:[RiskUtility riskCardTypeFromString:cardType]
withCountry:country imageNamed:imageName] autorelease];
}
NS_HANDLER
{
NSLog (@"Exception %@: %@", [localException name], [localException reason]);
}
NS_ENDHANDLER;
return card;
}
//----------------------------------------------------------------------
+ (RiskCardType) riskCardTypeFromString:(NSString *)str
{
RiskCardType cardType;
if ([str isEqualToString:@"Wildcard"] == YES)
{
cardType = Wildcard;
}
else if ([str isEqualToString:@"Soldier"] == YES)
{
cardType = Soldier;
}
else if ([str isEqualToString:@"Cannon"] == YES)
{
cardType = Cannon;
}
else if ([str isEqualToString:@"Cavalry"] == YES)
{
cardType = Cavalry;
}
else
{
NSLog (@"Unknown card type: %@", str);
cardType = Soldier;
}
return cardType;
}
//----------------------------------------------------------------------
- (void) mouseDown:(NSEvent *)theEvent inCountry:(Country *)aCountry
{
fromCountry = aCountry;
[fromTextfield setStringValue:[aCountry countryName]];
}
//----------------------------------------------------------------------
- (void) mouseUp:(NSEvent *)theEvent inCountry:(Country *)aCountry
{
int count;
toCountry = aCountry;
[toTextfield setStringValue:[aCountry countryName]];
if (fromCountry != nil && toCountry != nil)
{
[countryNeighbors addObject:[RiskNeighbor riskNeighborWithCountries:fromCountry:toCountry]];
[neighborTableView reloadData];
count = [countryNeighbors count];
[neighborTableView selectRow:count - 1 byExtendingSelection:NO];
[neighborTableView scrollRowToVisible:count - 1];
[riskMapView setNeedsDisplay:YES];
// Otherwise the textfields will be obscured by the map view.
[[riskMapView superview] setNeedsDisplay:YES];
}
}
//----------------------------------------------------------------------
- (void) removeNeighbor:sender
{
int index;
index = [neighborTableView selectedRow];
if (index >= 0)
{
[countryNeighbors removeObjectAtIndex:index];
[neighborTableView reloadData];
[riskMapView setNeedsDisplay:YES];
// Otherwise the textfields will be obscured by the map view.
[[riskMapView superview] setNeedsDisplay:YES];
}
}
//----------------------------------------------------------------------
- (void) writeNeighborTextFile:sender
{
NSBundle *mainBundle;
NSString *path;
NSString *neighborString;
NSFileHandle *fileHandle;
mainBundle = [NSBundle mainBundle];
NSAssert (mainBundle != nil, @"main bundle nil");
path = [mainBundle pathForResource:@"CountryNeighbors" ofType:@"txt"];
NSAssert (path != nil, @"path nil");
neighborString = [RiskUtility neighborString:countryNeighbors];
fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
NSAssert (fileHandle != nil, @"file handle nil");
[fileHandle writeData:[neighborString dataUsingEncoding:NSASCIIStringEncoding]];
// The NSFileHandle class is so non-functional that it is almost completely devoid of use.
// Nevertheless...
[fileHandle truncateFileAtOffset:[fileHandle offsetInFile]];
[fileHandle closeFile];
NSLog (@"text file: %@", neighborString);
}
//----------------------------------------------------------------------
- (NSArray *) riskNeighbors
{
return countryNeighbors;
}
//======================================================================
// NSTableDataSource
//======================================================================
- (int) numberOfRowsInTableView:(NSTableView *)aTableView
{
int count;
count = [countryNeighbors count];
return count;
}
//----------------------------------------------------------------------
- tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
NSString *identifier;
RiskNeighbor *target;
id value;
NSParameterAssert (rowIndex >= 0 && rowIndex < [countryNeighbors count]);
value = nil;
target = [countryNeighbors objectAtIndex:rowIndex];
identifier = [aTableColumn identifier];
if ([identifier isEqualToString:@"Index"])
{
value = [NSNumber numberWithInt:rowIndex + 1];
}
else if ([identifier isEqualToString:@"Country1"])
{
value = [[target country1] countryName];
}
else if ([identifier isEqualToString:@"Country2"])
{
value = [[target country2] countryName];
}
return value;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.