1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Source/GoGame.m Fri Mar 07 11:43:02 2008 -0800
1.3 @@ -0,0 +1,166 @@
1.4 +/* This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
1.5 + http://developer.apple.com/samplecode/GeekGameBoard/
1.6 + Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
1.7 +
1.8 + Redistribution and use in source and binary forms, with or without modification, are permitted
1.9 + provided that the following conditions are met:
1.10 +
1.11 + * Redistributions of source code must retain the above copyright notice, this list of conditions
1.12 + and the following disclaimer.
1.13 + * Redistributions in binary form must reproduce the above copyright notice, this list of
1.14 + conditions and the following disclaimer in the documentation and/or other materials provided
1.15 + with the distribution.
1.16 +
1.17 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
1.18 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1.19 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
1.20 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1.21 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1.22 + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1.23 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
1.24 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.25 +*/
1.26 +#import "GoGame.h"
1.27 +#import "Grid.h"
1.28 +#import "Piece.h"
1.29 +#import "Dispenser.h"
1.30 +#import "Stack.h"
1.31 +#import "QuartzUtils.h"
1.32 +
1.33 +
1.34 +@implementation GoGame
1.35 +
1.36 +
1.37 +- (void) x_createDispenser: (NSString*)imageName position: (CGPoint)position forPlayer: (unsigned)playerNo
1.38 +{
1.39 + CGFloat pieceSize = (int)(_grid.spacing.width * 0.9) & ~1; // make sure it's even
1.40 + Piece *stone = [[Piece alloc] initWithImageNamed: imageName scale: pieceSize];
1.41 + stone.owner = [self.players objectAtIndex: playerNo];
1.42 + CGRect frame = {position, {1.5*pieceSize,1.5*pieceSize}};
1.43 + Dispenser *disp = [[Dispenser alloc] initWithPrototype: stone quantity: INT_MAX frame:frame];
1.44 + [_board addSublayer: disp];
1.45 + [disp release];
1.46 + [stone release];
1.47 +}
1.48 +
1.49 +
1.50 +- (id) initWithBoard: (CALayer*)board
1.51 +{
1.52 + self = [super initWithBoard: board];
1.53 + if (self != nil) {
1.54 + [self setNumberOfPlayers: 2];
1.55 +
1.56 + CGSize size = board.bounds.size;
1.57 + RectGrid *grid = [[RectGrid alloc] initWithRows: 9 columns: 9
1.58 + frame: CGRectMake((size.width-size.height+16)/2,8,
1.59 + size.height-16,size.height-16)];
1.60 + _grid = grid;
1.61 + grid.backgroundColor = GetCGPatternNamed(@"Wood.jpg");
1.62 + grid.borderColor = kTranslucentLightGrayColor;
1.63 + grid.borderWidth = 2;
1.64 + grid.lineColor = kTranslucentGrayColor;
1.65 + grid.cellClass = [GoSquare class];
1.66 + [grid addAllCells];
1.67 + ((GoSquare*)[grid cellAtRow: 2 column: 2]).dotted = YES;
1.68 + ((GoSquare*)[grid cellAtRow: 6 column: 6]).dotted = YES;
1.69 + ((GoSquare*)[grid cellAtRow: 2 column: 6]).dotted = YES;
1.70 + ((GoSquare*)[grid cellAtRow: 6 column: 2]).dotted = YES;
1.71 + grid.usesDiagonals = grid.allowsMoves = grid.allowsCaptures = NO;
1.72 + [board addSublayer: grid];
1.73 + [grid release];
1.74 +
1.75 + CGRect gridFrame = grid.frame;
1.76 + CGFloat pieceSize = (int)grid.spacing.width & ~1; // make sure it's even
1.77 + [self x_createDispenser: @"Red Ball.png"
1.78 + position: CGPointMake(CGRectGetMinX(gridFrame)-2*pieceSize,
1.79 + CGRectGetMinY(gridFrame))
1.80 + forPlayer: 0];
1.81 + [self x_createDispenser: @"White Ball.png"
1.82 + position: CGPointMake(CGRectGetMaxX(gridFrame)+0.5*pieceSize,
1.83 + CGRectGetMaxY(gridFrame)-1.5*pieceSize)
1.84 + forPlayer: 1];
1.85 +
1.86 + CGFloat captureHeight = gridFrame.size.height-4*pieceSize;
1.87 + _captured[0] = [[Stack alloc] initWithStartPos: CGPointMake(2*pieceSize,0)
1.88 + spacing: CGSizeMake(0,pieceSize)
1.89 + wrapInterval: floor(captureHeight/pieceSize)
1.90 + wrapSpacing: CGSizeMake(-pieceSize,0)];
1.91 + _captured[0].frame = CGRectMake(CGRectGetMinX(gridFrame)-3*pieceSize,
1.92 + CGRectGetMinY(gridFrame)+3*pieceSize,
1.93 + 2*pieceSize, captureHeight);
1.94 + _captured[0].zPosition = kPieceZ+1;
1.95 + [board addSublayer: _captured[0]];
1.96 + [_captured[0] release];
1.97 +
1.98 + _captured[1] = [[Stack alloc] initWithStartPos: CGPointMake(0,captureHeight)
1.99 + spacing: CGSizeMake(0,-pieceSize)
1.100 + wrapInterval: floor(captureHeight/pieceSize)
1.101 + wrapSpacing: CGSizeMake(pieceSize,0)];
1.102 + _captured[1].frame = CGRectMake(CGRectGetMaxX(gridFrame)+pieceSize,
1.103 + CGRectGetMinY(gridFrame)+pieceSize,
1.104 + 2*pieceSize, captureHeight);
1.105 + _captured[1].zPosition = kPieceZ+1;
1.106 + [board addSublayer: _captured[1]];
1.107 + [_captured[1] release];
1.108 +
1.109 + [self nextPlayer];
1.110 +}
1.111 + return self;
1.112 +}
1.113 +
1.114 +
1.115 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
1.116 +{
1.117 + Square *dst=(Square*)dstHolder;
1.118 +
1.119 + // There should be a check here for a "ko" (repeated position) ... exercise for the reader!
1.120 +
1.121 + // Check for suicidal move. First an easy check for an empty adjacent space:
1.122 + NSArray *neighbors = dst.neighbors;
1.123 + for( GridCell *c in neighbors )
1.124 + if( c.empty )
1.125 + return YES; // there's an empty space
1.126 + // If the piece is surrounded, check the neighboring groups' liberties:
1.127 + for( GridCell *c in neighbors ) {
1.128 + int nLiberties;
1.129 + [c getGroup: &nLiberties];
1.130 + if( c.bit.unfriendly ) {
1.131 + if( nLiberties <= 1 )
1.132 + return YES; // the move captures, so it's not suicidal
1.133 + } else {
1.134 + if( nLiberties > 1 )
1.135 + return YES; // the stone joins a group with other liberties
1.136 + }
1.137 + }
1.138 + return NO;
1.139 +}
1.140 +
1.141 +
1.142 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
1.143 +{
1.144 + Square *dst=(Square*)dstHolder;
1.145 + int curIndex = _currentPlayer.index;
1.146 + // Check for captured enemy groups:
1.147 + BOOL captured = NO;
1.148 + for( GridCell *c in dst.neighbors )
1.149 + if( c.bit.unfriendly ) {
1.150 + int nLiberties;
1.151 + NSSet *group = [c getGroup: &nLiberties];
1.152 + if( nLiberties == 0 ) {
1.153 + captured = YES;
1.154 + for( GridCell *capture in group )
1.155 + [_captured[curIndex] addBit: capture.bit]; // Moves piece to POW camp!
1.156 + }
1.157 + }
1.158 + if( captured )
1.159 + [[NSSound soundNamed: @"Pop"] play];
1.160 +
1.161 + [self nextPlayer];
1.162 +}
1.163 +
1.164 +
1.165 +// This sample code makes no attempt to detect the end of the game, or count score,
1.166 +// both of which are rather complex to decide in Go.
1.167 +
1.168 +
1.169 +@end