Minor compiler-compatibility fixes.
     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.
 
    26 #import "Game+Protected.h"
 
    28 #import "QuartzUtils.h"
 
    31 @interface GridCell ()
 
    32 - (void) setBitTransform: (CATransform3D)bitTransform;
 
    39 - (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
 
    40             spacing: (CGSize)spacing
 
    41            position: (CGPoint)pos
 
    43     NSParameterAssert(nRows>0 && nColumns>0);
 
    49         _cellClass = [GridCell class];
 
    50         self.lineColor = kBlackColor;
 
    53         _bitTransform = CATransform3DIdentity;
 
    55         self.bounds = CGRectMake(-1, -1, nColumns*spacing.width+2, nRows*spacing.height+2);
 
    57         self.anchorPoint = CGPointMake(0,0);
 
    58         self.zPosition = kBoardZ;
 
    59         self.needsDisplayOnBoundsChange = YES;
 
    61         unsigned n = nRows*nColumns;
 
    62         _cells = [[NSMutableArray alloc] initWithCapacity: n];
 
    63         id null = [NSNull null];
 
    65             [_cells addObject: null];
 
    67         [self setNeedsDisplay];
 
    73 - (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
 
    76     CGFloat spacing = floor(MIN( (frame.size.width -2)/(CGFloat)nColumns,
 
    77                                (frame.size.height-2)/(CGFloat)nRows) );
 
    78     CGSize size = CGSizeMake(nColumns*spacing+2, nRows*spacing+2);
 
    79     CGPoint position = frame.origin;
 
    80     position.x += round( (frame.size.width -size.width )/2.0 );
 
    81     position.y += round( (frame.size.height-size.height)/2.0 );
 
    83     return [self initWithRows: nRows columns: nColumns
 
    84                       spacing: CGSizeMake(spacing,spacing)
 
    91     CGColorRelease(_cellColor);
 
    92     CGColorRelease(_lineColor);
 
    98 static void setcolor( CGColorRef *var, CGColorRef color )
 
   100     if( color != *var ) {
 
   101         CGColorRelease(*var);
 
   102         *var = CGColorRetain(color);
 
   106 - (CGColorRef) cellColor                        {return _cellColor;}
 
   107 - (void) setCellColor: (CGColorRef)cellColor    {setcolor(&_cellColor,cellColor);}
 
   109 - (CGColorRef) lineColor                        {return _lineColor;}
 
   110 - (void) setLineColor: (CGColorRef)lineColor    {setcolor(&_lineColor,lineColor);}
 
   112 - (CGImageRef) backgroundImage                  {return _backgroundImage;}
 
   113 - (void) setBackgroundImage: (CGImageRef)image
 
   115     if( image != _backgroundImage ) {
 
   116         CGImageRelease(_backgroundImage);
 
   117         _backgroundImage = CGImageRetain(image);
 
   121 @synthesize cellClass=_cellClass, rows=_nRows, columns=_nColumns, spacing=_spacing, reversed=_reversed,
 
   122             usesDiagonals=_usesDiagonals, allowsMoves=_allowsMoves, allowsCaptures=_allowsCaptures,
 
   123             bitTransform=_bitTransform;
 
   127 #pragma mark GEOMETRY:
 
   130 - (GridCell*) cellAtRow: (unsigned)row column: (unsigned)col
 
   132     if( row < _nRows && col < _nColumns ) {
 
   133         id cell = [_cells objectAtIndex: row*_nColumns+col];
 
   134         if( cell != [NSNull null] )
 
   141 /** Subclasses can override this, to change the cell's class or frame. */
 
   142 - (GridCell*) createCellAtRow: (unsigned)row column: (unsigned)col 
 
   143                suggestedFrame: (CGRect)frame
 
   145     GridCell *cell = [[_cellClass alloc] initWithGrid: self 
 
   148     cell.name = [NSString stringWithFormat: @"%c%u", ('A'+row),(1+col)];
 
   149     return [cell autorelease];
 
   153 - (GridCell*) addCellAtRow: (unsigned)row column: (unsigned)col
 
   155     NSParameterAssert(row<_nRows);
 
   156     NSParameterAssert(col<_nColumns);
 
   157     unsigned index = row*_nColumns+col;
 
   158     GridCell *cell = [_cells objectAtIndex: index];
 
   159     if( (id)cell == [NSNull null] ) {
 
   160         unsigned effectiveRow=row, effectiveCol=col;
 
   162             effectiveRow = _nRows-1    - effectiveRow;
 
   163             effectiveCol = _nColumns-1 - effectiveCol;
 
   165         CGRect frame = CGRectMake(effectiveCol*_spacing.width, effectiveRow*_spacing.height,
 
   166                                   _spacing.width,_spacing.height);
 
   167         cell = [self createCellAtRow: row column: col suggestedFrame: frame];
 
   169             [_cells replaceObjectAtIndex: index withObject: cell];
 
   171                 [self addSublayer: cell];
 
   173                 [self insertSublayer: cell atIndex: 0];
 
   174             [self setNeedsDisplay];
 
   183     for( int row=0; row<_nRows; row++ )
 
   184         for( int col=0; col<_nColumns; col++ ) 
 
   185             [self addCellAtRow: row column: col];
 
   189 - (void) removeCellAtRow: (unsigned)row column: (unsigned)col
 
   191     NSParameterAssert(row<_nRows);
 
   192     NSParameterAssert(col<_nColumns);
 
   193     unsigned index = row*_nColumns+col;
 
   194     id cell = [_cells objectAtIndex: index];
 
   195     if( cell != [NSNull null] )
 
   196         [cell removeFromSuperlayer];
 
   197     [_cells replaceObjectAtIndex: index withObject: [NSNull null]];
 
   198     [self setNeedsDisplay];
 
   204     NSMutableArray *cells = [[_cells mutableCopy] autorelease];
 
   205     for( int i=cells.count-1; i>=0; i-- )
 
   206         if( [cells objectAtIndex: i] == [NSNull null] )
 
   207             [cells removeObjectAtIndex: i];
 
   212 - (GridCell*) cellWithName: (NSString*)name
 
   214     for( CALayer *layer in self.sublayers )
 
   215         if( [layer isKindOfClass: [GridCell class]] )
 
   216             if( [name isEqualToString: ((GridCell*)layer).name] )
 
   217                 return (GridCell*)layer;
 
   222 - (NSCountedSet*) countPiecesByPlayer
 
   224     NSCountedSet *players = [NSCountedSet set];
 
   225     for( GridCell *cell in self.cells ) {
 
   226         Player *owner = cell.bit.owner;
 
   228             [players addObject: owner];
 
   234 - (CATransform3D) bitTransform
 
   236     return _bitTransform;
 
   239 - (void) setBitTransform: (CATransform3D)t
 
   242     for( GridCell *cell in self.cells )
 
   243         [cell setBitTransform: t];
 
   246 - (void) updateCellTransform
 
   248     CATransform3D t = self.aggregateTransform;
 
   249     t.m41 = t.m42 = t.m43 = 0.0f;           // remove translation component
 
   250     t = CATransform3DInvert(t);
 
   251     self.bitTransform = t;
 
   256 #pragma mark GAME STATE:
 
   259 - (NSString*) stateString
 
   261     NSMutableString *state = [NSMutableString stringWithCapacity: _cells.count];
 
   262     for( GridCell *cell in self.cells ) {
 
   264         NSString *name = bit ?bit.name :@"-";
 
   265         NSAssert(name.length==1,@"Missing or multicharacter name");
 
   266         [state appendString: name];
 
   271 - (void) setStateString: (NSString*)state
 
   273     Game *game = self.game;
 
   275     for( GridCell *cell in self.cells )
 
   276         cell.bit = [game makePieceNamed: [state substringWithRange: NSMakeRange(i++,1)]];
 
   280 - (BOOL) applyMoveString: (NSString*)move
 
   283     for( NSString *ident in [move componentsSeparatedByString: @"-"] ) {
 
   284         while( [ident hasSuffix: @"!"] || [ident hasSuffix: @"*"] )
 
   285             ident = [ident substringToIndex: ident.length-1];
 
   286         GridCell *dst = [self cellWithName: ident];
 
   289         if( src && ! [self.game animateMoveFrom: src to: dst] )
 
   298 #pragma mark DRAWING:
 
   301 - (void) drawCellsInContext: (CGContextRef)ctx fill: (BOOL)fill
 
   303     // Subroutine of -drawInContext:. Draws all the cells, with or without a fill.
 
   304     for( unsigned row=0; row<_nRows; row++ )
 
   305         for( unsigned col=0; col<_nColumns; col++ ) {
 
   306             GridCell *cell = [self cellAtRow: row column: col];
 
   308                 [cell drawInParentContext: ctx fill: fill];
 
   312 - (void) drawBackgroundInContext: (CGContextRef)ctx
 
   314     if( _backgroundImage ) {
 
   315         CGRect bounds = self.bounds;
 
   317             CGContextSaveGState(ctx);
 
   318             CGContextRotateCTM(ctx, M_PI);
 
   319             CGContextTranslateCTM(ctx, -bounds.size.width, -bounds.size.height);
 
   321         CGContextDrawImage(ctx, bounds, _backgroundImage);
 
   323             CGContextRestoreGState(ctx);
 
   328 - (void)drawInContext:(CGContextRef)ctx
 
   330     // Custom CALayer drawing implementation. Delegates to the cells to draw themselves
 
   331     // in me; this is more efficient than having each cell have its own drawing.
 
   332     [super drawInContext: ctx];
 
   334     [self drawBackgroundInContext: ctx];
 
   337         CGContextSetFillColorWithColor(ctx, _cellColor);
 
   338         [self drawCellsInContext: ctx fill: YES];
 
   341         CGContextSetStrokeColorWithColor(ctx,_lineColor);
 
   342         [self drawCellsInContext:ctx fill: NO];
 
   353 @implementation GridCell
 
   356 - (id) initWithGrid: (Grid*)grid 
 
   357                 row: (unsigned)row column: (unsigned)col
 
   365         self.anchorPoint = CGPointMake(0,0);
 
   366         self.position = frame.origin;
 
   367         CGRect bounds = frame;
 
   368         bounds.origin.x -= floor(bounds.origin.x);  // make sure my coords fall on pixel boundaries
 
   369         bounds.origin.y -= floor(bounds.origin.y);
 
   370         self.bounds = bounds;
 
   371         self.borderColor = kHighlightColor;         // Used when highlighting (see -setHighlighted:)
 
   372         [self setBitTransform: grid.bitTransform];
 
   377 - (NSString*) description
 
   379     return [NSString stringWithFormat: @"%@(%u,%u)", [self class],_column,_row];
 
   382 @synthesize grid=_grid, row=_row, column=_column;
 
   385 - (void) setBitTransform: (CATransform3D)bitTransform
 
   387     // To make the bitTransform relative to my center, I need to offset the center to the origin
 
   388     // first, and then back afterwards.
 
   389     CGSize size = self.bounds.size;
 
   390     size.width = roundf(size.width/2.0);
 
   391     size.height = roundf(size.height/2.0);
 
   392     CATransform3D x = CATransform3DMakeTranslation(-size.width, -size.height, 0);
 
   393     x = CATransform3DConcat(x, bitTransform);
 
   394     x = CATransform3DConcat(x, CATransform3DMakeTranslation(size.width, size.height ,0));
 
   395     self.sublayerTransform = x;    
 
   399 - (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
 
   401     // Default implementation just fills or outlines the cell.
 
   402     CGRect frame = self.frame;
 
   404         CGContextFillRect(ctx,frame);
 
   406         CGContextStrokeRect(ctx, frame);
 
   410 - (void) setBit: (Bit*)bit
 
   412     if( bit != self.bit ) {
 
   415             bit.position = GetCGRectCenter(self.bounds);
 
   419 - (Bit*) canDragBit: (Bit*)bit
 
   421     if( _grid.allowsMoves && bit==self.bit )
 
   422         return [super canDragBit: bit];
 
   427 - (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
 
   429     return self.bit == nil || _grid.allowsCaptures;
 
   435     return self.game.currentPlayer.index == 0;
 
   439 - (NSArray*) neighbors
 
   441     BOOL orthogonal = ! _grid.usesDiagonals;
 
   442     NSMutableArray *neighbors = [NSMutableArray arrayWithCapacity: 8];
 
   443     for( int dy=-1; dy<=1; dy++ )
 
   444         for( int dx=-1; dx<=1; dx++ )
 
   445             if( (dx || dy) && !(orthogonal && dx && dy) ) {
 
   446                 GridCell *cell = [_grid cellAtRow: _row+dy column: _column+dx];
 
   448                     [neighbors addObject: cell];
 
   454 // Recursive subroutine used by getGroup:.
 
   455 - (void) x_addToGroup: (NSMutableSet*)group liberties: (NSMutableSet*)liberties owner: (Player*)owner
 
   459         if( [liberties containsObject: self] )
 
   460             return; // already traversed
 
   461         [liberties addObject: self];
 
   462     } else if( bit.owner==owner ) {
 
   463         if( [group containsObject: self] )
 
   464             return; // already traversed
 
   465         [group addObject: self];
 
   466         for( GridCell *c in self.neighbors )
 
   467             [c x_addToGroup: group liberties: liberties owner: owner];
 
   472 - (NSSet*) getGroup: (int*)outLiberties
 
   474     NSMutableSet *group=[NSMutableSet set], *liberties=nil;
 
   476         liberties = [NSMutableSet set];
 
   477     [self x_addToGroup: group liberties: liberties owner: self.bit.owner];
 
   479         *outLiberties = liberties.count;
 
   485 #pragma mark DRAG-AND-DROP:
 
   488 #if ! TARGET_OS_IPHONE
 
   490 // An image from another app can be dragged onto a Grid to change its background pattern.
 
   492 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 
   494     if( CanGetCGImageFromPasteboard([sender draggingPasteboard]) )
 
   495         return NSDragOperationCopy;
 
   497         return NSDragOperationNone;
 
   500 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 
   502     CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
 
   504         CGColorRef pattern = CreatePatternColor(image);
 
   505         _grid.cellColor = pattern;
 
   506         CGColorRelease(pattern);
 
   507         [_grid setNeedsDisplay];
 
   522 @implementation RectGrid
 
   525 - (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
 
   526             spacing: (CGSize)spacing
 
   527            position: (CGPoint)pos
 
   529     self = [super initWithRows: nRows columns: nColumns spacing: spacing position: pos];
 
   531         _cellClass = [Square class];
 
   537 - (CGColorRef) altCellColor                         {return _altCellColor;}
 
   538 - (void) setAltCellColor: (CGColorRef)altCellColor  {setcolor(&_altCellColor,altCellColor);}
 
   547 @implementation Square
 
   550 - (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
 
   553         CGColorRef c = ((RectGrid*)_grid).altCellColor;
 
   555             if( ! ((_row+_column) & 1) )
 
   557             CGContextSetFillColorWithColor(ctx, c);
 
   560     [super drawInParentContext: ctx fill: fill];
 
   564 - (void) setHighlighted: (BOOL)highlighted
 
   566     [super setHighlighted: highlighted];
 
   567     self.cornerRadius = self.bounds.size.width/2.0;
 
   568     self.borderWidth = (highlighted ?6 :0);
 
   572 - (Square*) nw     {return (Square*)[_grid cellAtRow: _row+1 column: _column-1];}
 
   573 - (Square*) n      {return (Square*)[_grid cellAtRow: _row+1 column: _column  ];}
 
   574 - (Square*) ne     {return (Square*)[_grid cellAtRow: _row+1 column: _column+1];}
 
   575 - (Square*) e      {return (Square*)[_grid cellAtRow: _row   column: _column+1];}
 
   576 - (Square*) se     {return (Square*)[_grid cellAtRow: _row-1 column: _column+1];}
 
   577 - (Square*) s      {return (Square*)[_grid cellAtRow: _row-1 column: _column  ];}
 
   578 - (Square*) sw     {return (Square*)[_grid cellAtRow: _row-1 column: _column-1];}
 
   579 - (Square*) w      {return (Square*)[_grid cellAtRow: _row   column: _column-1];}
 
   581 // Directions relative to the current player:
 
   582 - (Square*) fl     {return self.fwdIsN ?self.nw :self.se;}
 
   583 - (Square*) f      {return self.fwdIsN ?self.n  :self.s;}
 
   584 - (Square*) fr     {return self.fwdIsN ?self.ne :self.sw;}
 
   585 - (Square*) r      {return self.fwdIsN ?self.e  :self.w;}
 
   586 - (Square*) br     {return self.fwdIsN ?self.se :self.nw;}
 
   587 - (Square*) b      {return self.fwdIsN ?self.s  :self.n;}
 
   588 - (Square*) bl     {return self.fwdIsN ?self.sw :self.ne;}
 
   589 - (Square*) l      {return self.fwdIsN ?self.w  :self.e;}
 
   592 static int sgn( int n ) {return n<0 ?-1 :(n>0 ?1 :0);}
 
   595 - (SEL) directionToCell: (GridCell*)dst
 
   597     static NSString* const kDirections[9] = {@"sw", @"s", @"se",
 
   600     if( dst.grid != self.grid )
 
   602     int dy=dst.row-_row, dx=dst.column-_column;
 
   604         if( !( _grid.usesDiagonals && abs(dx)==abs(dy) ) )
 
   606     NSString *dir = kDirections[ 3*(sgn(dy)+1) + (sgn(dx)+1) ];
 
   607     return dir ?NSSelectorFromString(dir) :NULL;
 
   610 - (NSArray*) lineToCell: (GridCell*)dst inclusive: (BOOL)inclusive;
 
   612     SEL dir = [self directionToCell: dst];
 
   615     NSMutableArray *line = [NSMutableArray array];
 
   617     for( cell=self; cell; cell = [cell performSelector: dir] ) {
 
   618         if( inclusive || (cell!=self && cell!=dst) )
 
   619             [line addObject: cell];
 
   623     return nil; // should be impossible, but just in case
 
   627 #if ! TARGET_OS_IPHONE
 
   629 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 
   631     CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
 
   633         CGColorRef color = CreatePatternColor(image);
 
   634         RectGrid *rectGrid = (RectGrid*)_grid;
 
   635         if( rectGrid.altCellColor && ((_row+_column) & 1) )
 
   636             rectGrid.altCellColor = color;
 
   638             rectGrid.cellColor = color;
 
   639         CGColorRelease(color);
 
   640         [rectGrid setNeedsDisplay];
 
   654 @implementation GoSquare
 
   656 @synthesize dotted=_dotted;
 
   658 - (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
 
   661         [super drawInParentContext: ctx fill: fill];
 
   663         CGRect frame = self.frame;
 
   664         const CGFloat midx=floor(CGRectGetMidX(frame))+0.5, 
 
   665                     midy=floor(CGRectGetMidY(frame))+0.5;
 
   666         CGPoint p[4] = {{CGRectGetMinX(frame),midy},
 
   667                         {CGRectGetMaxX(frame),midy},
 
   668                         {midx,CGRectGetMinY(frame)},
 
   669                         {midx,CGRectGetMaxY(frame)}};
 
   670         if( ! self.s )  p[2].y = midy;
 
   671         if( ! self.n )  p[3].y = midy;
 
   672         if( ! self.w )  p[0].x = midx;
 
   673         if( ! self.e )  p[1].x = midx;
 
   674         CGContextStrokeLineSegments(ctx, p, 4);
 
   677             CGContextSetFillColorWithColor(ctx,_grid.lineColor);
 
   678             CGRect dot = CGRectMake(midx-2.5, midy-2.5, 5, 5);
 
   679             CGContextFillEllipseInRect(ctx, dot);