Source/CheckersGame.m
author Jens Alfke <jens@mooseyard.com>
Wed May 28 12:47:10 2008 -0700 (2008-05-28)
changeset 8 45c82a071aca
parent 1 3eb7be1dd7b6
child 9 a59acc683080
permissions -rw-r--r--
* Got it working with latest iPhone SDK.
* Fixed some text alignment issues that showed up on PlayingCards.
* Working on persistence and move-tracking for Game.
     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.
     4 
     5     Redistribution and use in source and binary forms, with or without modification, are permitted
     6     provided that the following conditions are met:
     7 
     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.
    13 
    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.
    22 */
    23 #import "CheckersGame.h"
    24 #import "Grid.h"
    25 #import "Piece.h"
    26 #import "QuartzUtils.h"
    27 #import "GGBUtils.h"
    28 
    29 
    30 @implementation CheckersGame
    31 
    32 
    33 - (Piece*) pieceForPlayer: (int)playerNum
    34 {
    35     Piece *p = [[Piece alloc] initWithImageNamed: (playerNum==0 ?@"Green Ball.png" :@"Red Ball.png") 
    36                                            scale: floor(_grid.spacing.width * 0.8)];
    37     p.owner = [self.players objectAtIndex: playerNum];
    38     p.name = playerNum ?@"2" :@"1";
    39     return [p autorelease];
    40 }
    41 
    42 - (Grid*) x_makeGrid
    43 {
    44     RectGrid *grid = [[[RectGrid alloc] initWithRows: 8 columns: 8 frame: _board.bounds] autorelease];
    45     _grid = grid;
    46     CGPoint pos = _grid.position;
    47     pos.x = floor((_board.bounds.size.width-grid.frame.size.width)/2);
    48     grid.position = pos;
    49     grid.allowsMoves = YES;
    50     grid.allowsCaptures = NO;
    51     grid.cellColor = CreateGray(0.0, 0.25);
    52     grid.altCellColor = CreateGray(1.0, 0.25);
    53     grid.lineColor = nil;
    54 
    55     [grid addAllCells];
    56     for( int i=0; i<32; i++ ) {
    57         int row = i/4;
    58         [_cells addObject: [_grid cellAtRow: row column: 2*(i%4) + (row&1)]];
    59     }
    60     self.stateString = @"111111111111--------222222222222";
    61     return grid;
    62 }
    63 
    64 
    65 - (id) initWithBoard: (GGBLayer*)board
    66 {
    67     self = [super initWithBoard: board];
    68     if (self != nil) {
    69         [self setNumberOfPlayers: 2];
    70         _cells = [[NSMutableArray alloc] init];
    71         [self x_makeGrid];
    72         [board addSublayer: _grid];
    73         [self nextPlayer];
    74         
    75         PreloadSound(@"Tink");
    76         PreloadSound(@"Funk");
    77         PreloadSound(@"Blow");
    78         PreloadSound(@"Pop");
    79     }
    80     return self;
    81 }
    82 
    83 - (void) dealloc
    84 {
    85     [_cells release];
    86     [_grid release];
    87     [super dealloc];
    88 }
    89 
    90 
    91 - (NSString*) stateString
    92 {
    93     unichar state[_cells.count];
    94     int i = 0;
    95     for( GridCell *cell in _cells ) {
    96         NSString *ident = cell.bit.name;
    97         if( ident )
    98             state[i++] = [ident characterAtIndex: 0];
    99         else
   100             state[i++] = '-';
   101     }
   102     return [NSString stringWithCharacters: state length: i];
   103 }
   104 
   105 - (void) setStateString: (NSString*)state
   106 {
   107     _numPieces[0] = _numPieces[1] = 0;
   108     int i = 0;
   109     for( GridCell *cell in _cells ) {
   110         Piece *piece;
   111         switch( [state characterAtIndex: i++] ) {
   112             case '1': piece = [self pieceForPlayer: 0]; _numPieces[0]++; break;
   113             case '2': piece = [self pieceForPlayer: 1]; _numPieces[1]++; break;
   114             default:  piece = nil; break;
   115         }
   116         cell.bit = piece;
   117     }    
   118 }
   119 
   120 
   121 - (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
   122 {
   123     Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
   124     if( [bit valueForKey: @"King"] )
   125         if( dst==src.bl || dst==src.br || dst==src.l || dst==src.r
   126            || (src.bl.bit.unfriendly && dst==src.bl.bl) || (src.br.bit.unfriendly && dst==src.br.br) )
   127             return YES;    
   128     return dst==src.fl || dst==src.fr
   129         || (src.fl.bit.unfriendly && dst==src.fl.fl) || (src.fr.bit.unfriendly && dst==src.fr.fr);
   130 }
   131 
   132 - (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
   133 {
   134     Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
   135     int playerIndex = self.currentPlayer.index;
   136     
   137     if( self.currentMove.length==0 )
   138         [self.currentMove appendString: src.name];
   139     [self.currentMove appendString: dst.name];
   140     
   141     BOOL isKing = ([bit valueForKey: @"King"] != nil);
   142     PlaySound(isKing ?@"Funk" :@"Tink");
   143 
   144     // "King" a piece that made it to the last row:
   145     if( dst.row == (playerIndex ?0 :7) )
   146         if( ! isKing ) {
   147             PlaySound(@"Blow");
   148             bit.scale = 1.4;
   149             [bit setValue: @"King" forKey: @"King"];
   150             // don't set isKing flag - piece can't jump again after being kinged.
   151         }
   152 
   153     // Check for a capture:
   154     Square *capture = nil;
   155     if(dst==src.fl.fl)
   156         capture = src.fl;
   157     else if(dst==src.fr.fr)
   158         capture = src.fr;
   159     else if(dst==src.bl.bl)
   160         capture = src.bl;
   161     else if(dst==src.br.br)
   162         capture = src.br;
   163     
   164     if( capture ) {
   165         PlaySound(@"Pop");
   166         Bit *bit = capture.bit;
   167         _numPieces[bit.owner.index]--;
   168         [bit destroy];
   169         
   170         // Now check if another capture is possible. If so, don't end the turn:
   171         if( (dst.fl.bit.unfriendly && dst.fl.fl.empty) || (dst.fr.bit.unfriendly && dst.fr.fr.empty) )
   172             return;
   173         if( isKing )
   174             if( (dst.bl.bit.unfriendly && dst.bl.bl.empty) || (dst.br.bit.unfriendly && dst.br.br.empty) )
   175                 return;
   176     }
   177     
   178     [self endTurn];
   179 }
   180 
   181 - (Player*) checkForWinner
   182 {
   183     // Whoever runs out of pieces loses:
   184     if( _numPieces[0]==0 )
   185         return [self.players objectAtIndex: 1];
   186     else if( _numPieces[1]==0 )
   187         return [self.players objectAtIndex: 0];
   188     else
   189         return nil;
   190 }
   191 
   192 
   193 - (BOOL) applyMoveString: (NSString*)move
   194 {
   195     int length = move.length;
   196     if( length<4 || (length&1) )
   197         return NO;
   198     GridCell *src = nil;
   199     for( int i=0; i<length; i+=2 ) {
   200         NSString *ident = [move substringWithRange: NSMakeRange(i,2)];
   201         GridCell *dst = [_grid cellWithName: ident];
   202         if( i > 0 )
   203             if( ! [self animateMoveFrom: src to: dst] )
   204                 return NO;
   205         src = dst;
   206     }
   207     return YES;
   208 }
   209 
   210 
   211 @end