Source/TicTacToeGame.m
author Jens Alfke <jens@mooseyard.com>
Wed May 28 12:47:10 2008 -0700 (2008-05-28)
changeset 8 45c82a071aca
parent 7 428a194e3e59
child 10 6c78cc6bd7a6
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 "TicTacToeGame.h"
    24 #import "Grid.h"
    25 #import "Dispenser.h"
    26 #import "Piece.h"
    27 #import "QuartzUtils.h"
    28 
    29 
    30 @implementation TicTacToeGame
    31 
    32 - (Piece*) pieceForPlayer: (int)playerNumber
    33 {
    34     Piece *p = [[Piece alloc] initWithImageNamed: (playerNumber ? @"O.tiff" :@"X.tiff")
    35                                            scale: 80];
    36     p.owner = [self.players objectAtIndex: playerNumber];
    37     p.name = (playerNumber ?@"O" :@"X");
    38     return [p autorelease];
    39 }
    40 
    41 - (id) initWithBoard: (GGBLayer*)board
    42 {
    43     self = [super initWithBoard: board];
    44     if (self != nil) {
    45         [self setNumberOfPlayers: 2];
    46         
    47         // Create a 3x3 grid:
    48         CGFloat center = floor(CGRectGetMidX(board.bounds));
    49         _grid = [[RectGrid alloc] initWithRows: 3 columns: 3 frame: CGRectMake(center-150,0, 300,300)];
    50         [_grid addAllCells];
    51         _grid.allowsMoves = _grid.allowsCaptures = NO;
    52         _grid.cellColor = CreateGray(1.0, 0.25);
    53         _grid.lineColor = kTranslucentLightGrayColor;
    54         [board addSublayer: _grid];
    55         
    56         // Create piece dispensers for the two players:
    57         for( int playerNumber=0; playerNumber<=1; playerNumber++ ) {
    58             Piece *p = [self pieceForPlayer: playerNumber];
    59             CGFloat x = floor(CGRectGetMidX(_board.bounds));
    60 #if TARGET_OS_IPHONE
    61             x = x - 80 + 160*playerNumber;
    62             CGFloat y = 360;
    63 #else
    64             x += (playerNumber==0 ?-230 :230);
    65             CGFloat y = 175;
    66 #endif
    67             _dispenser[playerNumber] = [[Dispenser alloc] initWithPrototype: p quantity: 0
    68                                                                       frame: CGRectMake(x-45,y-45, 90,90)];
    69             [_board addSublayer: _dispenser[playerNumber]];
    70         }            
    71         
    72         // And they're off!
    73         [self nextPlayer];
    74     }
    75     return self;
    76 }
    77 
    78 
    79 - (NSString*) stateString
    80 {
    81     unichar str[10];
    82     for( int i=0; i<9; i++ ) {
    83         NSString *ident = [_grid cellAtRow: i/3 column: i%3].bit.name;
    84         if( ident==nil )
    85             str[i] = '-';
    86         else 
    87             str[i] = [ident characterAtIndex: 0];
    88     }
    89     return [NSString stringWithCharacters: str length: 9];
    90 }
    91 
    92 - (void) setStateString: (NSString*)stateString
    93 {
    94     for( int i=0; i<9; i++ ) {
    95         Piece *piece;
    96         switch( [stateString characterAtIndex: i] ) {
    97             case 'X': case 'x': piece = [self pieceForPlayer: 0]; break;
    98             case 'O': case 'o': piece = [self pieceForPlayer: 1]; break;
    99             default:            piece = nil; break;
   100         }
   101         [_grid cellAtRow: i/3 column: i%3].bit = piece;
   102     }
   103 }
   104 
   105 
   106 - (Bit*) bitToPlaceInHolder: (id<BitHolder>)holder
   107 {
   108     if( holder.bit==nil && [holder isKindOfClass: [Square class]] )
   109         return _dispenser[self.currentPlayer.index].bit;
   110     else
   111         return nil;
   112 }
   113 
   114 
   115 - (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)src to: (id<BitHolder>)dst
   116 {
   117     Square *square = (Square*)dst;
   118     int squareIndex = 3*square.row + square.column;
   119     [self.currentMove appendFormat: @"%@%i", bit.name, squareIndex];
   120     [super bit: bit movedFrom: src to: dst];
   121 }
   122 
   123 - (void) nextPlayer
   124 {
   125     [super nextPlayer];
   126     // Give the next player another piece to put down:
   127     _dispenser[self.currentPlayer.index].quantity = 1;
   128 }
   129 
   130 static Player* ownerAt( Grid *grid, int index )
   131 {
   132     return [grid cellAtRow: index/3 column: index%3].bit.owner;
   133 }
   134 
   135 /** Should return the winning player, if the current position is a win. */
   136 - (Player*) checkForWinner
   137 {
   138     static const int kWinningTriples[8][3] =  { {0,1,2}, {3,4,5}, {6,7,8},  // rows
   139                                                 {0,3,6}, {1,4,7}, {2,5,8},  // cols
   140                                                 {0,4,8}, {2,4,6} };         // diagonals
   141     for( int i=0; i<8; i++ ) {
   142         const int *triple = kWinningTriples[i];
   143         Player *p = ownerAt(_grid,triple[0]);
   144         if( p && p == ownerAt(_grid,triple[1]) && p == ownerAt(_grid,triple[2]) )
   145             return p;
   146     }
   147     return nil;
   148 }
   149 
   150 @end