0

I am making a Tic-Tac-Toe game in Java. I have four classes: TicTacTester just calls (creates an object) the TicTacToe class. The TicTacToe class provides the GUI of the game (it's a subclass of JFrame). It also creates the 9 buttons for the JPanel to display and users to click. The XOButton class defines what the buttons can do and actionPerformed method. Lastly, the GameEnd class defines what happens when the game ends (a new JFrame is created to display score and give the user 2 buttons: exit and restart).

The problem is when I try to code the contents of what happens when the user clicks "restart". It is suppose to call the resetBoard() method, which is defined in TicTacToe class. The problem is, I do not know the name of the object created from the TicTacToe class (in the tester class' static void main method I just typed "new TicTacToe", didn't need to define a name). I cannot call resetBoard from a static standpoint (i.e. I can't do TicTacToe.resetBoard(); ) because resetBoard needs to be non-static.

What I've tried: I've tried including in the constructor of the GameEnd class a TicTacToe object. If I do this, the GameEnd object creator has to go into TicTacToe class, so I can use 'this' keyword. This does not work because the GameEnd object needs to be created when the WinCondition is met, which is checked when a button is clicked in the XOButton class.

But if I put the GameEnd object creator in the XOButton class (where is is right now and, supposedly, where it should be), in the constructor for GameEnd(String s, TicTacToe a), I cannot use 'this' keyword for the TicTacToe object.

This is my button class. Most code is not relevant so it has been hidden.


public class XOButton extends JButton implements ActionListener {

//Hidden code
    private void winCheck() {
        for(int j = 0; j < 3; j++) {
            if(board[j][0] == 1 && board[j][1] == 1 && board[j][2] == 1 || board[0][j] == 1 && board[1][j] == 1 && board[2][j] == 1) {
                player1Score++;
                GameEnd end = new GameEnd("X wins this round!");
                finished = true;
                break;
            }
            else if(board[j][0] == 2 && board[j][1] == 2 && board[j][2] == 2 || board[0][j] == 2 && board[1][j] == 2 && board[2][j] == 2) {
                player2Score++;
                GameEnd end = new GameEnd("O wins this round!");
                finished = true;
                break;
            }
        }

        if(board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1 || board[0][2] == 1 && board[1][1] == 1 && board[2][0] == 1) {
            player1Score++;
            GameEnd end = new GameEnd("X wins this round!");
            finished = true;
        }
        else if(board[0][0] == 2 && board[1][1] == 2 && board[2][2] == 2 || board[0][2] == 2 && board[1][1] == 2 && board[2][0] == 2) {
            player2Score++;
            GameEnd end = new GameEnd("O wins this round!");
            finished = true;
        }
        if(turn == 9 && !finished) {
            GameEnd end = new GameEnd("This round is a Draw");
            finished = true;
        }

    }

    public void resetButton() {
        this.setIcon(null);
        markSpot(0);
        this.clicked = false;
    }

    public static void resetStatics() {
        turn = 0;
        finished = false;
    }

}

This is the TicTacToe class. Most code is not relevant so it has been hidden.


public class TicTacToe extends JFrame {

//Hidden code

    public void resetBoard() {
        for(int j = 0; j < 3; j++) {
            for(int i = 0; i < 3; i++) {
                buttons[j][i].resetButton();
            }
        }
        XOButton.resetStatics();
    }


}

This is the GameEnd class. An object of this is created when the WinCondition is met. Most code is not relevant so it has been hidden.

public class GameEnd extends JFrame implements ActionListener {

//Hidden code

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == exit) {
            System.exit(0);
        }
        else if(e.getSource() == retry) {
            TicTacToe.resetBoard();
        }

    }

}

//This is the Tester class

public class TicTacTester {
    public static void main(String[] args) {
        new TicTacToe();
    }
}

What I expect to happen is the game board to restart.

  • 1) For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) A single blank line of white space in source code is all that is *ever* needed. Blank lines after `{` or before `}` are also typically redundant. 3) See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/q/9554636/418556) 4) But don't extend `JFrame` or other GUI components unless there is a **specific* need to change existing behavior! 5) `if(e.getSource() == exit) { System.exit(0);` The simpler way is .. – Andrew Thompson May 27 '19 at 03:24
  • .. `frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);` 6) `GameEnd` I doubt this needs to be a class at all. Instead of calling it, show an appropriate `JOptionPane`. – Andrew Thompson May 27 '19 at 03:24
  • @AndrewThompson I am a little bit confused. If I were to use a JOptionPane instead of a GameEnd class, where would the JOptionPane be used? Would I initialize and configure/design it in the XOButton class where the WinCondition is or in the TicTacToe class? – Dhruv Patel May 27 '19 at 04:26
  • *".. where would the JOptionPane be used?"* You'd call it from any line of the code that has `new GameEnd(..);` – Andrew Thompson May 27 '19 at 04:28

1 Answers1

1

It seems like you are breaking the project down too far. If you have a class for a game, keep all of its methods inside that class. The only time I can think of to use separate classes are if you are trying to create this using the Model-View-Controller (MVC) architecture, or the like. This is a common approach for an application using GUI, data access, and controllers.

There might be other times, but this is all I can think of on the top of my head.

From what you are showing, I don't think it applies.


I think this would be a better approach:

TicTacToe.java

public class TicTacToe extends JFrame {
    private int scorePlayer1;
    private int scorePlayer2;
    private boolean initialized;    // default = false

    // Reset the board
    // Reset the markers, etc.
    public void resetGame() {}

    // Check to see if there is a winner
    // If so, announce the winner and return true
    // Otherwise, return false.
    public boolean winCheck() {}

    // Set up frame, buttons, score, etc.
    public void newGame(){
        // Create however many JPanels you need
        // Add it to a single JFrame

        // When you're ready...
        // and this game has not been initialized for the first time.
        // In this example jframe is an instance of JFrame
        if (!this.initialized)
            jframe.setVisible(true);
    }

    // Play the game
    public void play(){
        // For each round,
        // a player chooses where to put their "X" or "O"
        // add scores, etc.

        // Then at the end of each round
        if (this.winCheck())
            this.resetGame();
    }
}

TicTacToeTester.java:

public class TicTacToeTester {
    public static void main(String[] args){
        TicTacToe game = new TicTacToe();
        game.play();
    }
}

I hope this helps!

Let me know if you have any questions. :)

Community
  • 1
  • 1
Sometowngeek
  • 597
  • 1
  • 6
  • 27
  • I would still need a button class, correct? Also how would I display the Win-screen without another JFrame? – Dhruv Patel May 27 '19 at 04:35
  • @DhruvPatel, you can create an `XOButton` class if you want it to do specific things... I doubt it'll be necessary in this case if it only places the marker and you're using a logic to manipulate the player's score. If you decide to use a class for the button, you could. But checking for a winning game should remain in the main `TicTacToe` class because it determines whether there's a winner of the **game**, not the **button**. Does that help? – Sometowngeek May 27 '19 at 04:50
  • Regarding the JFrame, a JFrame is enough to display the window. I'll update my answer. – Sometowngeek May 27 '19 at 04:51
  • @DhruvPatel I've updated my answer... Let me know if this helps or if you need more help :) – Sometowngeek May 27 '19 at 05:07
  • So if I had a method in TicTacToe for winChecking, how would I be able to call it? I need to run "winCheck" every time ActionPerformed is executed (i.e. every time a user chooses a square). I cannot call a method from TicTacToe class in the ActionPerformed method because the actionperformed method belongs to the Button class while the winCheck belongs to the TicTacToe class. – Dhruv Patel May 27 '19 at 14:45
  • @DhruvPatel That won't work... Like I said in my first comment, `winCheck` should be inside the **TicTacToe** class, not **XOButton**. Which is why I added the `play()` method in the TicTacToe class. – Sometowngeek May 27 '19 at 15:57
  • @DhruvPatel Hold on... I think I see a way to add **XOButton**. Give me a sec. – Sometowngeek May 27 '19 at 16:25
  • @DhruvPatel If you'd like to place `winCheck()` in **XOButton**, you actually can. Here's how. https://gist.github.com/sometowngeek/5f0de509a1c93bb87dffcb3f06918a95 – Sometowngeek May 27 '19 at 16:30
  • If you'd like me to update my answer with that code, let me know. – Sometowngeek May 27 '19 at 16:30