// // 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 (r0) { [self removePieceFromGrid:theGrid atRow:r column:c]; [self addCapturingPieceToGrid:theGrid atRow:r column:c-1]; } if (c0) ? 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