《生命的游戏》中新一代的递归/循环计算



每个人。

我的"生命游戏"应用程序中的下一代(链接是示例应用程序)是正确计算的。游戏运行如预期,但每次您想要新一代时都必须按"下一代"。我在实现"开始"按钮来循环生成时遇到了问题。(请参阅链接了解"下一步"one_answers"开始"之间的区别。)

很明显,我需要ActionListener类中的某种循环。当私有布尔值为true时,我尝试在actionListener递归内部调用nextGen()。程序崩溃。我也尝试过设置某种等待,但这并不重要。

如果我放置10行nextGen(),它确实会进行10次迭代;在听众的内心,所以我想我需要在这里等待。(内存问题。)

希望你能帮我

下一代是这样计算的。

ActionListener类:

public class GameOfLifeListener implements ActionListener
{
    // IMPORTANT: GameOfLifeGrid contains the GameOfLife collection!
    private GameOfLifeGrid gameOfLife;

    public GameOfLifeListener ( GameOfLifeGrid g ) 
    {
        this.gameOfLife = g;
     }
    @Override
    public void actionPerformed (ActionEvent e) 
    {
        // Get actionCommand
        String ac = e.getActionCommand();
        if ( ac.equals("next") ) 
        {
             // Method calculates next generation
             nextGen();
        }
        if ( ac.equals("start") ) 
        {
             // ADDED CODE: See class GameOfLifeGrid in bottom.
             gameOfLife.start();
        }
    }
    private void nextGen ( ) 
    {
        // Get Next generation
        gameOfLife.getCollection().nextGen();
        // Repaint
        gameOfLife.repaint();
    }
}

当按下按钮"next"时,actionListener在GameOfLife对象上运行nextGen()。nextGen()方法的工作原理并不重要,但这里它与GameOfLife类的一些部分一起

public class GameOfLife extends CellCollection
{
    // Temporary array for new generation . We must add next generations alive cells HERE.
    // Else the calculations of the current generation will fail.
    private Cell[][] nextGen = null;
    public void nextGen ( ) 
    {
        // Create the new Array holding next generation
        prepareNextCollection();
        // Iterate the whole grid
        for ( int row = 0; row < super.rows; row++ ) 
        {
            for ( int col = 0; col < super.cols; col++ ) 
            {
                 ruleOne(row, col);
            }
        }
        // Set the new collection to superClass. 
        // Super class holds the collection that will be drawn
        super.setCollection(nextGen);
    }

    private void ruleOne ( int row, int col ) 
    {
        // Calculations not important. It works like expected.
    }
    private void prepareNextCollection ( ) 
    {
        this.nextGen = new Cell[rows][cols];
    }

这是GameOfLifeGrid类的选定部分。它绘制网格和活动单元格(单元格数组)。

public class GameOfLifeGrid extends Grid
{
    private GameOfLife collection = null;
    // ADDED MEMBERS: Timer, int
    private Timer timer; 
    private int updateEachMilliSec = 100; // Used in program. Not in this code
    @Override
    public void paintComponent ( Graphics g )
    {
        super.paintComponent(g);
        drawCells(g);
    }
    private void drawCells ( Graphics g ) 
    {
        for ( int row = 0; row < rows; row++ ) 
        {
            for ( int col = 0; col < cols; col++ )
            {
                if ( ! collection.isEmptyPos(row, col) ) 
                {
                    g.fillRect(super.calcX(col), super.calcY(row), cellSize, cellSize);
                }
            }
        } 
    }
    // ADDED METHOD!
    public void start() 
    {
        // Create a timer object. The timer will send events each 100 ms.
        // The events will be caught by the ActionListener returned from
        // nextGenlistener(). VOILA!
        timer = new Timer(100, nextGenlistener());
        // Start sending events to be caught!
        timer.start();
    }
    // ADDED METHOD! The ActionListener who will catch the events sent by timer.
    private ActionListener nextGenlistener () 
    {
        return new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e) 
            {
                // Get next generation
                collection.nextGen();
                // Repaint
                repaint();
            }
        };
    }

问题是,当您尝试在actionPerformed方法中使用Thread.sleep()进行循环时,会阻塞事件调度线程。在您释放对线程的控制之前,任何东西都无法重新绘制,所以当您的actionPerformed方法完成时,您的重新绘制请求会同时弹出并启动。

简单的解决方案是使用javax.swing.Timer定期触发事件,大致如下:

new Timer(5000, new ActionListener(){
  public void actionPerformed(ActionEvent e) {
    panel.repaint();
  }
}).start();

最新更新