Joshua Hill
Joshua Hill

Reputation: 23

Instantiating a child class that extends an abstract class, the abstract class having a parameter pointing to another different abstract class

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

Answers (1)

Piotr Żmudzin
Piotr Żmudzin

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

Related Questions