Reputation: 23
I am working on a project for my Object Orientated Java II course, and I am having trouble with starting it, as I can't seem to follow the logic of how the abstract classes I have to override with my own concrete classes are constructed (without running into a StackOverflowError). I am not allowed to declare any new state information in my concrete classes or modify the given abstract classes.
Here is the code for the abstract "Game" class:
public abstract class Game
{
protected Board board; // the board for this game
protected Player p1; // the game's first player
protected Player p2; // the game's other player
protected Player winner; // the game's winner
protected int score1; // p1's score
protected int score2; // p2's score
protected Player currentPlayer; // the player whose turn it is to play
/**
* Constructor for objects of class Game
*
* @param board an empty, game-specific board to play the
* game on
*/
public Game(Board board)
{
this.board = board;
board.setGame( this );
score1 = score2 = 0;
}// constructor
/**
* Plays an entire game
*/
public void play()
{
setUp();
board.display();
while (! gameOver() )
{
p1.playAMove();
board.display();
if (gameOver())
break;
p2.playAMove();
board.display();
}// main game loop
wrapUp();
}// play method
/**
* Sets up the board in its initial configuration as well as
* the two players of this game
*/
public abstract void setUp();
/**
* Determines whether or not the game has ended
*/
public abstract boolean gameOver();
/**
* Finishes the game after a tie or a win
*/
public abstract void wrapUp();
}
Here is the code for the abstract "Board" class:
public abstract class Board
{
protected Game game; // the game using this board
protected Piece[][] board; // the state of the board
protected int rows; // the vertical size of the board
protected int cols; // the horizontal size of the board
/**
* Constructor for objects of class Board
*
* @param game game the board is used for
* @param numRows number of rows of the board
* @param numColumns number of columns of the board
*/
public Board(Game game, int numRows, int numColumns)
{
this.game = game;
rows = numRows;
cols = numColumns;
board = new Piece[rows][cols];
}// constructor
/**
* Associates to this board the game that uses it
*
* @param game the game that uses this board
*/
public void setGame(Game game)
{
this.game = game;
}// setGame method
/**
* Returns the piece located at the given position or null
* if no piece is at that location; throws an exception if
* the location is off the board
*
* @param row the row index of the location
* @param column the column index of the location
* @return the piece at the given location or null
* if the location is empty
*/
protected Piece getPiece(int row, int column)
throws InvalidBoardPositionException
{
if (row < 0 || row >= rows || column < 0 || column >= cols)
throw new InvalidBoardPositionException(row,column);
return board[row][column];
}// getPiece method
/**
* Puts down the given piece at the given location; throws an
* exception if the location is off the board or already
* occupied
*
* @param piece the piece to place on the board
* @param row the row index of the target location
* @param column the column index of the target location
*/
protected void putPiece(Piece piece, int row, int column)
throws InvalidBoardPositionException
{
if ( row < 0 || row >= rows ||
column < 0 || column >= cols ||
! isEmpty(row,column) )
throw new InvalidBoardPositionException(row,column);
board[row][column] = piece;
}// putPiece method
/**
* Removes from the board the piece at the given location;
* throws an exception if the location is off the board or empty
*
* @param row the row index of the target location
* @param column the column index of the target location
*/
protected void removePiece(int row, int column)
throws InvalidBoardPositionException
{
if ( row < 0 || row >= rows ||
column < 0 || column >= cols ||
isEmpty(row,column) )
throw new InvalidBoardPositionException(row,column);
board[row][column] = null;
}// removePiece method
/**
* Returns true if and only if the specified location is
* empty
*
* @param row row index of the location being checked
* @param col column index of the location being checked
* @return true if and only if there is no piece at
* the location being checked
*/
protected boolean isEmpty(int row, int col)
{
return board[row][col] == null;
}// isEmpty method
/**
* Displays the board on the terminal window
*/
protected abstract void display();
}
I have to extend both classes (GGame extends Game, GBoard extends Board), and use this code in GGame to start the program:
public static void newGame()
{
new GGame().play();
}
There are other classes, but all I care about for now is actually getting the program to create an instance of "GGame" so I can move forward. I've tried doing this:
/**
* Constructor
*/
public GGame() //needs to have no parameters
{
super(new GBoard());
}
However, the constructor of the abstract "Board" class (which "GBoard" has to extend) requires an instance of "Game" to be passed to it. But if I pass an instance of "GGame" into the "GBoard" constructor it loops infinitely as new GGame()
and new GBoard()
call each other.
I'll take any ideas about what I can do, and will provide more info if necessary. I don't want someone to do the project for me, I'm just legitimately stuck and don't know how to proceed. I'm sure I'm missing something.
Upvotes: 2
Views: 148
Reputation: 154
If you don't want to modify the implementation of abstract classes, you must pass null
to the constructor of the superclass as follows:
class BoardImpl extends Board {
BoardImpl() {
super(null, a, b);
}
}
class GameImpl extends Game {
GameImpl(Board board) {
super(board);
}
}
and then pass the Board instance to the Game constructor:
Board board = new BoardImpl();
Game game = new GameImpl(board);
also note that passing this
in the class constructor like this:
public Game(Board board)
{
this.board = board;
board.setGame( this );
score1 = score2 = 0;
}
is a very bad practice because at the time of passing this
instance is not yet fully constructed.
Upvotes: 1