package cs3500.connectn.model; import java.util.Set; /** * An abstract Connect N game, which is a generalization of Connect * Four. The state of a Connect N game must keep track of the current * player and the arrangement of tokens in the grid, and this interface provides * methods for manipulating and observing that state while enforcing the rules * of the game and the integrity of the representation. * *
This interface also includes static factory methods for creating {@code * Model}s and {@link Model.Builder}s. * *
Impl. note: This interfaces responsibilities are limited to the core * domain of the game itself. Presentation code, of course, does not belong here * in the model. */ public interface Model { /** The default width of the grid. */ int DEFAULT_WIDTH = 7; /** The default height of the grid. */ int DEFAULT_HEIGHT = 6; /** The default length of the line needed to win. */ int DEFAULT_GOAL = 4; /** * Constructs a new game model for playing Connect Four with the default * parameters. * * @return the new game model * @see #connectN(int, int, int) * @see #builder() */ static Model connectFour() { return builder().build(); } /** * Constructs a new game model with the given parameters. * * @param width the width of the grid (positive) * @param height the height of the grid (positive) * @param goal the goal line length for the game ({@code > 1}) * @return the new game model * * @see #connectFour() * @see #builder() */ static Model connectN(int width, int height, int goal) { return builder() .width(width) .height(height) .goal(goal) .build(); } /** * Constructs a builder for configuring and then creating a {@code Model} * instance. Defaults to a game of Connect Four with a 7-by-6 grid. * * @return the new builder */ static Builder builder() { return new ModelImpl.BuilderImpl(); } /** * Gets the width of the game. * * @return the width */ int getWidth(); /** * Gets the height of the game. * * @return the height */ int getHeight(); /** * Gets the goal of the game. The goal is the line length required to win, * e.g., 4 for Connect Four. * * @return the goal */ int getGoal(); /** * Represents the status of the game. */ enum Status { /** * The game is ongoing. */ Playing, /** * The game has ended in a stalemate. */ Stalemate, /** * The game has ended with a winner. * * @see #getWinner() */ Won; } /** * Gets the current status of the game. * * @return the status */ Status getStatus(); /** * Determines whether the game is over. * * @return whether the game is over */ default boolean isGameOver() { return getStatus() != Status.Playing; } /** * Gets the player whose turn it is now. * *
PRECONDITION: the game isn't over * * @return the next player * @throws IllegalStateException if {@code isGameOver()} */ Player getNextPlayer(); /** * Returns the winner of the game. * *
PRECONDITION: the game is over and has a winner * * @return the winner * @throws IllegalStateException if {@code getStatus() != Status.Won} */ Player getWinner(); /** * Returns the set of positions in the grid forming the winning line. * *
PRECONDITION: the game is over and has a winner
*
* @return the set of positions
* @throws IllegalStateException if {@code getStatus() != Status.Won}
*/
Set The {@code IllegalMoveException}s below are thrown for user errors,
* whereas the {@code IllegalStateException}s are thrown for (client)
* programmer errors.
*
* @param who the player who is moving
* @param where which column to play in
* @return the height of the column after playing
*
* @throws ColumnFullException if the requested column is full
* @throws ColumnOutOfBoundsException if the requested column does not exist
* @throws IllegalStateException if the game is over
* @throws IllegalStateException if it isn't {@code who}'s turn
*/
int move(Player who, int where) throws IllegalMoveException;
/**
* Indicates that the user attempted an illegal move.
*
* @see ColumnFullException
* @see ColumnOutOfBoundsException
*/
class IllegalMoveException extends Exception {}
/**
* Indicates that the user attempted to play in a column that was already
* full.
*/
class ColumnFullException extends IllegalMoveException {
/**
* Constructs a new {@code ColumnFullException} for the given column.
*
* @param column the number of the full column
*/
public ColumnFullException(int column) {
this.column = column;
}
public int getColumn() { return column; }
private final int column;
}
/**
* Indicates that the user attempted to play in a non-existent column.
*/
class ColumnOutOfBoundsException extends IllegalMoveException {
/**
* Constructs a new {@code ColumnOutOfBoundsException} parametrized by the
* given highest available column number.
*
* @param maxColumn the largest in-bounds column number
*/
public ColumnOutOfBoundsException(int maxColumn) {
this.maxColumn = maxColumn;
}
public int getMaxColumn() { return maxColumn; }
private final int maxColumn;
}
/**
* Builds a {@link Model}, allowing the client to configure several
* parameters. This is an instance of the builder pattern.
*/
interface Builder {
/**
* Builds and returns the specified {@link Model}.
* @return a new {@code ConnectNModel}
*/
Model build();
/**
* Sets the width of the game grid.
*
* @param width the width (positive)
* @return {@code this}, for method chaining
*/
Builder width(int width);
/**
* Sets the height of the game grid.
*
* @param height the height (positive)
* @return {@code this}, for method chaining
*/
Builder height(int height);
/**
* Sets the goal line length for the game.
*
* @param goal the goal (> 1)
* @return {@code this}, for method chaining
*/
Builder goal(int goal);
}
}