I am making a tic-tac-toe Java application using Swing for the GUI. My game functions properly when I play as O, but if I choose X and the game board fills up the program freezes without ever filling in the last box and displaying either the win or tie message. I have to close the program from the IDE when it freezes. My code is below would appreciate any feedback.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class TicTacToe implements ActionListener {
Random rand = new Random();
JFrame frame;
JPanel inputPanel;
JPanel board;
JButton X;
JButton O;
JLabel xOro;
JButton[] buttons = new JButton[9];
String player1;
String computer;
boolean playerTurn;
boolean hasWinner = false;
public TicTacToe(){
frame = new JFrame();
//Top of the board where player decides to play x or o
inputPanel = new JPanel(new BorderLayout());
X = new JButton("X");
X.addActionListener(this);
O = new JButton("O");
O.addActionListener(this);
xOro = new JLabel("Do you wan to play X or O?");
xOro.setHorizontalAlignment(SwingConstants.CENTER);
inputPanel.add(xOro, BorderLayout.NORTH);
inputPanel.add(X, BorderLayout.WEST);
inputPanel.add(O, BorderLayout.EAST);
//Adding the panel of buttons to the board
board = new JPanel(new GridLayout(3,3));
for(int i = 0; i < buttons.length; i ){
buttons[i] = new JButton();
buttons[i].addActionListener(this);
board.add(buttons[i]);
}
board.setVisible(false);
frame.add(inputPanel, BorderLayout.NORTH);
frame.add(board, BorderLayout.SOUTH);
frame.setSize(250,175);
frame.setTitle("Tic Tac Toe");
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new Moser_Problem1();
}
@Override
public void actionPerformed(ActionEvent e) {
//Checking which button is pressed to assign player to X or O.
if(e.getSource() == X){
player1 = "X";
computer = "O";
playerTurn = true;
board.setVisible(true);
} else if(e.getSource() == O){
player1 = "O";
computer = "X";
playerTurn = false;
board.setVisible(true);
}
//After player chooses which to play as, this will check to see which value should go in the button based on whose turn it is.
else{
JButton src = (JButton) e.getSource();
if(playerTurn) {
src.setText(player1);
winCheck(player1);
tieCheck();
}
else{
src.setText(computer);
}
//Changing player turn from false to true or vice versa at the end of each turn
playerTurn = !playerTurn;
}
//Gets rid of the input panel once the player chooses X or O.
if(!player1.equals("")){
inputPanel.setVisible(false);
}
//Computer turn logic
if(!playerTurn){
int choice = rand.nextInt(9);
JButton src = buttons[choice];
while(!src.getText().equals("")){
choice = rand.nextInt(9);
src = buttons[choice];
}
src.setText(computer);
winCheck(computer);
tieCheck();
playerTurn = !playerTurn;
}
//After there is a winner, either create a new game window or close the window and end the program
if(hasWinner){
if(e.getSource() == X){
new Moser_Problem1();
frame.dispose();
} else if(e.getSource() == O){
frame.dispose();
}
}
}
public void winCheck(String player) {
//All possible winning combos for tic-tac-toe board.
if(buttons[0].getText().equals(player) && buttons[1].getText().equals(player) && buttons[2].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[3].getText().equals(player) && buttons[4].getText().equals(player) && buttons[5].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[6].getText().equals(player) && buttons[7].getText().equals(player) && buttons[8].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[0].getText().equals(player) && buttons[3].getText().equals(player) && buttons[6].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[1].getText().equals(player) && buttons[4].getText().equals(player) && buttons[7].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[2].getText().equals(player) && buttons[5].getText().equals(player) && buttons[8].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[0].getText().equals(player) && buttons[4].getText().equals(player) && buttons[8].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else if(buttons[6].getText().equals(player) && buttons[4].getText().equals(player) && buttons[2].getText().equals(player)){
xOro.setText(player " wins!\n Do you want to play again?");
player1 = "";
inputPanel.setVisible(true);
X.setText("Yes");
O.setText("No");
hasWinner = true;
} else{
hasWinner = false;
}
}
public void tieCheck(){
//Checks for a tie by adding getting the text from each box and making sure none are empty.
//If one is empty, nothing will happen, but if there are no empty spaces will print out a tie message.
boolean hasEmptySpot = false;
for (JButton button : buttons) {
String check = button.getText();
if (check.equals("")) {
hasEmptySpot = true;
}
}
if(!hasEmptySpot){
xOro.setText("It's a tie!\n Would you like to play again?");
X.setText("Yes");
O.setText("No");
player1 = "";
inputPanel.setVisible(true);
hasWinner = true;
}
}
}
There are no exceptions or errors when the program runs, but for some reason filling up the board playing as x freezes the whole program.
CodePudding user response:
[...] but for some reason filling up the board playing as x freezes the whole program.
The problem is the while
loop you have:
int choice = rand.nextInt(9);
JButton src = buttons[choice];
while(!src.getText().equals("")){
choice = rand.nextInt(9);
src = buttons[choice];
}
This will pick a random free button. But you are entering this while
loop when the game is complete, specially when there is no winner (a draw). This means that you are trying to find a free button, but there is none. So your event handler for the JButton
get stuck inside the while()
loop, blocking the whole GUI thread.
You must not find a next move for the computer player, when the board is completely filled.