Skip to content

Commit

Permalink
Added game play methods and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Ly committed Sep 3, 2012
1 parent 988568e commit 7867409
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 4 deletions.
13 changes: 13 additions & 0 deletions ConnectFour/Models/Board.m
Expand Up @@ -111,4 +111,17 @@ - (NSArray*) indices {
return _indices;
}

- (NSString*) description {
NSMutableString *str = [NSMutableString stringWithCapacity: 250];
for(int r = 0; r < size.height; r ++) {
for(int c = 0; c < size.width; c ++) {
NSUInteger i = r * size.width + c;
Marker *m = [contents objectAtIndex: i];
[str appendString: m.text];
}
[str appendString: @"\n"];
}
return str;
}

@end
5 changes: 4 additions & 1 deletion ConnectFour/Models/Game.h
Expand Up @@ -21,8 +21,11 @@

@property (nonatomic, strong) Board *board;
@property (nonatomic, strong) NSArray *directions;
@property (nonatomic, strong) Marker *activeMarker;

- (void) move: (Move*) _move;
- (BOOL) move: (Move*) _move;
- (Marker*) markerAtIndex: (JLIndex*) index;
- (int) lowestEmptyRowForColumn: (NSUInteger) col;
- (BOOL) isWin;

@end
51 changes: 48 additions & 3 deletions ConnectFour/Models/Game.m
Expand Up @@ -15,14 +15,17 @@
#import "Marker.h"

@interface Game()
-(int) lowestEmptyRowForColumn: (NSUInteger) col;
-(void) toggleActiveMarker;
-(BOOL) checkIndex:(JLIndex*) index hasMarker: (Marker*) marker
inDirection: (Direction*) direction withSteps: (NSUInteger) steps;
-(BOOL) isWinAtIndex: (JLIndex*) index;
@end

@implementation Game

@synthesize board;
@synthesize directions;
@synthesize activeMarker;

- (Game*) init {
self = [super init];
Expand All @@ -43,17 +46,19 @@ - (Game*) init {
return self;
}

- (void) move: (Move*) _move {
- (BOOL) move: (Move*) _move {
int r = [self lowestEmptyRowForColumn: _move.column];

if(r < 0) {
NSLog(@"Warning, invalid move %@", _move);
return; // @todo, throw exception?
return NO; // @todo, throw exception?
}

JLIndex *moveIndex = [JLIndex indexWithRow:r andColumn:_move.column];
[board moveWithMarker: activeMarker atIndex: moveIndex];
[self toggleActiveMarker];

return YES;
}

-(int) lowestEmptyRowForColumn: (NSUInteger) col {
Expand All @@ -71,4 +76,44 @@ - (Marker*) markerAtIndex: (JLIndex*) index {
-(void) toggleActiveMarker {
activeMarker = activeMarker == Marker.A ? Marker.B : Marker.A;
}

-(BOOL) checkIndex:(JLIndex*) index hasMarker: (Marker*) marker
inDirection: (Direction*) direction withSteps: (NSUInteger) steps {
if(steps == 0) return YES;
else if([board isInBounds: index]
&& [board positionAt:index hasMarker:marker]) {
JLIndex *newIndex =
[JLIndex indexWithRow: index.row + direction.vertical
andColumn: index.column + direction.horizontal];
return [self checkIndex: newIndex hasMarker:marker
inDirection:direction withSteps:steps-1];
}
else return NO;
}
-(BOOL) isWinAtIndex: (JLIndex*) index {
if(! [board isInBounds: index]) return NO;

Marker *m = [board markerAtIndex: index];
if(m == Marker.Empty) return NO;

BOOL __block _isWin = NO;
[directions enumerateObjectsUsingBlock:^(Direction *dir, NSUInteger idx, BOOL *stop) {
if([self checkIndex: index hasMarker: m inDirection: dir withSteps:4]) {
_isWin = YES;
(*stop) = YES;
}
}];

return _isWin;
}
- (BOOL) isWin {
BOOL __block _isWin = FALSE;
[[board indices] enumerateObjectsUsingBlock:^(JLIndex *index, NSUInteger idx, BOOL *stop) {
if([self isWinAtIndex: index]) {
_isWin = YES;
(*stop) = YES;
}
}];
return _isWin;
}
@end
57 changes: 57 additions & 0 deletions ConnectFourTests/GamePlayTests.m
Expand Up @@ -36,4 +36,61 @@ - (void) testShouldHappenInMovesByChoosingSecondColumn {
STAssertEquals(Marker.B, [game markerAtIndex: index], @"Marker is at correct index");
}

- (void) testShouldStartWithMarkerA {
STAssertEquals(Marker.A, game.activeMarker, @"Starts with Marker A");
}

- (void) testShouldAlternateBetweenTwoMarkers {
[game move: [Move moveWithColumn: 1]];
STAssertEquals(Marker.B, game.activeMarker, @"Markers are equal");
}

- (void) testShouldDetectVerticalMatch {
Move *moveA = [Move moveWithColumn: 1];
Move *moveB = [Move moveWithColumn: 2];
for(int i=0; i<3; i++) {
STAssertTrue([game move: moveA], @"Move A");
STAssertTrue([game move: moveB], @"Move B");
}
STAssertFalse([game isWin], @"No winner yet");
[game move: moveA];
STAssertTrue([game isWin], @"Someone has won");

}

- (void) testShouldNotAllowMoveInFullColumn {
Move *move = [Move moveWithColumn: 1];
STAssertTrue([game move: move], @"Move Okay");
STAssertTrue([game move: move], @"Move Okay");
STAssertTrue([game move: move], @"Move Okay");
STAssertTrue([game move: move], @"Move Okay");
STAssertTrue([game move: move], @"Move Okay");
STAssertTrue([game move: move], @"Move Okay");
STAssertFalse([game move: move], @"Move NOT Okay");
}

- (void) testShouldDetermineFirstEmptyRowInColumn {
Move *move = [Move moveWithColumn: 1];

STAssertEquals(5, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(4, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(3, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(2, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(1, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(0, [game lowestEmptyRowForColumn: 1], @"Lowest column");
[game move: move];

STAssertEquals(-1, [game lowestEmptyRowForColumn: 1], @"Lowest column");
}

@end

0 comments on commit 7867409

Please sign in to comment.