2016-06-22 7 views
1

Ich versuche derzeit, ein Spiel des Lebens Umsetzung zu entwickeln. Ich habe Lösungen für fast jedes Problem gefunden, aber ich kämpfe mit den "Mustern". Fast alles, was ich ausprobiert habe, bietet nicht die richtigen Muster wie den "Blinker". Ich denke, dass die GUI/Swing aufgrund einer Verzögerung der Grund für die falschen Muster sein könnte, aber ich bin mir nicht sicher oder sogar eine Möglichkeit, das zu beheben.Game of Life Probleme mit Struktur nicht Swing bezogen

Ich werde einen Screenshot der statischen Muster und meines aktuellen Codes anhängen. Jeder Rat wird geschätzt. Das implementierte Strategy Interface bietet nur einige Integer (3 = MAX, 2 = MIN). Um mit Schnittstellen arbeiten zu können.

GameOfLife Patterns

GameOfLifeFrame

public class GameOfLifeFrame extends JFrame implements ActionListener{ 
    private GameOfLifeBoard gameBoard; 
    private GameOfLifeInterface gameInterface; 
    private JPanel btnPanel; 
    private JPanel jPanel; 
    private JMenuBar jMenuBar; 
    private JMenu jMenu; 
    private JButton btnStart; 
    private JButton btnStop; 

private JMenuItem jMenuItemStart; 
private JMenuItem jMenuItemStop; 
private JMenuItem jMenuItemReset; 
private JMenuItem jMenuItemExit; 
* Constructor 
*/ 
public GameOfLifeFrame(){ 
    initComponents(); 
} 

private void initComponents(){ 
    gameBoard = new GameOfLifeBoard(); 
    gameInterface = new GameOfLifeInterface(gameBoard); 
    add(gameInterface); 

    btnPanel = new JPanel(); 
    jPanel = new JPanel(); 
    setJMenu(); 

    setButtons(); 

    setTitle("Game of Life"); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setLocationByPlatform(true); 

    Dimension minDim = new Dimension(500,500); 
    Dimension prefDim = new Dimension(500,500); 
    setMinimumSize(minDim); 
    setPreferredSize(prefDim); 

    add(jMenuBar, BorderLayout.PAGE_START); 
    add(jPanel, BorderLayout.NORTH); 
    add(btnPanel, BorderLayout.SOUTH); 

    pack(); 
    setVisible(true); 
} 

/** 
* private void setJMenu 
* Creates JMenu for GameOfLife Frame 
*/ 
private void setJMenu(){ 
    jMenuBar = new JMenuBar(); 
    jMenu = new JMenu("Menü"); 
    jMenuItemStart = new JMenuItem("Start"); 
    jMenuItemStop = new JMenuItem("Stop"); 
    jMenuItemReset = new JMenuItem("Zurücksetzen"); 
    jMenuItemExit = new JMenuItem("Verlassen"); 

    //Menu ActionListener 
    jMenuItemStart.addActionListener(this); 
    jMenuItemStop.addActionListener(this); 
    jMenuItemReset.addActionListener(this); 
    jMenuItemExit.addActionListener(this); 

    //Adding MenuItem to Menu & Menu to MenuBar 
    jMenu.add(jMenuItemStart); 
    jMenu.add(jMenuItemStop); 
    jMenu.add(jMenuItemReset); 
    jMenu.add(jMenuItemExit); 
    jMenuBar.add(jMenu); 
} 

/** 
* actionPerformed 
* get Action on GUI. Reaction depends on Buttons. 
* 
* @param e ActionEvent 
*/ 
@Override 
public void actionPerformed(ActionEvent e){ 
    if(e.getSource() == jMenuItemStart){ 
     gameInterface.setActivity(true); 
     if(btnStart.getText() == "Resume"){ 
      btnStart.setText("Start"); 
     } 
    } 
    else if(e.getSource() == jMenuItemStop){ 
     gameInterface.setActivity(false); 
     if(btnStart.getText() == "Start"){ 
      btnStart.setText("Resume"); 
     } 
    } 
    else if(e.getSource() == jMenuItemReset){ 
     gameBoard.setGameBoard(gameBoard.clearGameBoard()); 
     if(!(btnStart.getText() == "Start")){ 
      btnStart.setText("Start"); 
     } 
     gameBoard.randomize(); 
    } 
    else if(e.getSource() == jMenuItemExit){ 
     System.exit(0); 
    } 
    else if(e.getSource() == btnStart){ 
     gameInterface.setActivity(true); 
     if(btnStart.getText() == "Resume"){ 
      btnStart.setText("Start"); 
     } 
    } 
    else if(e.getSource() == btnStop){ 
     gameInterface.setActivity(false); 
     btnStart.setText("Resume"); 
    } 
} 

/** 
* setButtons 
* sets Buttons Start and Stop and adds them to the Panel & ActionListener 
*/ 
private void setButtons(){ 
    btnStart = new JButton("Start"); 
    btnStop = new JButton("Stop"); 
    btnPanel.add(btnStart); 
    btnPanel.add(btnStop); 
    btnStart.addActionListener(this); 
    btnStop.addActionListener(this); 
} 

/** 
* Main Method, creates an instance of GameOfLifeFrame(GameOfLifeBoard) 
* @param args Main Method 
*/ 
public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      new GameOfLifeFrame(); 
     } 
    }); 
} 

}

GameOfLifeBoard

public class GameOfLifeBoard implements Strategy { 
    private boolean[][] gameBoard; 

public GameOfLifeBoard() { 
    this.gameBoard = new boolean[ROW][COL]; 
    for (int i = 0; i < gameBoard.length; i++) { 
     for (int j = 0; j < gameBoard[i].length; j++) { 
      gameBoard[i][j] = false; 
     } 
    } 
} 

/** 
* getGameBoard 
* @return gameBoard 
*/ 
boolean[][] getGameBoard(){ 
    return gameBoard; 
} 

/** 
* setGameBoard 
* @param boolArray two-dimensional Array 
*/ 
void setGameBoard(boolean[][] boolArray){ 
    for (int i = 0; i < boolArray.length; i++){ 
     for (int j = 0; j < boolArray[i].length; j++){ 
      gameBoard[i][j] = boolArray[i][j]; 
     } 
    } 
} 

/** 
* clearGameBoard clears the current gameBoard by setting all boolean to false 
* @return clGameBoard returns a blank gameBoard 
*/ 
boolean[][] clearGameBoard(){ 

    for (int i = 0; i < gameBoard.length; i++) { 
     for (int j = 0; j < gameBoard[i].length; j++) { 
      gameBoard[i][j] = false; 
     } 
    } 
    return gameBoard; 
} 

/** 
* nextGeneration calculates the new Generation (gameBoard) 
* using the static variables 3 and 2 (MAX and MIN) from Strategy (interface) 
* by applying the rules from Strategy 
* 
* nextGeneration uses a temporary 2D boolean Array to replace the old Generation with the new Generation 
* by looping through the current gameBoard and replacing each cell with the new status of the cell 
* in the new generation 
*/ 
void nextGeneration(){ 
    boolean[][] newGen = new boolean[ROW][COL];; 

    for (int i = 0; i < gameBoard.length; i++) { 
     for (int j = 0; j < gameBoard[i].length; j++) { 

      newGen[i][j] = gameBoard[i][j]; 

      switch (getAliveNeighbourCells(i,j)){ 
       case MAX: 
        if(getCellState(i,j)){ 
         newGen[i][j] = true; 
        } 
        else if(!getCellState(i,j)){ 
         newGen[i][j] = true; 
        } 
        break; 
       case MIN: 
        if(getCellState(i,j)){ 
         newGen[i][j] = true; 
        } 
        else if(!getCellState(i,j)){ 
         newGen[i][j] = false; 
        } 
        break; 
       default: 
        newGen[i][j] = false; 
        break; 
      } 
     } 
    } 
    for (int i = 0; i < gameBoard.length; i++) { 
     for (int j = 0; j < gameBoard[i].length; j++) { 
      gameBoard[i][j] = newGen[i][j]; 
     } 
    } 

} 

/** 
* randomize randomizes each cell on the gameBoard by setting it to true or false (25% true) 
*/ 
void randomize(){ 
    for(int i = 0; i < gameBoard.length; i++){ 
     for(int j = 0; j < gameBoard[i].length; j++){ 
      double d = Math.random(); 
      if(d <= 0.25){ 
       gameBoard[i][j] = true; 
      } 
      else{ 
       gameBoard[i][j] = false; 
      } 
     } 
    } 
} 

/** 
* getNeighbourCells, counts the surrounding cells next to the current cell 
* @param x delivers position of current cell 
* @param y delivers position of current cell 
* @return counter-1, because the loops count the current cell itself 
*/ 

private int getAliveNeighbourCells(int x, int y) { 
    int counter = 0; 
    for (int i = x-1; i <= x + 1; i++) { 
     for (int j = y-1; j <= y + 1; j++) { 
      if(i >= 0 && i < gameBoard.length-1 && j >= 0 && j < gameBoard[i].length-1){ 
       if(gameBoard[i][j]){ 
        counter++; 
       } 
      } 
     } 
    } 
    return counter; 
} 

/** 
* getCellState returns CellState of a specific cell on the gameBoard 
* @param i delivers position of current cell 
* @param j delivers position of current cell 
* @return gameBoard[i][j] returns current CellState on gameBoard at position [i][j] 
*/ 
@Override 
public boolean getCellState(int i, int j) { 
    return gameBoard[i][j]; 
} 

GameOfLifeInterface

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


public class GameOfLifeInterface extends JPanel implements ActionListener{ 
private Timer time = new Timer(150, this); 
private GameOfLifeBoard gameBoard; 
private boolean isActive; 

/** 
* GameOfLifeInterface randomizes the gameBoard 
* @param gameBoard gets randomized by GameOfLifeBoard.randomize 
*/ 
public GameOfLifeInterface(GameOfLifeBoard gameBoard){ 
    this.gameBoard = gameBoard; 
    gameBoard.randomize(); 
} 

/** 
* paintComponent draws the current Generation (Dead Cell will be painted in white, Alive Cell in Black) 
* and restarts or stops the Timer time 
* @param graph Graphics 
*/ 

public void paintComponent(Graphics graph){ 
    super.paintComponent(graph); 
    int iBox = 2; 
    for (int i = 0; i < gameBoard.getGameBoard().length; i++) { 
     for (int j = 0; j < gameBoard.getGameBoard()[i].length; j++) { 
      graph.setColor(!gameBoard.getGameBoard()[i][j]? Color.WHITE : Color.BLACK); 
      graph.fillRect(i * iBox, j * iBox, iBox, iBox); 
     } 
    } 
    if(isActive){ 
     time.restart(); 
    } 
    else{ 
     time.stop(); 
     repaint(); 
    } 
} 

/** 
* setActivity sets private boolean: true or false 
* @param activity boolean stores decision of User (Buttons: Stop/Start) 
*/ 
public void setActivity(boolean activity){ 
    isActive = activity; 
} 

/** 
* actionPerformed if Timer time has past, the current Generation will be replaced with the new Generation 
* GameBoard gets repainted to show the new Generation 
* @param e ActionEvent 
*/ 
@Override 
public void actionPerformed(ActionEvent e) { 
    if(e.getSource().equals(time)){ 
     gameBoard.nextGeneration(); 
     repaint(); 
    } 
} 

Schnittstelle Strategie

public interface Strategy { 
int ROW = 500; 
int COL = 500; 
int MIN = 2; 
int MAX = 3; 

boolean getCellState(int i, int j); 

}

Antwort

2

Ihre getAliveNeighborCells Methode ist falsch. Es zählt den Wert der mittleren Zelle, wenn nur die umgebenden Zellen gezählt werden sollen.

So wird Ihr Code das folgende Muster überprüfen:

XXX 
XXX 
XXX 

Wenn es nur diese Zellen zählen sollte:

XXX 
X X 
XXX 

Die einfachste Lösung nur die Bedingung (i != x || j != y) auf Ihre if Aussage ist hinzuzufügen, wie folgt:

if(gameBoard[i][j] && (i != x || j != y)){ //... 

Dort könnte noch Seien Sie andere Fehler in Ihrem Code, aber Sie haben viele wichtige Teile weggelassen, so dass ich es nicht kompilieren und testen kann.

Hier ein paar Vorschläge, um Ihren Code zu verbessern/korrigieren:

Statt Ihre JMenuBar wie eine normale Komponente hinzuzufügen, sollten Sie die setJMenuBar Methode verwenden, die explizit für diesen Zweck ist.

Dies ist eher eine stilistische Entscheidung, aber ich würde Ihre setJMenu Methode zu einer getJMenuBar Methode ändern, die eine neue JMenuBar zurückgibt und der Anrufer es dem Feld zuweisen lässt. In diesem Zusammenhang würde ich auch empfehlen, Felder zu erstellen, die nach der Initialisierung nicht geändert werden sollten final. In Ihrer actionPerformed Methode vergleichen Sie String s mit ==. Das ist ein bad idea, der technisch in dieser Situation funktioniert, aber fast sicher für einen irgendwann unerwartet ausfallen wird. Sie sollten stattdessen String s mit equals vergleichen.

In GameOfLifeBoard würde ich empfehlen, die getGameBoard Methode zu entfernen und sie durch Zugriffsmethoden zu ersetzen, um die notwendigen Informationen zu erhalten. Die Methoden, die ich empfehlen würde, wären bool getBoardItem(int row, int col) (dieses ist bereits von getCellState abgedeckt), int getBoardRows() und int getBoardColumns(int row). Dadurch erhalten Sie die gleichen Informationen, aber der Anrufer kann die Karte nicht ändern, wodurch Sie mehr Kontrolle über seinen Status erhalten.

In nextGeneration kopieren Sie manuell jedes Feld in newGen in gameBoard. Das funktioniert, aber es wäre schneller, nur die Referenz zu aktualisieren, mit gameBoard = newBoard.

Nach ROW und COL definiert in Strategy scheint es unnötigerweise sperrt Sie in einer Größe. Sie können das durch eine Methodendeklaration int getRowSize() und int getColSize() ersetzen und die Implementierung die gewünschten Werte zurückgeben. Das würde verschiedenen Implementierungen erlauben, die gewünschte Größe zu verwenden.

Das sind die Dinge, die mir als mögliche Verbesserungen auffallen.

+0

Ich versuche, die fehlenden Teile durch Bearbeiten hinzuzufügen. Danke für Ihre Hilfe! –

+0

Implementiert Ihre Lösung und es funktioniert. Dank dafür! Haben Sie etwas dagegen, mir weitere mögliche Fehler in meinem Code oder einige Ratschläge zu nennen, um besseren Code zu generieren? –

+0

@ S.Neum Ich habe einige Vorschläge für Dinge hinzugefügt, die ich ändern würde. – resueman

Verwandte Themen