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.