1 /* This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
2 http://developer.apple.com/samplecode/GeekGameBoard/
3 Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
5 Redistribution and use in source and binary forms, with or without modification, are permitted
6 provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice, this list of conditions
9 and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of
11 conditions and the following disclaimer in the documentation and/or other materials provided
12 with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
15 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
17 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
21 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 #import "CheckersGame.h"
26 #import "QuartzUtils.h"
30 @implementation CheckersGame
33 static NSMutableDictionary *kPieceStyle1, *kPieceStyle2;
37 if( self == [CheckersGame class] ) {
38 kPieceStyle1 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
39 (id)GetCGImageNamed(@"Green.png"), @"contents",
40 kCAGravityResizeAspect, @"contentsGravity",
41 kCAFilterLinear, @"minificationFilter",
43 kPieceStyle2 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
44 (id)GetCGImageNamed(@"Red.png"), @"contents",
45 kCAGravityResizeAspect, @"contentsGravity",
46 kCAFilterLinear, @"minificationFilter",
56 _cells = [[NSMutableArray alloc] init];
57 [self setNumberOfPlayers: 2];
59 PreloadSound(@"Tink");
60 PreloadSound(@"Funk");
61 PreloadSound(@"Blow");
67 - (CGImageRef) iconForPlayer: (int)playerNum
69 return GetCGImageNamed( playerNum==0 ?@"Green.png" :@"Red.png" );
72 - (Piece*) pieceForPlayer: (int)playerNum
74 Piece *p = [[Piece alloc] init];
75 p.bounds = CGRectMake(0,0,floor(_grid.spacing.width),floor(_grid.spacing.height));
76 p.style = (playerNum ?kPieceStyle2 :kPieceStyle1);
77 p.owner = [self.players objectAtIndex: playerNum];
78 p.name = playerNum ?@"2" :@"1";
79 return [p autorelease];
82 - (void) makeKing: (Piece*)piece
85 [piece setValue: @"King" forKey: @"King"];
86 piece.name = piece.owner.index ?@"4" :@"3";
91 RectGrid *grid = [[RectGrid alloc] initWithRows: 8 columns: 8 frame: _board.bounds];
93 [_board addSublayer: _grid];
94 CGPoint pos = _grid.position;
95 pos.x = floor((_board.bounds.size.width-grid.frame.size.width)/2);
97 grid.allowsMoves = YES;
98 grid.allowsCaptures = NO;
99 grid.cellColor = CreateGray(0.0, 0.25);
100 grid.altCellColor = CreateGray(1.0, 0.25);
101 grid.lineColor = nil;
104 [_cells removeAllObjects];
105 for( int i=0; i<32; i++ ) {
107 [_cells addObject: [_grid cellAtRow: row column: 2*(i%4) + (row&1)]];
119 - (NSString*) initialStateString
121 return @"111111111111--------222222222222";
124 - (NSString*) stateString
126 unichar state[_cells.count];
128 for( GridCell *cell in _cells ) {
129 NSString *ident = cell.bit.name;
131 state[i++] = [ident characterAtIndex: 0];
135 return [NSString stringWithCharacters: state length: i];
138 - (void) setStateString: (NSString*)state
140 _numPieces[0] = _numPieces[1] = 0;
142 for( GridCell *cell in _cells ) {
144 int which = [state characterAtIndex: i++] - '1';
145 if( which >=0 && which < 4 ) {
146 int player = (which & 1);
147 piece = [self pieceForPlayer: player];
148 _numPieces[player]++;
150 [self makeKing: piece];
158 - (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
160 Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
161 if( [bit valueForKey: @"King"] )
162 if( dst==src.bl || dst==src.br || dst==src.l || dst==src.r
163 || (src.bl.bit.unfriendly && dst==src.bl.bl) || (src.br.bit.unfriendly && dst==src.br.br) )
165 return dst==src.fl || dst==src.fr
166 || (src.fl.bit.unfriendly && dst==src.fl.fl) || (src.fr.bit.unfriendly && dst==src.fr.fr);
169 - (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
171 Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
172 int playerIndex = self.currentPlayer.index;
174 Turn *turn = self.currentTurn;
175 if( turn.move.length==0 )
176 [turn addToMove: src.name];
177 [turn addToMove: @"-"];
178 [turn addToMove: dst.name];
180 BOOL isKing = ([bit valueForKey: @"King"] != nil);
181 PlaySound(isKing ?@"Funk" :@"Tink");
183 // "King" a piece that made it to the last row:
184 if( dst.row == (playerIndex ?0 :7) )
187 [self makeKing: (Piece*)bit];
188 [turn addToMove: @"*"];
189 // don't set isKing flag - piece can't jump again after being kinged.
192 // Check for a capture:
193 Square *capture = nil;
196 else if(dst==src.fr.fr)
198 else if(dst==src.bl.bl)
200 else if(dst==src.br.br)
205 _numPieces[capture.bit.owner.index]--;
206 [capture destroyBit];
207 [turn addToMove: @"!"];
209 // Now check if another capture is possible. If so, don't end the turn:
210 if( (dst.fl.bit.unfriendly && dst.fl.fl.empty) || (dst.fr.bit.unfriendly && dst.fr.fr.empty) )
213 if( (dst.bl.bit.unfriendly && dst.bl.bl.empty) || (dst.br.bit.unfriendly && dst.br.br.empty) )
220 - (Player*) checkForWinner
222 // Whoever runs out of pieces loses:
223 if( _numPieces[0]==0 )
224 return [self.players objectAtIndex: 1];
225 else if( _numPieces[1]==0 )
226 return [self.players objectAtIndex: 0];
232 - (BOOL) applyMoveString: (NSString*)move
235 for( NSString *ident in [move componentsSeparatedByString: @"-"] ) {
236 while( [ident hasSuffix: @"!"] || [ident hasSuffix: @"*"] )
237 ident = [ident substringToIndex: ident.length-1];
238 GridCell *dst = [_grid cellWithName: ident];
241 if( src && ! [self animateMoveFrom: src to: dst] )