2017-10-09 53 views
0

幾年前,我做了一個GUI TicTacToe遊戲,想重做它,因爲我現在有更多的編程技巧。我能夠將代碼從600行縮減到大約150行。Java TicTacToe程序觸發非贏組合

雖然我使用了相同的方案,但遇到了一些我無法解決的問題,請幫助我。

該計劃包括兩個類,主類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); 
     } 
    } 
} 

現在讓我解釋的程序是如何工作的。 3x3運動場由ButtonArray btnPlayButton組成。這些按鈕是,它們的標籤相比較,因此在遊戲開始時沒有匹配的標籤,創建時按鈕從1到9正確標記。在這裏:

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

每當你點擊一個btnPlayButton,程序跳轉到actionPerformed方法。由於btnPlayButtons沒有ActionCommand,因此它跳轉到方法的else部分。在這裏,int buttonCounter得到大於1. Wether buttonCounter是偶數或奇數,被點擊的btnPlayButton被重新標記爲「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(),或者更準確地說,ButtonsWithIdenticalLabels(x, y, z)的的btnPlayButtons[x]btnPlayButtons[y]btnPlayButtons[z]採取比較,如果相同則返回true標籤。

由於btnPlayButton排序是這樣的:

0 1 2 
3 4 5 
6 7 8 

獲勝組合是:012,345,678,036,147,258,045和246

如此,例如,當btnPlayButton[0]btnPlayButton[1]btnPlayButton[2]都具有相同的標籤。 ButtonsWithIdenticalLabels是真的,程序跳轉到Deactivatebuttons()所有btnPlayButton都被禁用,意味着獲勝的組合被發現,遊戲結束。如果btnPlayButton[1]的標籤是「X」,那麼int xScore將被添加1。另外btnPlayButton[0],btnPlayButton[1]btnPlayButton[2]被塗成紅色以增加美感。

使用重新啓動按鈕,您跳入一個for循環,該循環再次重新標記btnPlayButton並將它們添加到實現到TTTFrame中的ActionListenerbuttonCounter也重置爲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; 
      } 

現在的問題是,我是,那幾個重新啓動後,X和O的標籤不交了。有時也有3個OS在一排,有時甚至字段這樣越來越公認的奪冠

Picture

如果有人知道如何解決這個錯誤,我會很高興。

由於提前,

Fihdi

+2

有了這個問題的代碼很多,你不太可能在這裏得到幫助。你是否試圖自己調試它?這應該可以幫助您找到錯誤,並在此處回答更具體的問題。 –

+4

歡迎來到Stack Overflow! 請參考[遊覽](/遊覽),環顧四周,閱讀[幫助中心](/幫助),特別是[如何提出一個好問題?](/ help/how-to-問)和[我可以在這裏問什麼問題?](/幫助/話題)。請閱讀(並遵循) [Java命名約定](http://www.oracle.com/technetwork/java/codeconventions-135099.html) –

+0

https://ericlippert.com/2014/03/05/how -to-debug-small-programs/ – slim

回答

1

這裏的問題是:當你重新開始遊戲,一個新的ActionListener被添加到每個按鈕。然而,只有當你點擊它或當某人贏得比賽時,它纔會被刪除。這意味着當您在任何人獲勝之前重新開始遊戲時,每個未點擊的按鈕都會獲得第二個ActionListener,因此點擊將被註冊兩次並出現此錯誤。嘗試致電DeactivateButtons(),然後重置電路板。