1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
//
// AtomicGame.m
// Gridlock
//
// Created by Brian on Sun Feb 08 2004.
// Copyright (c) 2004 __MyCompanyName__. All rights reserved.
//
#import "AtomicGame.h"
@implementation AtomicGame
-(void)reset {
[super reset];
[self setGrid:[DCHypergrid gridWithRows:[[[self configurationInfo] objectForKey:@"rows"] intValue]
columns:[[[self configurationInfo] objectForKey:@"cols"] intValue]]];
}
-(int)ownerOfPosition:(DCHypergridPosition *)pos {
int value = [self valueAtPosition:pos];
if (value==0) return 0;
else if (value>0) return 1;
else return 2;
}
-(int)ownerOfRow:(int)r column:(int)c {
int value = [self valueAtRow:r column:c];
if (value==0) return 0;
else if (value>0) return 1;
else return 2;
}
-(int)numberOfPositionsOwnedByPlayer:(int)pnum {
NSEnumerator *pe = [[self grid] positionEnumerator];
id pos;
int total = 0;
while (pos=[pe nextObject]) {
if (pnum==[self ownerOfPosition:pos]) ++total;
}
return total;
}
-(BOOL)isAnyPositionOwnedByPlayer:(int)pnum {
NSEnumerator *pe = [[self grid] positionEnumerator];
id pos;
while (pos=[pe nextObject]) {
if (pnum==[self ownerOfPosition:pos]) return YES;
}
return NO;
}
-(int)maxStablePiecesForRow:(int)r column:(int)c {
BOOL endrow = (r==0 || r==[self numberOfRows]-1);
BOOL endcol = (c==0 || c==[self numberOfColumns]-1);
if (endrow && endcol) return 1;
if (endrow || endcol) return 2;
return 3;
}
-(int)maxStablePiecesForPosition:(DCHypergridPosition *)pos {
return [self maxStablePiecesForRow:[pos row] column:[pos column]];
}
-(int)cellValueDelta {
return ([self currentPlayerNumber]==1) ? 1 : -1;
}
-(void)removePieceFromGrid:(DCHypergrid *)theGrid atRow:(int)r column:(int)c {
[theGrid setValue:[theGrid valueAtRow:r column:c]-[self cellValueDelta] atRow:r column:c];
}
-(void)addCapturingPieceToGrid:(DCHypergrid *)theGrid atRow:(int)r column:(int)c {
[theGrid setValue:[self cellValueDelta]*(1+abs([theGrid valueAtRow:r column:c])) atRow:r column:c];
}
// returns YES if following the explostion there are more unstable positions *and* cells are owned by both players
-(BOOL)performExplosionIterationInGrid:(DCHypergrid *)theGrid
fromPositions:(NSArray *)positions
nextUnstablePositions:(NSMutableArray *)nextUnstablePositions {
// this method may be performance-sensitive, avoiding object allocations
int i;
int maxr = [self numberOfRows];
int maxc = [self numberOfColumns];
for(i=0; i<[positions count]; i++) {
id pos = [positions objectAtIndex:i];
int r = [pos row];
int c = [pos column];
// distribute pieces to orthogonal adjacent positions
if (r>0) {
[self removePieceFromGrid:theGrid atRow:r column:c];
[self addCapturingPieceToGrid:theGrid atRow:r-1 column:c];
}
if (r<maxr-1) {
[self removePieceFromGrid:theGrid atRow:r column:c];
[self addCapturingPieceToGrid:theGrid atRow:r+1 column:c];
}
if (c>0) {
[self removePieceFromGrid:theGrid atRow:r column:c];
[self addCapturingPieceToGrid:theGrid atRow:r column:c-1];
}
if (c<maxc-1) {
[self removePieceFromGrid:theGrid atRow:r column:c];
[self addCapturingPieceToGrid:theGrid atRow:r column:c+1];
}
}
// now check for new ustable positions, and determine if both players still own cells
{
int r, c;
BOOL hasP1 = NO;
BOOL hasP2 = NO;
[nextUnstablePositions removeAllObjects];
for(r=0; r<maxr; r++) {
for(c=0; c<maxc; c++) {
int value = [theGrid valueAtRow:r column:c];
int owner = (value==0) ? 0 : ((value>0) ? 1 : 2);
if (owner==1) hasP1 = YES;
if (owner==2) hasP2 = YES;
if (abs(value)>[self maxStablePiecesForRow:r column:c]) {
[nextUnstablePositions addObject:[DCHypergridPosition positionWithRow:r column:c]];
}
}
}
return ([nextUnstablePositions count]>0 && hasP1 && hasP2);
}
}
-(BOOL)prepareMoveSequence:(NSArray *)move {
id pos = [move lastObject];
[self resetFutureGrid];
[self addCapturingPieceToGrid:[self futureGrid] atRow:[pos row] column:[pos column]];
if (abs([self valueAtPosition:pos])>=[self maxStablePiecesForPosition:pos]) {
// move causes an explosion, compute resulting grid
NSMutableArray *explodingPositions = [NSMutableArray arrayWithObject:pos];
BOOL stillGoing = YES;
// repeat until explosions stop or opponent is dead
while (stillGoing) {
stillGoing = [self performExplosionIterationInGrid:[self futureGrid]
fromPositions:explodingPositions
nextUnstablePositions:explodingPositions];
}
}
return YES;
}
-(NSArray *)allValidMoveSequences {
NSMutableArray *moves = [NSMutableArray array];
int pnum = [self currentPlayerNumber];
NSEnumerator *pe = [[self grid] positionEnumerator];
id pos;
while (pos=[pe nextObject]) {
int owner = [self ownerOfPosition:pos];
if (owner==0 || owner==pnum) {
[moves addObject:[pos arrayWithSelf_]];
}
}
return moves;
}
-(BOOL)isGameOver {
return ([self moveCount]>2 && !([self isAnyPositionOwnedByPlayer:1] && [self isAnyPositionOwnedByPlayer:2]));
}
-(int)winningPlayer {
if ([self isAnyPositionOwnedByPlayer:1]) return 1;
return 2;
}
@end
|