1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
|
/* Gridlock
Copyright (c) 2002-2003 by Brian Nenninger. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
#import "DCHypergrid.h"
#import "AccessorMacros.h"
#import "CocoaAdditions.h"
@interface Game : NSObject {
DCHypergrid *grid;
DCHypergrid *futureGrid;
int playerNumber;
NSDictionary *configurationInfo;
int moveCount;
int _nrows;
int _ncols;
}
/** Returns true if the given position exists in the game. Subclasses should not need to override.
*/
-(BOOL)isPositionValid:(DCHypergridPosition *)pos;
-(BOOL)isValidRow:(int)row column:(int)col;
/** Returns a deep copy of the game, duplicating all state. The default implementation creates
a new object of the receiver's class and copies the grid and playerNumber ivars. Subclasses
should override if they need to copy additional state, in which case they should also call
the superclass implementation.
The returned object has a retain count of 1 and should be released by the caller when needed.
*/
-(Game *)copy;
/** Makes the given game a copy of the receiver, by copying all necessary information. The
given game can be assumed to have a grid with the same dimensions as the receiver. The default
implementation copies the grid values and ivars defined in this class. Superclasses should
override to copy additional state if needed.
*/
-(void)copyValuesToGame:(Game *)newGame;
/**
Resets the game to its beginning state. Subclasses which override must call the superclass
implementation.
*/
-(void)reset;
/** Creates a grid with dimensions and initial positions from the "rows", "cols", and "positions" keys
in the game's configurationInfo dictionary. Normally called by subclasses in their -reset methods.
*/
-(void)createGridFromConfiguration;
/** Returns the number of rows in the game board.
Default implementation returns [[self grid] numberOfRows]. Subclasses should not override
unless they don't use the grid ivar.
*/
-(int)numberOfRows;
/** Returns the number of columns in the game board.
Default implementation returns [[self grid] numberOfColumns]. Subclasses should not override
unless they don't use the grid ivar.
*/
-(int)numberOfColumns;
/** Returns the DCHypergrid object that the game uses. Default implementation returns the grid
ivar; subclasses should not normally need to override.
*/
idAccessor_h(grid, setGrid)
/** Returns the number of moves made in the game. Subclasses should not need to override.
*/
-(int)moveCount;
// accessors for configuration dictionary. The dictionary must not be modified after it is assigned.
-(NSDictionary *)configurationInfo;
-(void)setConfigurationInfo:(NSDictionary *)value;
/** Returns YES if the given array contains positions representing the beginning of a legal move.
It should return NO if the array represents a complete move to which no more positions can be
added (in which case -isCompleteMoveSequenceValid: would return YES). Should return NO if the
the argument is empty or nil.
The default implementation examines the moves returned by -allValidMoveSequences. Subclasses *must*
override if they implement -allValidMoveSequences in terms of -inferredValidMoveSequences
to avoid an infinite loop.
*/
-(BOOL)isPartialMoveSequenceValid:(NSArray *)positions;
/** Returns YES if the given array contains positions represents a complete legal move. It is
possible for both -isPartialMoveSequenceValid: and -isCompleteMoveSequenceValid: to return YES
for the same array; for example if (A,B) and (A,B,C) are legal moves then both methods
should return YES when given an argument of (A,B). If the argument is empty or nil, should
return true if a pass is legal.
The default implementation examines the moves returned by -allValidMoveSequences. Subclasses *must*
override if they implement -allValidMoveSequences in terms of -inferredValidMoveSequences
to avoid an infinite loop.
*/
-(BOOL)isCompleteMoveSequenceValid:(NSArray *)positions;
/** Returns YES if a pass is a valid move. Implemented by calling -isCompleteMoveSequenceValid:
with a nil argument. Subclasses should not need to override.
*/
-(BOOL)isPassValid;
/** Must be implemented by subclasses.
Called when the given move is being considered or about to be made. This method should update
internal state so that -positionsOfAllChangingCells and -futureValueAtPosition: return correct
values for the given move. Normally a subclass will do this by setting values in the futureGrid
ivar (after first calling -resetFutureGrid). If a subclass doesn't use futureGrid, it must override
-positionsOfAllChangingCells and -futureValueAtPosition: .
The move must be valid; if it is not the results are undefined.
*/
-(BOOL)prepareMoveSequence:(NSArray *)positions;
/** Provides access to the grid which holds the values which the game would have if the move specified in
-prepareMoveSequence: were to be executed. Subclasses should update this grid in their implementations of
-prepareMoveSequence: .
*/
-(DCHypergrid *)futureGrid;
-(void)setFutureGrid:(DCHypergrid *)value;
/** Creates futureGrid if it hasn't been initialized, setting it to a grid equal to the grid ivar.
Subclasses will normally call this method at the beginning of -prepareMoveSequence:
*/
-(void)resetFutureGrid;
/** Updates the state of the game by executing the move given in the last call to -prepareMoveSequence:
The default implementation copies the values stored by the futureGrid ivar if it is non-nil. If futureGrid
is nil, it calls -positionsOfAllChangingCells to get the positions to be updated, and calls
-futureValueAtPosition: for each of those positions. Subclasses do not need to override.
*/
-(void)updateFromPreparedMove;
/** Returns all cells which would change state if the move previously specified by a call to
-prepareMoveSequence: were to be executed. The default implemenation determines the changed positions by
inspecting the futureGrid ivar. Subclasses should override if they don't use futureGrid.
*/
-(NSArray *)positionsOfAllChangingCells;
/** Called when a pass is being considered or about to be made. Implemented by calling
-prepareMoveSequence: with a nil argument. Subclasses should not need to override.
*/
-(BOOL)preparePass;
/** Executes the move, updates the present state of the game, and returns YES.
The default implementation calls -prepareMoveSequence:, uses -futureValueAtPosition: to update
the game state, and calls -moveFinised. Subclasses do not need to override, but can for optimization.
The move must be valid; if it is not the results are undefined.
*/
-(BOOL)makeMoveSequence:(NSArray *)positions;
/** Called to execute a pass. Implemented by calling -makeMoveSequence: with a nil argument. Subclasses should not need to override.
*/
-(BOOL)pass;
/** Called when a move has just been made. The default implementation increments the move count
and player number, subclasses which override should call the superclass implementation.
*/
-(void)didMakeMove:(NSArray *)positions;
/** Returns the value of the cell at the given position. Default implementation forwards the call
to the grid ivar.
*/
-(int)valueAtPosition:(DCHypergridPosition *)pos;
-(int)valueAtRow:(int)r column:(int)c;
/** Sets the value of the cell at the given position. Default implementation forwards the call
to the grid ivar.
*/
-(void)setValue:(int)value atPosition:(DCHypergridPosition *)pos;
-(void)setValue:(int)value atRow:(int)r column:(int)c;
/** Helper method to set the values of multiple cells listed in the given array. The elements of
the array must be arrays of 3 objects, all of which respond to -intValue, giving the row, column,
and value in that order. Generally this method is used when setting a starting position read
from a configuration file (see Games.plist).
*/
-(void)setGridValuesFromArray:(NSArray *)array;
/** Helper method to initialize a game by setting the values of cells in the "first" rows
(row 0 and up for player 1, highest numbered row and down for player 2).
*/
-(void)fillFirstRows:(int)numRows;
/** Returns the value that the cell at the given position would have if the move previously
specified by a call to -prepareMoveSequence: were to be executed. The default implementation looks
in the futureGrid ivar for the future value. Subclasses should override if they don't use futureGrid.
*/
-(int)futureValueAtPosition:(DCHypergridPosition *)pos;
/** Returns the number of players in the game. The default implementation returns 2.
*/
-(int)numberOfPlayers;
/** Must be implemented by subclasses.
Returns the number (1-based) of the player whose turn it is.
*/
-(int)currentPlayerNumber;
-(void)setCurrentPlayerNumber:(int)value;
/** Returns the player number (1-based) who will move after the given player number. The default
implementation returns 1+([self currentPlayerNumber]%[self numberOfPlayers]).
*/
-(int)playerNumberMovingAfterPlayer:(int)pnum;
/** Returns the number (1-based) of the player whose turn it will next be. The default
implementation returns [self playerNumberMovingAfterPlayer:[self currentPlayerNumber]].
*/
-(int)nextPlayerNumber;
/** Sets the player number to the next player. Subclasses should not need to override.
*/
-(void)incrementPlayerNumber;
/** Returns YES if player scores should be shown. The default implentation returns NO.
*/
-(BOOL)showScores;
/** Returns a game-specific score for the given player. The default implementation returns the number of
cells with value equal to the player number.
*/
-(int)scoreForPlayer:(int)pnum;
/** Returns the number of the player who has won, or 0 if there is no winner. Should only be
called if the game is over (-isGameOver returns YES). The default implementation returns
the player with the highest score as determined by -scoreForPlayer:.
*/
-(int)winningPlayer;
/** Returns an array of positions which contain the "winning" pieces. The default implementation
returns nil, subclasses should override if applicable (e.g. Connect Four and Gomoku).
*/
-(NSArray *)positionsOfWinningPieces;
/** Must be implemented by subclasses.
Returns YES if the game is over, NO if not.
*/
-(BOOL)isGameOver;
/** Must be implemented by subclasses.
Returns an array containing all legal move sequences for the current player. Subclasses may implement
this method by calling -inferredValidMoveSequences (see below), but if they do, they *must* override
-isPartialMoveSequenceValid: and -isCompleteMoveSequenceValid:, since the default implementations of
those methods call -allValidMoveSequences, and -inferredValidMoveSequences calls them.
*/
-(NSArray *)allValidMoveSequences;
/** Returns an array containing all legal move sequences for the current player. Used by AI
classes. Uses -isPartialMoveSequenceValid: and -isCompleteMoveSequenceValid: to build all
possible sequences of valid moves. This method should only ever be called by subclasses
as a means of implementing allValidMoveSequences. If this is done, the subclass *must*
override -isPartialMoveSequenceValid: and -isCompleteMoveSequenceValid: to avoid infinite recursion.
*/
-(NSArray *)inferredValidMoveSequences;
/** Returns a human-readable description of the given move sequence. The default implementation
labels columns as letters starting with 'a', rows as numbers starting with 1, and returns a
string like "c4-d5".
*/
-(NSString *)descriptionForMove:(NSArray *)move;
-(DCHypergridPosition *)randomPosition;
-(void)fillRandomEmptyCellsWithValue:(int)value count:(int)count;
-(id)propertyList;
-(void)updateFromPropertyList:(id)plist;
@end
|