Added support for clicking the board to place new pieces. Go and Tic-Tac-Toe now use this.
authorJens Alfke <jens@mooseyard.com>
Tue Mar 11 09:21:53 2008 -0700 (2008-03-11)
changeset 340d225cf9c43
parent 2 7b0441db81e5
child 4 d781b00f3ed4
Added support for clicking the board to place new pieces. Go and Tic-Tac-Toe now use this.
GeekGameBoard-iPhone.xcodeproj/project.pbxproj
Resources/Wood.jpg
Source/BoardUIView.m
Source/BoardView.m
Source/Game.h
Source/Game.m
Source/GoGame.m
Source/Grid.m
Source/QuartzUtils.m
Source/TicTacToeGame.m
Source/iPhoneAppDelegate.m
     1.1 --- a/GeekGameBoard-iPhone.xcodeproj/project.pbxproj	Mon Mar 10 17:32:04 2008 -0700
     1.2 +++ b/GeekGameBoard-iPhone.xcodeproj/project.pbxproj	Tue Mar 11 09:21:53 2008 -0700
     1.3 @@ -19,6 +19,11 @@
     1.4  		279F4C1D0D85D0AF00B32DBF /* X.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 279F4C1C0D85D0AF00B32DBF /* X.tiff */; };
     1.5  		279F4C1F0D85D0CB00B32DBF /* O.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 279F4C1E0D85D0CB00B32DBF /* O.tiff */; };
     1.6  		279F4C740D85D43800B32DBF /* Background.png in Resources */ = {isa = PBXBuildFile; fileRef = 279F4C730D85D43800B32DBF /* Background.png */; };
     1.7 +		279F4E0A0D860B8800B32DBF /* Green Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 279F4E050D860B8800B32DBF /* Green Ball.png */; };
     1.8 +		279F4E0B0D860B8800B32DBF /* Red Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 279F4E060D860B8800B32DBF /* Red Ball.png */; };
     1.9 +		279F4E0C0D860B8800B32DBF /* White Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 279F4E070D860B8800B32DBF /* White Ball.png */; };
    1.10 +		279F4E0E0D860B8800B32DBF /* Yellow Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 279F4E090D860B8800B32DBF /* Yellow Ball.png */; };
    1.11 +		279F4F1B0D86448100B32DBF /* Wood.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 279F4F1A0D86448100B32DBF /* Wood.jpg */; };
    1.12  		27C99B0F0D820868005AFD4F /* BoardUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C99AE40D820868005AFD4F /* BoardUIView.m */; };
    1.13  		27C99B100D820868005AFD4F /* Bit.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C99AE60D820868005AFD4F /* Bit.m */; };
    1.14  		27C99B110D820868005AFD4F /* BitHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C99AE80D820868005AFD4F /* BitHolder.m */; };
    1.15 @@ -57,6 +62,11 @@
    1.16  		279F4C1C0D85D0AF00B32DBF /* X.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = X.tiff; sourceTree = "<group>"; };
    1.17  		279F4C1E0D85D0CB00B32DBF /* O.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = O.tiff; sourceTree = "<group>"; };
    1.18  		279F4C730D85D43800B32DBF /* Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Background.png; sourceTree = "<group>"; };
    1.19 +		279F4E050D860B8800B32DBF /* Green Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Green Ball.png"; sourceTree = "<group>"; };
    1.20 +		279F4E060D860B8800B32DBF /* Red Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Red Ball.png"; sourceTree = "<group>"; };
    1.21 +		279F4E070D860B8800B32DBF /* White Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "White Ball.png"; sourceTree = "<group>"; };
    1.22 +		279F4E090D860B8800B32DBF /* Yellow Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Yellow Ball.png"; sourceTree = "<group>"; };
    1.23 +		279F4F1A0D86448100B32DBF /* Wood.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Wood.jpg; sourceTree = "<group>"; };
    1.24  		27C99AE30D820868005AFD4F /* BoardUIView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoardUIView.h; sourceTree = "<group>"; };
    1.25  		27C99AE40D820868005AFD4F /* BoardUIView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BoardUIView.m; sourceTree = "<group>"; };
    1.26  		27C99AE50D820868005AFD4F /* Bit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bit.h; sourceTree = "<group>"; };
    1.27 @@ -150,10 +160,6 @@
    1.28  			children = (
    1.29  				27C99AE30D820868005AFD4F /* BoardUIView.h */,
    1.30  				27C99AE40D820868005AFD4F /* BoardUIView.m */,
    1.31 -				27C99B4F0D82106E005AFD4F /* GGBLayer.h */,
    1.32 -				27C99B500D82106E005AFD4F /* GGBLayer.m */,
    1.33 -				279F4B600D85C63000B32DBF /* GGBTextLayer.h */,
    1.34 -				279F4B610D85C63000B32DBF /* GGBTextLayer.m */,
    1.35  				27C99AE50D820868005AFD4F /* Bit.h */,
    1.36  				27C99AE60D820868005AFD4F /* Bit.m */,
    1.37  				27C99AE70D820868005AFD4F /* BitHolder.h */,
    1.38 @@ -163,6 +169,10 @@
    1.39  				27C99AF20D820868005AFD4F /* Boards and Pieces */,
    1.40  				27C99AEB0D820868005AFD4F /* Cards */,
    1.41  				27C99AFD0D820868005AFD4F /* Games */,
    1.42 +				27C99B4F0D82106E005AFD4F /* GGBLayer.h */,
    1.43 +				27C99B500D82106E005AFD4F /* GGBLayer.m */,
    1.44 +				279F4B600D85C63000B32DBF /* GGBTextLayer.h */,
    1.45 +				279F4B610D85C63000B32DBF /* GGBTextLayer.m */,
    1.46  				27C99B0A0D820868005AFD4F /* QuartzUtils.h */,
    1.47  				27C99B0B0D820868005AFD4F /* QuartzUtils.m */,
    1.48  				27C99B0C0D820868005AFD4F /* GGBUtils.h */,
    1.49 @@ -248,6 +258,11 @@
    1.50  		29B97317FDCFA39411CA2CEA /* Resources */ = {
    1.51  			isa = PBXGroup;
    1.52  			children = (
    1.53 +				279F4E050D860B8800B32DBF /* Green Ball.png */,
    1.54 +				279F4E060D860B8800B32DBF /* Red Ball.png */,
    1.55 +				279F4E070D860B8800B32DBF /* White Ball.png */,
    1.56 +				279F4F1A0D86448100B32DBF /* Wood.jpg */,
    1.57 +				279F4E090D860B8800B32DBF /* Yellow Ball.png */,
    1.58  				279F4C730D85D43800B32DBF /* Background.png */,
    1.59  				279F4C1C0D85D0AF00B32DBF /* X.tiff */,
    1.60  				279F4C1E0D85D0CB00B32DBF /* O.tiff */,
    1.61 @@ -312,6 +327,11 @@
    1.62  				279F4C1D0D85D0AF00B32DBF /* X.tiff in Resources */,
    1.63  				279F4C1F0D85D0CB00B32DBF /* O.tiff in Resources */,
    1.64  				279F4C740D85D43800B32DBF /* Background.png in Resources */,
    1.65 +				279F4E0A0D860B8800B32DBF /* Green Ball.png in Resources */,
    1.66 +				279F4E0B0D860B8800B32DBF /* Red Ball.png in Resources */,
    1.67 +				279F4E0C0D860B8800B32DBF /* White Ball.png in Resources */,
    1.68 +				279F4E0E0D860B8800B32DBF /* Yellow Ball.png in Resources */,
    1.69 +				279F4F1B0D86448100B32DBF /* Wood.jpg in Resources */,
    1.70  			);
    1.71  			runOnlyForDeploymentPostprocessing = 0;
    1.72  		};
     2.1 Binary file Resources/Wood.jpg has changed
     3.1 --- a/Source/BoardUIView.m	Mon Mar 10 17:32:04 2008 -0700
     3.2 +++ b/Source/BoardUIView.m	Tue Mar 11 09:21:53 2008 -0700
     3.3 @@ -14,6 +14,11 @@
     3.4  #import "GGBUtils.h"
     3.5  
     3.6  
     3.7 +@interface BoardUIView ()
     3.8 +- (void) _findDropTarget: (CGPoint)pos;
     3.9 +@end
    3.10 +
    3.11 +
    3.12  @implementation BoardUIView
    3.13  
    3.14  
    3.15 @@ -102,17 +107,40 @@
    3.16      NSAssert(touches.count==1,@"No multitouch support yet");
    3.17      UITouch *touch = touches.anyObject;
    3.18      
    3.19 +    BOOL placing = NO;
    3.20      _dragStartPos = touch.locationInView;
    3.21      _dragBit = (Bit*) [self hitTestPoint: _dragStartPos
    3.22                          forLayerMatching: layerIsBit 
    3.23                                    offset: &_dragOffset];
    3.24 -    if( _dragBit ) {
    3.25 -        _dragMoved = NO;
    3.26 -        _dropTarget = nil;
    3.27 -        _oldHolder = _dragBit.holder;
    3.28 -        // Ask holder's and game's permission before dragging:
    3.29 -        if( _oldHolder )
    3.30 -            _dragBit = [_oldHolder canDragBit: _dragBit];
    3.31 +
    3.32 +    if( ! _dragBit ) {
    3.33 +        // If no bit was clicked, see if it's a BitHolder the game will let the user add a Bit to:
    3.34 +        id<BitHolder> holder = (id<BitHolder>) [self hitTestPoint: _dragStartPos
    3.35 +                                                 forLayerMatching: layerIsBitHolder
    3.36 +                                                           offset: NULL];
    3.37 +        if( holder ) {
    3.38 +            _dragBit = [_game bitToPlaceInHolder: holder];
    3.39 +            if( _dragBit ) {
    3.40 +                _dragOffset.x = _dragOffset.y = 0;
    3.41 +                if( _dragBit.superlayer==nil )
    3.42 +                    _dragBit.position = _dragStartPos;
    3.43 +                placing = YES;
    3.44 +            }
    3.45 +        }
    3.46 +    }
    3.47 +
    3.48 +    if( ! _dragBit ) {
    3.49 +        Beep();
    3.50 +        return;
    3.51 +    }
    3.52 +    
    3.53 +    // Clicked on a Bit:
    3.54 +    _dragMoved = NO;
    3.55 +    _dropTarget = nil;
    3.56 +    _oldHolder = _dragBit.holder;
    3.57 +    // Ask holder's and game's permission before dragging:
    3.58 +    if( _oldHolder ) {
    3.59 +        _dragBit = [_oldHolder canDragBit: _dragBit];
    3.60          if( _dragBit && ! [_game canBit: _dragBit moveFrom: _oldHolder] ) {
    3.61              [_oldHolder cancelDragBit: _dragBit];
    3.62              _dragBit = nil;
    3.63 @@ -122,14 +150,20 @@
    3.64              Beep();
    3.65              return;
    3.66          }
    3.67 -        // Start dragging:
    3.68 -        _oldSuperlayer = _dragBit.superlayer;
    3.69 -        _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
    3.70 -        _oldPos = _dragBit.position;
    3.71 -        ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
    3.72 -        _dragBit.pickedUp = YES;
    3.73 -    } else
    3.74 -        Beep();
    3.75 +    }
    3.76 +    // Start dragging:
    3.77 +    _oldSuperlayer = _dragBit.superlayer;
    3.78 +    _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
    3.79 +    _oldPos = _dragBit.position;
    3.80 +    ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
    3.81 +    _dragBit.pickedUp = YES;
    3.82 +    
    3.83 +    if( placing ) {
    3.84 +        if( _oldSuperlayer )
    3.85 +            _dragBit.position = _dragStartPos;      // animate Bit to new position
    3.86 +        _dragMoved = YES;
    3.87 +        [self _findDropTarget: _dragStartPos];
    3.88 +    }
    3.89  }
    3.90  
    3.91  
    3.92 @@ -158,27 +192,33 @@
    3.93          [CATransaction commit];
    3.94  
    3.95          // Find what it's over:
    3.96 -        id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: pos
    3.97 -                                                 forLayerMatching: layerIsBitHolder
    3.98 -                                                           offset: NULL];
    3.99 -        if( target == _oldHolder )
   3.100 -            target = nil;
   3.101 -        if( target != _dropTarget ) {
   3.102 -            [_dropTarget willNotDropBit: _dragBit];
   3.103 -            _dropTarget.highlighted = NO;
   3.104 -            _dropTarget = nil;
   3.105 -        }
   3.106 -        if( target ) {
   3.107 -            CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
   3.108 -                                                     fromLayer: _dragBit.superlayer];
   3.109 -            if( [target canDropBit: _dragBit atPoint: targetPos]
   3.110 -               && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
   3.111 -                _dropTarget = target;
   3.112 -                _dropTarget.highlighted = YES;
   3.113 -            }
   3.114 +        [self _findDropTarget: pos];
   3.115 +    }
   3.116 +}
   3.117 +
   3.118 +
   3.119 +- (void) _findDropTarget: (CGPoint)pos
   3.120 +{
   3.121 +    id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: pos
   3.122 +                                             forLayerMatching: layerIsBitHolder
   3.123 +                                                       offset: NULL];
   3.124 +    if( target == _oldHolder )
   3.125 +        target = nil;
   3.126 +    if( target != _dropTarget ) {
   3.127 +        [_dropTarget willNotDropBit: _dragBit];
   3.128 +        _dropTarget.highlighted = NO;
   3.129 +        _dropTarget = nil;
   3.130 +    }
   3.131 +    if( target ) {
   3.132 +        CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
   3.133 +                                                 fromLayer: _dragBit.superlayer];
   3.134 +        if( [target canDropBit: _dragBit atPoint: targetPos]
   3.135 +           && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
   3.136 +            _dropTarget = target;
   3.137 +            _dropTarget.highlighted = YES;
   3.138          }
   3.139      }
   3.140 -}
   3.141 +}    
   3.142  
   3.143  
   3.144  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   3.145 @@ -200,9 +240,13 @@
   3.146              } else {
   3.147                  // Nope, cancel:
   3.148                  [_dropTarget willNotDropBit: _dragBit];
   3.149 -                ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
   3.150 -                _dragBit.position = _oldPos;
   3.151 -                [_oldHolder cancelDragBit: _dragBit];
   3.152 +                if( _oldSuperlayer ) {
   3.153 +                    ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
   3.154 +                    _dragBit.position = _oldPos;
   3.155 +                    [_oldHolder cancelDragBit: _dragBit];
   3.156 +                } else {
   3.157 +                    [_dragBit removeFromSuperlayer];
   3.158 +                }
   3.159              }
   3.160          } else {
   3.161              // Just a click, without a drag:
     4.1 --- a/Source/BoardView.m	Mon Mar 10 17:32:04 2008 -0700
     4.2 +++ b/Source/BoardView.m	Tue Mar 11 09:21:53 2008 -0700
     4.3 @@ -28,6 +28,11 @@
     4.4  #import "GGBUtils.h"
     4.5  
     4.6  
     4.7 +@interface BoardView ()
     4.8 +- (void) _findDropTarget: (NSPoint)pos;
     4.9 +@end
    4.10 +
    4.11 +
    4.12  @implementation BoardView
    4.13  
    4.14  
    4.15 @@ -137,17 +142,40 @@
    4.16  
    4.17  - (void) mouseDown: (NSEvent*)ev
    4.18  {
    4.19 +    BOOL placing = NO;
    4.20      _dragStartPos = ev.locationInWindow;
    4.21      _dragBit = (Bit*) [self hitTestPoint: _dragStartPos
    4.22                          forLayerMatching: layerIsBit 
    4.23                                    offset: &_dragOffset];
    4.24 -    if( _dragBit ) {
    4.25 -        _dragMoved = NO;
    4.26 -        _dropTarget = nil;
    4.27 -        _oldHolder = _dragBit.holder;
    4.28 -        // Ask holder's and game's permission before dragging:
    4.29 -        if( _oldHolder )
    4.30 -            _dragBit = [_oldHolder canDragBit: _dragBit];
    4.31 +    
    4.32 +    if( ! _dragBit ) {
    4.33 +        // If no bit was clicked, see if it's a BitHolder the game will let the user add a Bit to:
    4.34 +        id<BitHolder> holder = (id<BitHolder>) [self hitTestPoint: _dragStartPos
    4.35 +                                                 forLayerMatching: layerIsBitHolder
    4.36 +                                                           offset: NULL];
    4.37 +        if( holder ) {
    4.38 +            _dragBit = [_game bitToPlaceInHolder: holder];
    4.39 +            if( _dragBit ) {
    4.40 +                _dragOffset.x = _dragOffset.y = 0;
    4.41 +                if( _dragBit.superlayer==nil )
    4.42 +                    _dragBit.position = NSPointToCGPoint([self convertPoint: _dragStartPos fromView: nil]);
    4.43 +                placing = YES;
    4.44 +            }
    4.45 +        }
    4.46 +    }
    4.47 +    
    4.48 +    if( ! _dragBit ) {
    4.49 +        Beep();
    4.50 +        return;
    4.51 +    }
    4.52 +    
    4.53 +    // Clicked on a Bit:
    4.54 +    _dragMoved = NO;
    4.55 +    _dropTarget = nil;
    4.56 +    _oldHolder = _dragBit.holder;
    4.57 +    // Ask holder's and game's permission before dragging:
    4.58 +    if( _oldHolder ) {
    4.59 +        _dragBit = [_oldHolder canDragBit: _dragBit];
    4.60          if( _dragBit && ! [_game canBit: _dragBit moveFrom: _oldHolder] ) {
    4.61              [_oldHolder cancelDragBit: _dragBit];
    4.62              _dragBit = nil;
    4.63 @@ -157,17 +185,25 @@
    4.64              NSBeep();
    4.65              return;
    4.66          }
    4.67 -        // Start dragging:
    4.68 -        _oldSuperlayer = _dragBit.superlayer;
    4.69 -        _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
    4.70 -        _oldPos = _dragBit.position;
    4.71 -        ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
    4.72 -        _dragBit.pickedUp = YES;
    4.73 -        [[NSCursor closedHandCursor] push];
    4.74 -    } else
    4.75 -        NSBeep();
    4.76 +    }
    4.77 +    
    4.78 +    // Start dragging:
    4.79 +    _oldSuperlayer = _dragBit.superlayer;
    4.80 +    _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
    4.81 +    _oldPos = _dragBit.position;
    4.82 +    ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
    4.83 +    _dragBit.pickedUp = YES;
    4.84 +    [[NSCursor closedHandCursor] push];
    4.85 +    
    4.86 +    if( placing ) {
    4.87 +        if( _oldSuperlayer )
    4.88 +            _dragBit.position = NSPointToCGPoint([self convertPoint: _dragStartPos fromView: nil]);
    4.89 +        _dragMoved = YES;
    4.90 +        [self _findDropTarget: _dragStartPos];
    4.91 +    }
    4.92  }
    4.93  
    4.94 +
    4.95  - (void) mouseDragged: (NSEvent*)ev
    4.96  {
    4.97      if( _dragBit ) {
    4.98 @@ -192,28 +228,37 @@
    4.99          [CATransaction commit];
   4.100  
   4.101          // Find what it's over:
   4.102 -        id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: where
   4.103 -                                                 forLayerMatching: layerIsBitHolder
   4.104 -                                                           offset: NULL];
   4.105 -        if( target == _oldHolder )
   4.106 -            target = nil;
   4.107 -        if( target != _dropTarget ) {
   4.108 -            [_dropTarget willNotDropBit: _dragBit];
   4.109 -            _dropTarget.highlighted = NO;
   4.110 -            _dropTarget = nil;
   4.111 -        }
   4.112 -        if( target ) {
   4.113 -            CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
   4.114 -                                                     fromLayer: _dragBit.superlayer];
   4.115 -            if( [target canDropBit: _dragBit atPoint: targetPos]
   4.116 -               && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
   4.117 -                _dropTarget = target;
   4.118 -                _dropTarget.highlighted = YES;
   4.119 -            }
   4.120 +        [self _findDropTarget: pos];
   4.121 +    }
   4.122 +}
   4.123 +
   4.124 +
   4.125 +- (void) _findDropTarget: (NSPoint)locationInWindow
   4.126 +{
   4.127 +    locationInWindow.x += _dragOffset.x;
   4.128 +    locationInWindow.y += _dragOffset.y;
   4.129 +    id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: locationInWindow
   4.130 +                                             forLayerMatching: layerIsBitHolder
   4.131 +                                                       offset: NULL];
   4.132 +    if( target == _oldHolder )
   4.133 +        target = nil;
   4.134 +    if( target != _dropTarget ) {
   4.135 +        [_dropTarget willNotDropBit: _dragBit];
   4.136 +        _dropTarget.highlighted = NO;
   4.137 +        _dropTarget = nil;
   4.138 +    }
   4.139 +    if( target ) {
   4.140 +        CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
   4.141 +                                                 fromLayer: _dragBit.superlayer];
   4.142 +        if( [target canDropBit: _dragBit atPoint: targetPos]
   4.143 +           && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
   4.144 +            _dropTarget = target;
   4.145 +            _dropTarget.highlighted = YES;
   4.146          }
   4.147      }
   4.148  }
   4.149  
   4.150 +
   4.151  - (void) mouseUp: (NSEvent*)ev
   4.152  {
   4.153      if( _dragBit ) {
   4.154 @@ -233,9 +278,13 @@
   4.155              } else {
   4.156                  // Nope, cancel:
   4.157                  [_dropTarget willNotDropBit: _dragBit];
   4.158 -                ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
   4.159 -                _dragBit.position = _oldPos;
   4.160 -                [_oldHolder cancelDragBit: _dragBit];
   4.161 +                if( _oldSuperlayer ) {
   4.162 +                    ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
   4.163 +                    _dragBit.position = _oldPos;
   4.164 +                    [_oldHolder cancelDragBit: _dragBit];
   4.165 +                } else {
   4.166 +                    [_dragBit removeFromSuperlayer];
   4.167 +                }
   4.168              }
   4.169          } else {
   4.170              // Just a click, without a drag:
     5.1 --- a/Source/Game.h	Mon Mar 10 17:32:04 2008 -0700
     5.2 +++ b/Source/Game.h	Tue Mar 11 09:21:53 2008 -0700
     5.3 @@ -60,6 +60,10 @@
     5.4      Default implementation just calls -endTurn. */
     5.5  - (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)src to: (id<BitHolder>)dst;
     5.6  
     5.7 +/** Called on mouse-down/touch of an *empty* BitHolder. Should return a Bit if
     5.8 +    it's OK to place a new Bit there; else nil. */
     5.9 +- (Bit*) bitToPlaceInHolder: (id<BitHolder>)holder;
    5.10 +
    5.11  /** Called instead of the above if a Bit is simply clicked, not dragged.
    5.12      Should return NO if the click is illegal (i.e. clicking an empty draw pile in a card game.)
    5.13      Default implementation always returns YES. */
     6.1 --- a/Source/Game.m	Mon Mar 10 17:32:04 2008 -0700
     6.2 +++ b/Source/Game.m	Tue Mar 11 09:21:53 2008 -0700
     6.3 @@ -30,15 +30,6 @@
     6.4  @end
     6.5  
     6.6  
     6.7 -/**  WARNING: THIS CODE REQUIRES GARBAGE COLLECTION!
     6.8 - **  This sample application uses Objective-C 2.0 garbage collection.
     6.9 - **  Therefore, the source code in this file does NOT perform manual object memory management.
    6.10 - **  If you reuse any of this code in a process that isn't garbage collected, you will need to
    6.11 - **  add all necessary retain/release/autorelease calls, and implement -dealloc methods,
    6.12 - **  otherwise unpleasant leakage will occur!
    6.13 - **/
    6.14 -
    6.15 -
    6.16  @implementation Game
    6.17  
    6.18  
    6.19 @@ -134,6 +125,12 @@
    6.20      [self endTurn];
    6.21  }
    6.22  
    6.23 +- (Bit*) bitToPlaceInHolder: (id<BitHolder>)holder
    6.24 +{
    6.25 +    return nil;
    6.26 +}
    6.27 +
    6.28 +
    6.29  - (BOOL) clickedBit: (Bit*)bit
    6.30  {
    6.31      return YES;
     7.1 --- a/Source/GoGame.m	Mon Mar 10 17:32:04 2008 -0700
     7.2 +++ b/Source/GoGame.m	Tue Mar 11 09:21:53 2008 -0700
     7.3 @@ -32,29 +32,20 @@
     7.4  @implementation GoGame
     7.5  
     7.6  
     7.7 -- (void) x_createDispenser: (NSString*)imageName position: (CGPoint)position forPlayer: (unsigned)playerNo
     7.8 -{
     7.9 -    CGFloat pieceSize = (int)(_grid.spacing.width * 0.9) & ~1;  // make sure it's even
    7.10 -    Piece *stone = [[Piece alloc] initWithImageNamed: imageName scale: pieceSize];
    7.11 -    stone.owner = [self.players objectAtIndex: playerNo];
    7.12 -    CGRect frame = {position, {1.5*pieceSize,1.5*pieceSize}};
    7.13 -    Dispenser *disp = [[Dispenser alloc] initWithPrototype: stone quantity: INT_MAX frame:frame];
    7.14 -    [_board addSublayer: disp];
    7.15 -    [disp release];
    7.16 -    [stone release];
    7.17 -}    
    7.18 -
    7.19 -
    7.20  - (id) initWithBoard: (GGBLayer*)board
    7.21  {
    7.22      self = [super initWithBoard: board];
    7.23      if (self != nil) {
    7.24          [self setNumberOfPlayers: 2];
    7.25 +        [(Player*)[_players objectAtIndex: 0] setName: @"Red"];
    7.26 +        [(Player*)[_players objectAtIndex: 1] setName: @"White"];
    7.27          
    7.28          CGSize size = board.bounds.size;
    7.29 +        CGFloat boardSide = MIN(size.width,size.height);
    7.30          RectGrid *grid = [[RectGrid alloc] initWithRows: 9 columns: 9 
    7.31 -                                                  frame: CGRectMake((size.width-size.height+16)/2,8,
    7.32 -                                                                    size.height-16,size.height-16)];
    7.33 +                                                  frame: CGRectMake(floor((size.width-boardSide)/2),
    7.34 +                                                                    floor((size.height-boardSide)/2),
    7.35 +                                                                    boardSide,boardSide)];
    7.36          _grid = grid;
    7.37          grid.backgroundColor = GetCGPatternNamed(@"Wood.jpg");
    7.38          grid.borderColor = kTranslucentLightGrayColor;
    7.39 @@ -72,15 +63,6 @@
    7.40          
    7.41          CGRect gridFrame = grid.frame;
    7.42          CGFloat pieceSize = (int)grid.spacing.width & ~1;  // make sure it's even
    7.43 -        [self x_createDispenser: @"Red Ball.png"
    7.44 -                      position: CGPointMake(CGRectGetMinX(gridFrame)-2*pieceSize, 
    7.45 -                                            CGRectGetMinY(gridFrame))
    7.46 -                     forPlayer: 0];
    7.47 -        [self x_createDispenser: @"White Ball.png"
    7.48 -                      position: CGPointMake(CGRectGetMaxX(gridFrame)+0.5*pieceSize,
    7.49 -                                            CGRectGetMaxY(gridFrame)-1.5*pieceSize)
    7.50 -                     forPlayer: 1];
    7.51 -        
    7.52          CGFloat captureHeight = gridFrame.size.height-4*pieceSize;
    7.53          _captured[0] = [[Stack alloc] initWithStartPos: CGPointMake(2*pieceSize,0)
    7.54                                                 spacing: CGSizeMake(0,pieceSize)
    7.55 @@ -110,6 +92,18 @@
    7.56  }
    7.57  
    7.58  
    7.59 +- (Bit*) bitToPlaceInHolder: (id<BitHolder>)holder
    7.60 +{
    7.61 +    if( holder.bit != nil || ! [holder isKindOfClass: [GoSquare class]] )
    7.62 +        return nil;
    7.63 +    NSString *imageName = self.currentPlayer.index ?@"White Ball.png" :@"Red Ball.png";
    7.64 +    CGFloat pieceSize = (int)(_grid.spacing.width * 0.9) & ~1;  // make sure it's even
    7.65 +    Piece *stone = [[Piece alloc] initWithImageNamed: imageName scale: pieceSize];
    7.66 +    stone.owner = self.currentPlayer;
    7.67 +    return [stone autorelease];
    7.68 +}
    7.69 +
    7.70 +
    7.71  - (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
    7.72  {
    7.73      Square *dst=(Square*)dstHolder;
     8.1 --- a/Source/Grid.m	Mon Mar 10 17:32:04 2008 -0700
     8.2 +++ b/Source/Grid.m	Tue Mar 11 09:21:53 2008 -0700
     8.3 @@ -67,9 +67,14 @@
     8.4  {
     8.5      CGFloat spacing = floor(MIN( (frame.size.width -2)/(CGFloat)nColumns,
     8.6                                 (frame.size.height-2)/(CGFloat)nRows) );
     8.7 +    CGSize size = CGSizeMake(nColumns*spacing+2, nRows*spacing+2);
     8.8 +    CGPoint position = frame.origin;
     8.9 +    position.x += round( (frame.size.width -size.width )/2.0 );
    8.10 +    position.y += round( (frame.size.height-size.height)/2.0 );
    8.11 +
    8.12      return [self initWithRows: nRows columns: nColumns
    8.13                        spacing: CGSizeMake(spacing,spacing)
    8.14 -                     position: frame.origin];
    8.15 +                     position: position];
    8.16  }
    8.17  
    8.18  
    8.19 @@ -187,6 +192,7 @@
    8.20  {
    8.21      // Custom CALayer drawing implementation. Delegates to the cells to draw themselves
    8.22      // in me; this is more efficient than having each cell have its own drawing.
    8.23 +    [super drawInContext: ctx];
    8.24      if( _cellColor ) {
    8.25          CGContextSetFillColorWithColor(ctx, _cellColor);
    8.26          [self drawCellsInContext: ctx fill: YES];
    8.27 @@ -409,6 +415,7 @@
    8.28  - (void) setHighlighted: (BOOL)highlighted
    8.29  {
    8.30      [super setHighlighted: highlighted];
    8.31 +    self.cornerRadius = self.bounds.size.width/2.0;
    8.32      self.borderWidth = (highlighted ?6 :0);
    8.33  }
    8.34  
     9.1 --- a/Source/QuartzUtils.m	Mon Mar 10 17:32:04 2008 -0700
     9.2 +++ b/Source/QuartzUtils.m	Tue Mar 11 09:21:53 2008 -0700
     9.3 @@ -71,8 +71,9 @@
     9.4      [CATransaction setValue:(id)kCFBooleanTrue
     9.5                       forKey:kCATransactionDisableActions];
     9.6  
     9.7 -    CGPoint pos = [newSuperlayer convertPoint: layer.position 
     9.8 -                      fromLayer: layer.superlayer];
     9.9 +    CGPoint pos = layer.position;
    9.10 +    if( layer.superlayer )
    9.11 +        pos = [newSuperlayer convertPoint: pos fromLayer: layer.superlayer];
    9.12      [layer retain];
    9.13      [layer removeFromSuperlayer];
    9.14      if( index >= 0 )
    10.1 --- a/Source/TicTacToeGame.m	Mon Mar 10 17:32:04 2008 -0700
    10.2 +++ b/Source/TicTacToeGame.m	Tue Mar 11 09:21:53 2008 -0700
    10.3 @@ -71,6 +71,14 @@
    10.4      return self;
    10.5  }
    10.6  
    10.7 +- (Bit*) bitToPlaceInHolder: (id<BitHolder>)holder
    10.8 +{
    10.9 +    if( holder.bit==nil && [holder isKindOfClass: [Square class]] )
   10.10 +        return _dispenser[self.currentPlayer.index].bit;
   10.11 +    else
   10.12 +        return nil;
   10.13 +}
   10.14 +
   10.15  - (void) nextPlayer
   10.16  {
   10.17      [super nextPlayer];
    11.1 --- a/Source/iPhoneAppDelegate.m	Mon Mar 10 17:32:04 2008 -0700
    11.2 +++ b/Source/iPhoneAppDelegate.m	Tue Mar 11 09:21:53 2008 -0700
    11.3 @@ -45,7 +45,7 @@
    11.4      [_window addSubview: _headline];
    11.5      
    11.6      // Start game:
    11.7 -    [self startGameNamed: @"TicTacToeGame"];
    11.8 +    [self startGameNamed: @"GoGame"];
    11.9      
   11.10      // Show window
   11.11      [_window makeKeyAndVisible];