Java TictaToe程序在非获胜组合时触发

Java TictaToe程序在非获胜组合时触发,java,tic-tac-toe,Java,Tic Tac Toe,几年前我做了一个GUI Tictaoe游戏,现在我有了更多的编程技能,所以我想重做它。我能够将代码从600行压缩到150行左右 当我使用相同的方案时,我遇到了一些我自己无法解决的问题,所以请帮我解决 该程序由两个类组成,主类TTTMain: public class TTTMain { public static void main(String[] args) { TTTFrame tttf = new TTTFrame(0,0); /*Tic Tac Toe Fi

几年前我做了一个GUI Tictaoe游戏,现在我有了更多的编程技能,所以我想重做它。我能够将代码从600行压缩到150行左右

当我使用相同的方案时,我遇到了一些我自己无法解决的问题,所以请帮我解决

该程序由两个类组成,主类
TTTMain

public class TTTMain {

public static void main(String[] args) {
    TTTFrame tttf = new TTTFrame(0,0);
    
    /*Tic Tac Toe Field:
     *  0 1 2
     *  3 4 5
     *  6 7 8
    */
    
}}
TTTFrame

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TTTFrame extends JFrame implements ActionListener {

    private Button[] btnPlayButton;
    private Button btnRestart;
    private int buttonCounter;
    private int xScore;
    private int oScore;
    private Label Olabel, Xlabel;

    TTTFrame(int xScore, int oScore) {

        this.xScore = xScore;
        this.oScore = oScore;

        btnPlayButton = new Button[9];
        for (int i = 0; i < 9; i++) {
            btnPlayButton[i] = new Button("" + i);
            btnPlayButton[i].setBackground(Color.white);
            btnPlayButton[i].setForeground(Color.white);
            btnPlayButton[i].addActionListener(this);
            this.add(btnPlayButton[i]);
        }

        Xlabel = new Label("X: " + this.xScore);
        Xlabel.setFont(new Font("Arial", Font.BOLD, 24));
        Xlabel.setForeground(Color.white);
        Xlabel.setBackground(Color.black);
        this.add(Xlabel);

        btnRestart = new Button("Restart");
        btnRestart.setActionCommand("Restart");
        btnRestart.setFont(new Font("Arial", Font.PLAIN, 18));
        btnRestart.addActionListener(this);
        this.add(btnRestart);

        Olabel = new Label("O: " + this.oScore);
        Olabel.setFont(new Font("Arial", Font.BOLD, 24));
        Olabel.setForeground(Color.white);
        Olabel.setBackground(Color.black);
        this.add(Olabel);

        this.setLayout(new GridLayout(4, 3));
        this.pack();
        this.setResizable(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Tic Tac Toe");
        this.setSize(300, 400);
        this.getContentPane().setBackground(Color.black);
        this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getActionCommand().equals("Restart")) {
            System.out.println("Restarted");
            for (int i = 0; i < 9; i++) {

                btnPlayButton[i].setLabel("" + i);
                btnPlayButton[i].setForeground(Color.white);
                btnPlayButton[i].setBackground(Color.white);
                btnPlayButton[i].addActionListener(this);

                this.buttonCounter = 0;
            }
        } else {

            ((Button) e.getSource()).setFont(new Font("Arial", Font.BOLD, 48));
            ((Button) e.getSource()).setForeground(Color.black);
            System.out.println(buttonCounter);
            if (buttonCounter % 2 == 0) {
                ((Button) e.getSource()).setLabel("X");
                ((Button) e.getSource()).removeActionListener(this);
            } else {
                ((Button) e.getSource()).setLabel("O");
                ((Button) e.getSource()).removeActionListener(this);
            }
            buttonCounter++;
            CheckField();
        }

    }

    private void CheckField() {

        if (ButtonsWithIdenticalLabels(0, 1, 2)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(3, 4, 5)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(6, 7, 8)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(0, 3, 6)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(1, 4, 7)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(2, 5, 8)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(0, 4, 8)) {

            Deactivatebuttons();
        }
        if (ButtonsWithIdenticalLabels(2, 4, 6)) {

            Deactivatebuttons();
        }
    }

    private boolean ButtonsWithIdenticalLabels(int i, int j, int k) {
        if (btnPlayButton[i].getLabel() == btnPlayButton[j].getLabel()
                && btnPlayButton[j].getLabel() == btnPlayButton[k].getLabel()) {
    
            btnPlayButton[i].setBackground(Color.red);
            btnPlayButton[j].setBackground(Color.red);
            btnPlayButton[k].setBackground(Color.red);

            if (btnPlayButton[i].getLabel().equals("X")) {
                xScore++;
                Xlabel.setText("X: " + xScore);
            } else {
                oScore++;
                Olabel.setText("O: " + oScore);
            }

            return true;
        } else {
            return false;
        }
    }

    private void Deactivatebuttons() {
        for (int i = 0; i < 9; i++) {
            btnPlayButton[i].removeActionListener(this);
        }
    }
}
无论何时单击
btnplay按钮
,程序都会跳入
actionPerformed
方法。由于
btnPlayButtons
没有
ActionCommand
,因此它直接跳转到方法的else部分。这里,int
buttonCounter
的值大于1。无论
按钮计数器
是偶数还是奇数,被单击的BTN显示按钮都会重新标记为“X”或“O”。由于
buttonCounter
每次单击都会获得+1,因此X和Os是交替的

下面是一节:

else {

    ((Button) e.getSource()).setFont(new Font("Arial", Font.BOLD, 48));
    ((Button) e.getSource()).setForeground(Color.black);
    System.out.println(buttonCounter);
    if (buttonCounter % 2 == 0) {
        ((Button) e.getSource()).setLabel("X");
        ((Button) e.getSource()).removeActionListener(this);
    } else {
        ((Button) e.getSource()).setLabel("O");
        ((Button) e.getSource()).removeActionListener(this);
    }
    buttonCounter++;
    CheckField();
}
单击按钮的
ActionListener
将被删除,以防止作弊。每按一次按钮,都会检查比赛场地是否有获胜的组合。这发生在
CheckField()

CheckField()
中,或者更准确地说,
按钮具有相同的标签(x,y,z)
将获取并比较
btnPlayButtons[x]
btnPlayButtons[y]
btnPlayButtons[z]
的标签,如果它们相同,则返回true

由于btnPlayButton的顺序如下:

0 1 2
3 4 5
6 7 8
获奖组合为:012345678036147258045和246

因此,例如,当
btnPlayButton[0]
时,
btnPlayButton[1]
btnPlayButton[2]
都具有相同的标签
ButtonsWithIdenticalLabels
为真,程序跳入
Deactivatebuttons()
,所有
btnPlayButton
都被禁用,这意味着找到了一个获胜的组合,游戏结束。如果
btnPlayButton[1]
的标签为“X”,则
int-xScore
会向其添加1。此外,
btnPlayButton[0]
btnPlayButton[1]
btnPlayButton[2]
为美观起见,将其涂成红色

使用Restart按钮,您跳入一个for循环,该循环再次重新标记btnPlayButton,并将它们添加到TTTFrame中实现的
ActionListener
<代码>按钮计数器也将重置为0。重新标记与课程开始时的标记相同:

if (e.getActionCommand().equals("Restart")) {
            System.out.println("Restarted");
            for (int i = 0; i < 9; i++) {

                btnPlayButton[i].setLabel("" + i);
                btnPlayButton[i].setForeground(Color.white);
                btnPlayButton[i].setBackground(Color.white);
                btnPlayButton[i].addActionListener(this);

                this.buttonCounter = 0;
            }
if(如getActionCommand().equals(“重启”)){
System.out.println(“重新启动”);
对于(int i=0;i<9;i++){
btnPlayButton[i].setLabel(“+i”);
btnPlayButton[i].setForeground(颜色.白色);
btnPlayButton[i].背景设置(颜色.白色);
btnPlayButton[i].addActionListener(此);
this.buttonCounter=0;
}
现在的问题是,在重新启动几次之后,X和O的标记不再交替。有时一行有3个Os,有时甚至像这样的字段也被认为是一个胜利

如果有人知道如何修复这个错误,我会非常高兴

提前感谢,


Fihdi

这里的问题是:当你重新启动游戏时,每个按钮都会添加一个新的
ActionListener
。但是,只有当你点击它或有人赢了游戏时,它才会被删除。这意味着当你在任何人赢之前重新启动游戏时,每个未点击的按钮都会有第二个
ActionListener
,因此点击将被删除注册两次,出现此错误。请尝试调用
DeactivateButtons()
重置电路板之前。

问题中有这么多代码,您不太可能在这里得到帮助。您已经尝试过自己调试它了吗?这应该可以帮助您找到错误,并在这里返回一个更具体的问题。欢迎使用堆栈溢出!请阅读,四处看看,特别是阅读r和。请阅读(并遵循)这里的主要问题是,您的整个游戏都包含在一个类中。进行重构,您可能会发现问题。如果您继续以相同的方式开发,您将遇到更多的问题,这将更难修复
if (e.getActionCommand().equals("Restart")) {
            System.out.println("Restarted");
            for (int i = 0; i < 9; i++) {

                btnPlayButton[i].setLabel("" + i);
                btnPlayButton[i].setForeground(Color.white);
                btnPlayButton[i].setBackground(Color.white);
                btnPlayButton[i].addActionListener(this);

                this.buttonCounter = 0;
            }