import javax.swing.*; //for GUI components like JFrame, JPanel, JButton
import java.awt.*; // for creating buttons and other visual components like coc=lor font etc
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class GUI{ // The main class
private JButton[] buttons;
private char[] num = {'1','2','3','4','5','6','7','8','9'};
private char player, computer;
private ImageIcon playericon, computericon;
private boolean running = true;
public GUI() {
JFrame frame = new JFrame("Tic tac toe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //exits the frame when click on x
frame.setLayout(null); //used to automatically position the components in the frame but when set to null you need to set everything manually using .setBounds()
BackgroundPanel panel = new BackgroundPanel("ticbg.jpg");//panel is used to display buttons, label( which displays te text and images)
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //extend the frame to full screen
frame.setContentPane(panel); //add all the components(buttons) to the panel.
JButton button = new JButton(); //creates a new button
button.setBounds(637, 500, 89, 93);
button.setIcon(new ImageIcon("start button.png")); //add image to button
button.setBorder(BorderFactory.createEtchedBorder()); //for border decor
button.setFocusable(false); //removes the box that displays around the text in the button
button.addActionListener(e -> { //tells what to do when click on the button
SelectToken();
frame.dispose(); //used to close the window/ frame and in this code moves to another frame/screen/window
});
panel.add(button); // adding the button to the panel
frame.setVisible(true);// makes the frame visible
}
//it is called inner class
public class BackgroundPanel extends JPanel { //BackgroundPanel is a custom panel that extends JPanel to display background image
private Image backgroundImage;
public BackgroundPanel(String imagePath) {
backgroundImage = new ImageIcon(imagePath).getImage();
setLayout(null);
}
@Override
protected void paintComponent(Graphics g) { //overriding paintComponent that draws the bg image
super.paintComponent(g); //clears the background to draw the image
g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this); // draws the image
}
}
public void SelectToken(){
JFrame frame = new JFrame("Select Token");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BackgroundPanel panel2 = new BackgroundPanel("ticbg2.png");
frame.setContentPane(panel2);
frame.setLayout(null);
JButton button2 = new JButton();
button2.setBounds(650, 210, 98, 98);
button2.setIcon(new ImageIcon("X.png"));
button2.setBorder(BorderFactory.createEtchedBorder());
button2.setFocusable(false);
button2.addActionListener(e->{
player = 'X';
computer = 'O';
playericon = new ImageIcon("X.png");
computericon = new ImageIcon("O.png");
button2.setEnabled(false);
});
JButton button3 = new JButton("O");
button3.setBounds(650, 320, 98, 98);
button3.setIcon(new ImageIcon("O.png"));
button3.setBorder(BorderFactory.createEtchedBorder());
button3.setFocusable(false);
button3.addActionListener(e->{
player = 'O';
computer ='X';
playericon = new ImageIcon("O.png");
computericon = new ImageIcon("X.png");
button3.setEnabled(false); //disabling the button once it is clicked
});
JButton startgame = new JButton();
startgame.setBounds(558, 430, 280, 60);
startgame.setIcon(new ImageIcon("Play Now.png"));
startgame.setBorder(BorderFactory.createEtchedBorder());
startgame.setFocusable(false);
startgame.addActionListener(e->{
Gamegrid();
frame.dispose();
});
//adding buttons to the panel2 (panel of the second frame)
panel2.add(button2);
panel2.add(button3);
panel2.add(startgame);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
public void Gamegrid(){
JFrame frame = new JFrame("Grid");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
BackgroundPanel panel3 = new BackgroundPanel("ticbg2.png");
frame.setContentPane(panel3);
frame.setLayout(new GridLayout(3, 3));
buttons = new JButton[9]; //creating array of buttons to form a grid
for (int i = 0; i < 9; i++) {
buttons[i] = new JButton(String.valueOf(num[i]));
buttons[i].setFont(new Font("Arial", Font.PLAIN, 24));
buttons[i].setBorder(BorderFactory.createEtchedBorder());
buttons[i].setIcon(new ImageIcon("gridbg.png"));
buttons[i].setFocusable(false);
buttons[i].addActionListener(new ButtonListener());
panel3.add(buttons[i]);
}
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
//called inner class
private class ButtonListener implements ActionListener { //class to tell what to do when a button is clicked
public void actionPerformed(ActionEvent e) {
if (running) {
JButton button = (JButton) e.getSource(); //e.getSource(): This part retrieves the thing that caused the action, like clicking a button.
//(JButton): This part converts whatever e.getSource() returns into a type called JButton.
//button: This part assigns the result of the conversion to a variable called button, so you can work with it later, like changing its text or appearance.
int index = Integer.parseInt(button.getText()) - 1; //first it gets what is written on the button then converts it to integer and then decreases it by 1 to match with the num array indexes
if (num[index] == player || num[index] == computer) {
JOptionPane.showMessageDialog(null, "Invalid move! Please choose an empty cell.");
} else {
num[index] = player;
button.setIcon(playericon);
if (checkWinner()) {
running = false;
JOptionPane.showMessageDialog(null, "You win!");
} else if (checkTie()) {
running = false;
JOptionPane.showMessageDialog(null, "Game Draw :(");
} else {
ComputerMove();
}
}
} else {
JOptionPane.showMessageDialog(null, "Game over! Please restart to play again.");
}
}
}
public void ComputerMove() {
// Check for a winning move
for (int i = 0; i < 9; i++) {
if (num[i] >= '1' && num[i] <= '9') {
char original = num[i];
num[i] = computer;
if (checkWinner()) {
buttons[i].setIcon(computericon);
return; // Computer wins
}
num[i] = original; // Undo the move
}
}
if (num[4] >= '1' && num[4] <= '9') {
num[4] = computer;
buttons[4].setIcon(computericon);
return;
}
for (int i : new int[] { 0, 2, 6, 8 }) {
if (num[i] >= '1' && num[i] <= '9') {
num[i] = computer;
buttons[i].setIcon(computericon);
return;
}
}
for (int i : new int[] { 1, 3, 5, 7 }) {
if (num[i] >= '1' && num[i] <= '9') {
num[i] = computer;
buttons[i].setIcon(computericon);
return;
}
}
// If no winning move, make a random move
Random r = new Random();
int j;
do {
j = r.nextInt(9);
} while (num[j] == 'X' || num[j] == 'O');
num[j] = computer;
buttons[j].setIcon(computericon);
}
public boolean checkWinner() {
// Check rows, columns, and diagonals
for (int i = 0; i < 3; i++){
// Check rows
if (num[i * 3] == num[i * 3 + 1] && num[i * 3 + 1] == num[i * 3 + 2]){
if (num[i * 3] == player){
return true;
} else if( num[i * 3] == computer){
return true;
}
}
// Check columns
if (num[i] == num[i + 3] && num[i + 3] == num[i + 6]){
if (num[i * 3] == player){
JOptionPane.showMessageDialog(null, "You win :)");
return true;
} else if( num[i * 3] == computer){
JOptionPane.showMessageDialog(null, "Computer Wins >_<");
return true;
}
}
// Check diagonals
if ((num[0] == num[4] && num[4] == num[8]) || (num[2] == num[4] && num[4] == num[6])){
if (num[i * 3] == player){
JOptionPane.showMessageDialog(null, "You win :)");
return true;
} else if( num[i * 3] == computer){
JOptionPane.showMessageDialog(null, "Computer Wins >_<");
return true;
}
}
}
return false;
}
// Check if the game is tied
private boolean checkTie(){
for (int i = 0; i < 9; i++){
if (num[i] != 'X' && num[i] != 'O'){
return false;
}
}
JOptionPane.showMessageDialog(null, "Game Draw :(");
return true;
}
}
我想改进“ComputerMove”和“CheckWinner”逻辑。
我使用 Java 中的 GUI 制作了 tic_tac_toe 游戏作为学期项目的结束。 “CheckWInner”和“ComputerMove”方法中存在逻辑错误。我想改进这些方法的逻辑。您的帮助将不胜感激。我将在下周提交此代码。 我刚刚开始使用 java GUI,并且由于这段代码的长度而感到困惑。 我重用了上学期的 tic tac toe 代码(用 C++ 编写)。 问题: 主要问题是;
获胜条件后“谁是获胜者”检查的按钮索引是错误的。
// check rows
下面的 if 子句没问题,但是 // Check columns
和 Check diagonals
会考虑不包含获胜条件的单元格(num[i * 3]
而不是 num[i]
和 num[0]
)。