jens@0: /* This code is based on Apple's "GeekGameBoard" sample code, version 1.0. jens@0: http://developer.apple.com/samplecode/GeekGameBoard/ jens@0: Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved. jens@0: jens@0: Redistribution and use in source and binary forms, with or without modification, are permitted jens@0: provided that the following conditions are met: jens@0: jens@0: * Redistributions of source code must retain the above copyright notice, this list of conditions jens@0: and the following disclaimer. jens@0: * Redistributions in binary form must reproduce the above copyright notice, this list of jens@0: conditions and the following disclaimer in the documentation and/or other materials provided jens@0: with the distribution. jens@0: jens@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR jens@0: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND jens@0: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- jens@0: BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES jens@0: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jens@0: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN jens@0: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF jens@0: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jens@0: */ jens@7: @class GGBLayer, Bit, BitHolder, Player; jens@0: @protocol BitHolder; jens@0: jens@0: jens@0: /** Abstract superclass. Keeps track of the rules and turns of a game. */ jens@0: @interface Game : NSObject jens@0: { jens@1: GGBLayer *_board; jens@0: NSArray *_players; jens@0: Player *_currentPlayer, *_winner; jens@7: NSMutableString *_currentMove; jens@7: NSMutableArray *_states, *_moves; jens@7: unsigned _currentTurn; jens@0: } jens@0: jens@0: /** Returns the human-readable name of this game. jens@0: (By default it just returns the class name with the "Game" suffix removed.) */ jens@0: + (NSString*) displayName; jens@0: jens@4: + (BOOL) landscapeOriented; jens@4: jens@0: @property (readonly, copy) NSArray *players; jens@0: @property (readonly) Player *currentPlayer, *winner; jens@0: jens@7: @property (readonly) NSArray *states, *moves; jens@7: @property (readonly) unsigned maxTurn; jens@7: @property unsigned currentTurn; jens@7: @property (readonly) BOOL isLatestTurn; jens@7: jens@7: - (BOOL) animateMoveFrom: (BitHolder*)src to: (BitHolder*)dst; jens@7: jens@0: jens@0: // Methods for subclasses to implement: jens@0: jens@0: /** Designated initializer. After calling the superclass implementation, jens@0: it should add the necessary Grids, Pieces, Cards, Decks etc. to the board. */ jens@1: - (id) initWithBoard: (GGBLayer*)board; jens@0: jens@7: jens@0: /** Should return YES if it is legal for the given bit to be moved from its current holder. jens@0: Default implementation always returns YES. */ jens@0: - (BOOL) canBit: (Bit*)bit moveFrom: (id)src; jens@0: jens@0: /** Should return YES if it is legal for the given Bit to move from src to dst. jens@0: Default implementation always returns YES. */ jens@0: - (BOOL) canBit: (Bit*)bit moveFrom: (id)src to: (id)dst; jens@0: jens@7: jens@0: /** Should handle any side effects of a Bit's movement, such as captures or scoring. jens@0: Does not need to do the actual movement! That's already happened. jens@0: It should end by calling -endTurn, if the player's turn is over. jens@0: Default implementation just calls -endTurn. */ jens@0: - (void) bit: (Bit*)bit movedFrom: (id)src to: (id)dst; jens@0: jens@3: /** Called on mouse-down/touch of an *empty* BitHolder. Should return a Bit if jens@3: it's OK to place a new Bit there; else nil. */ jens@3: - (Bit*) bitToPlaceInHolder: (id)holder; jens@3: jens@0: /** Called instead of the above if a Bit is simply clicked, not dragged. jens@0: Should return NO if the click is illegal (i.e. clicking an empty draw pile in a card game.) jens@0: Default implementation always returns YES. */ jens@0: - (BOOL) clickedBit: (Bit*)bit; jens@0: jens@0: /** Should return the winning player, if the current position is a win, else nil. jens@0: Default implementation returns nil. */ jens@0: - (Player*) checkForWinner; jens@0: jens@0: jens@7: @property (copy) NSString* stateString; jens@7: - (BOOL) applyMoveString: (NSString*)move; jens@7: jens@7: jens@0: // Protected methods for subclasses to call: jens@0: jens@0: /** Sets the number of players in the game. Subclass initializers should call this. */ jens@0: - (void) setNumberOfPlayers: (unsigned)n; jens@0: jens@7: /** The current move in progress. Append text to it as the user makes moves. */ jens@7: @property (readonly) NSMutableString* currentMove; jens@7: jens@0: /** Advance to the next player, when a turn is over. */ jens@0: - (void) nextPlayer; jens@0: jens@0: /** Checks for a winner and advances to the next player. */ jens@0: - (void) endTurn; jens@0: jens@0: @end jens@0: jens@0: jens@0: jens@0: /** A mostly-passive object used to represent a player. */ jens@0: @interface Player : NSObject jens@0: { jens@0: Game *_game; jens@0: NSString *_name; jens@0: } jens@0: jens@0: - (id) initWithGame: (Game*)game; jens@0: jens@0: @property (readonly) Game *game; jens@0: @property (copy) NSString *name; jens@0: @property (readonly) int index; jens@0: @property (readonly, getter=isCurrent) BOOL current; jens@0: @property (readonly, getter=isFriendly) BOOL friendly; jens@0: @property (readonly, getter=isUnfriendly) BOOL unfriendly; jens@0: @property (readonly) Player *nextPlayer, *previousPlayer; jens@0: jens@0: @end jens@0: jens@0: jens@0: jens@0: @interface CALayer (Game) jens@0: jens@0: /** Called on any CALayer in the game's layer tree, will return the current Game object. */ jens@0: @property (readonly) Game *game; jens@0: jens@0: @end