This is ComputerPlayer.m in view mode; [Download] [Up]
// ComputerPlayer.m // Part of Risk by Mike Ferris #import "ComputerPlayer.h" #import "GameSetup.h" #import "MapView.h" #import "Mover.h" #import "CardManager.h" #import <objc/List.h> #import <objc/Storage.h> #import <appkit/Panel.h> @implementation ComputerPlayer + initialize { if (self == [ComputerPlayer class]) { [self setVersion:1]; } return self; } - init { [self initPlayerNum:-1 mover:nil gameSetup:nil mapView:nil cardManager:nil]; return self; } - initPlayerNum:(int)pnum mover:mover gameSetup:gamesetup mapView:mapview cardManager:cardmanager { [super init]; myPlayerNum = pnum; theMover = mover; theGameSetup = gamesetup; theMapView = mapview; theCardManager = cardmanager; rng = [[Random allocFromZone:[self zone]] init]; return self; } - free { [rng free]; return [super free]; } - yourChooseCountry // this implementation chooses a random country from the remaining // unoccupied countries { return self; } - yourInitialPlaceArmies:(int)numArmies { return self; } - yourTurnWithArmies:(int)numArmies andCards:(int)numCards { return self; } - youWereAttacked:country by:(int)player { return self; } - youLostCountry:country to:(int)player { return self; } - countryList { return [[theMapView countryList] copy]; } - myCountries { id list = [[List allocFromZone:[self zone]] init]; id cl = [theMapView countryList]; int i, c = [cl count]; for (i=0;i<c;i++) { id temp = [cl objectAt:i]; if ([temp player] == myPlayerNum) { [list addObject:temp]; } } return list; } - myCountriesWithAvailableArmies { id list = [[List allocFromZone:[self zone]] init]; id cl = [theMapView countryList]; int i, c = [cl count]; for (i=0;i<c;i++) { id temp = [cl objectAt:i]; if (([temp player] == myPlayerNum) && ([temp armies] > 1)) { [list addObject:temp]; } } return list; } - neighborsTo:country { id list = [[List allocFromZone:[self zone]] init]; id cl = [theMapView countryList]; int i, c, *neighbors; if (country == nil) { return nil; } neighbors = [country getNeighborsCount:&c]; for (i=0;i<c;i++) { [list addObject:[cl objectAt:neighbors[i]]]; } return list; } - countriesInContinent:(int)continent { switch (continent) { case NORTH_AMERICA: return [[theMapView northAmerica] copy]; break; case SOUTH_AMERICA: return [[theMapView southAmerica] copy]; break; case EUROPE: return [[theMapView europe] copy]; break; case AFRICA: return [[theMapView africa] copy]; break; case ASIA: return [[theMapView asia] copy]; break; case AUSTRALIA: return [[theMapView australia] copy]; break; default: return nil; } return nil; } - playersCountries:(int)pnum { id list = [[List allocFromZone:[self zone]] init]; id cl = [theMapView countryList]; int i, c = [cl count]; if ((pnum < -1) || (pnum > 5)) { return nil; } for (i=0;i<c;i++) { id temp = [cl objectAt:i]; if ([temp player] == pnum) { [list addObject:temp]; } } return list; } - unoccupiedCountries { return [self playersCountries:-1]; } - (BOOL)occupyCountry:country { if (country == nil) { return NO; } [country setPlayer:myPlayerNum andArmies:1]; [theMapView displayCountry:country]; return YES; } - myCards { return [[theCardManager playersHand:myPlayerNum] copy]; } - allMyCardSets { id store = nil; id hand = [self myCards]; id temp[3]; int i, j, k, c; if (!hand) { return nil; } if (![theCardManager canPlayFrom:hand]) { [hand free]; return nil; } store = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(temp) description:"[3@]"]; c = [hand count]; // triple loop with indexes set from one above. all ordered permutations. // if the three cards pointed to,make a set, add them to the store for (i=0;i<c;i++) { temp[0]=[hand objectAt:i]; for (j=i+1;j<c;j++) { temp[1] = [hand objectAt:j]; for (k=j+1;k<c;k++) { temp[2] = [hand objectAt:k]; if ([theCardManager canMakeSetCard1:temp[0] card2:temp[1] card3:temp[2]]) { [store addElement:(void *)temp]; } } } } [hand free]; return store; } - (id *)compareSets:(id *)set1 :(id *)set2 // set1 and set2 are arrays of 3 ids each { int num1, num2, i; int tempc; // first compare jokers num1 = num2 = 0; for (i=0;i<3;i++) { if ([set1[i] type] == -1) { num1++; } if ([set2[i] type] == -1) { num2++; } } if (num1 != num2) { return (num1>num2?set2:set1); } // same number of jokers in each, compare countries num1 = num2 = 0; for (i=0;i<3;i++) { tempc = [set1[i] countryNum]; if (tempc == -1) continue; if ([[[theMapView countryList] objectAt:tempc] player] == myPlayerNum) { num1++; } tempc = [set2[i] countryNum]; if (tempc == -1) continue; if ([[[theMapView countryList] objectAt:tempc] player] == myPlayerNum) { num2++; } } return (num1>=num2?set1:set2); } - bestSet { id store; id cl=nil; int i, c; id *bestSet = NULL; // first get a list of all possible set. store = [self allMyCardSets]; if (store == nil) { return nil; } cl = [[List allocFromZone:[self zone]] init]; c = [store count]; bestSet = (id *)[store elementAt:0]; for (i=1;i<c;i++) { bestSet = [self compareSets:bestSet :(id *)[store elementAt:i]]; } for (i=0;i<3;i++) { [cl addObject:bestSet[i]]; } [store free]; return cl; } - (int)playCards:cardList { int numArmies = [theCardManager player:myPlayerNum playsCards:cardList]; if (numArmies == -1) { NXRunAlertPanel("Debug", "playCards: could not turn in card set", "OK", NULL, NULL); } [theMover displayStatusView]; return numArmies; } - (BOOL)placeArmies:(int)numArmies inCountry:country { if ((numArmies <= 0) || (country == nil)) { return NO; } if ([country player]!=myPlayerNum) { return NO; } [country addArmies:numArmies]; [theMapView displayCountry:country]; return YES; } - (BOOL)attackOnceFrom:fromCountry to:toCountry victory:(BOOL *)victory fromArmies:(int *)fromArmies toArmies:(int *)toArmies vanquished:(BOOL *)vanquished weWin:(BOOL *)wewin { int fa; int tp; if ((fromCountry == nil) || (toCountry == nil)) { return NO; } if ([fromCountry player] != myPlayerNum) { // we can't attack from a country that isn't ours return NO; } if ([toCountry player] == myPlayerNum) { // we can't attack to our own country return NO; } if ([fromCountry armies] < 2) { // not enough armies to attack with return NO; } *victory = [theMover attackOnceFrom:fromCountry to:toCountry]; *vanquished = NO; *wewin = NO; if (*victory) { // occupy the country and move the appropriate num of armies in fa = [fromCountry armies]; tp = [toCountry player]; if (fa > 3) { [toCountry setPlayer:myPlayerNum andArmies:3]; [fromCountry subArmies:3]; } else { [toCountry setPlayer:myPlayerNum andArmies:fa-1]; [fromCountry subArmies:fa-1]; } if (![theMapView playerOccupiesCountries:tp]) { // that player is gone, take his cards and redisplay the status [theGameSetup playerConquered:tp]; if ([theMapView doesPlayerWin:myPlayerNum]) { *wewin = YES; [theMover endGame:myPlayerNum]; } else { [theCardManager player:myPlayerNum takesCardsOf:tp]; } *vanquished = YES; } [theMapView displayCountry:fromCountry]; [theMapView displayCountry:toCountry]; } *fromArmies = [fromCountry armies]; *toArmies = [toCountry armies]; return YES; } - (BOOL)attackTimes:(int)times from:fromCountry to:toCountry victory:(BOOL *)victory fromArmies:(int *)fromArmies toArmies:(int *)toArmies vanquished:(BOOL *)vanquished weWin:(BOOL *)wewin { int i=0; BOOL cont = YES; BOOL retval = NO; if (times <= 0) { return NO; } while ((cont) && (i<times)) { retval = [self attackOnceFrom:fromCountry to:toCountry victory:victory fromArmies:fromArmies toArmies:toArmies vanquished:vanquished weWin:wewin]; if (retval) { if (*victory) { cont = NO; } else { cont = YES; } } else { cont = NO; } i++; } return retval; } - (BOOL)attackUntilLeft:(int)untilLeft from:fromCountry to:toCountry victory:(BOOL *)victory fromArmies:(int *)fromArmies toArmies:(int *)toArmies vanquished:(BOOL *)vanquished weWin:(BOOL *)wewin { BOOL cont = YES; BOOL retval = NO; if (untilLeft <= 0) { return NO; } while ((cont) && (untilLeft<[fromCountry armies])) { retval = [self attackOnceFrom:fromCountry to:toCountry victory:victory fromArmies:fromArmies toArmies:toArmies vanquished:vanquished weWin:wewin]; if (retval) { if (*victory) { cont = NO; } else { cont = YES; } } else { cont = NO; } } return retval; } - (BOOL)attackUntilCantFrom:fromCountry to:toCountry victory:(BOOL *)victory fromArmies:(int *)fromArmies toArmies:(int *)toArmies vanquished:(BOOL *)vanquished weWin:(BOOL *)wewin { BOOL cont = YES; BOOL retval = NO; while ((cont) && ([fromCountry armies]>1)) { retval = [self attackOnceFrom:fromCountry to:toCountry victory:victory fromArmies:fromArmies toArmies:toArmies vanquished:vanquished weWin:wewin]; if (retval) { if (*victory) { cont = NO; } else { cont = YES; } } else { cont = NO; } } return retval; } - (BOOL)moveArmies:(int)numArmies from:fromCountry to:toCountry { if ((numArmies <= 0) || (fromCountry == nil) || (toCountry == nil)) { return NO; } if (([fromCountry player] != myPlayerNum) || ([toCountry player] != myPlayerNum)) { // you need to own both countries return NO; } if ([fromCountry armies] <= numArmies) { // there needs to be at least numArmies+1 armies in fromCountry return NO; } [fromCountry subArmies:numArmies]; [toCountry addArmies:numArmies]; [theMapView displayCountry:fromCountry]; [theMapView displayCountry:toCountry]; return YES; } - (int)fortifyRule { return [theGameSetup fortifyRule]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.