Рекурсивные / циклические вычисления нового поколения в The Game of Life - PullRequest
1 голос
/ 07 марта 2012

каждый.

Следующее поколение в моем приложении Game of Life (ссылка - пример приложения) рассчитывается правильно. Игра работает, как и ожидалось, но вы должны нажимать «Далее» каждый раз, когда вы хотите новое поколение. У меня проблема с реализацией кнопки «Пуск» для зацикливания поколений. (См. Ссылку для определения различий между «next» и «start».)

Очевидно, мне нужен какой-то цикл внутри класса ActionListener. Я попытался вызвать nextGen () внутри actionListener рекурсивно, в то время как частное логическое значение true. Программа вылетает. Я также попытался установить какое-то ожидание, но это не имеет значения.

Это действительно делает 10 итераций, если я помещаю 10 строк nextGen (); внутри слушателя, так что я думаю, мне нужно подождать здесь. (Проблема с памятью.)

Надеюсь, вы поможете мне в этом. :)

Следующее поколение рассчитывается таким образом.

Класс 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();
    }
}

actionListener запускает nextGen () для объекта GameOfLife при нажатии кнопки «Далее». Принцип работы метода 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. Рисует сетку и живые клетки (Cell array).

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();
            }
        };
    }

1 Ответ

1 голос
/ 07 марта 2012

Проблема заключается в том, что при попытке выполнить цикл с Thread.sleep () в методе actionPerformed вы блокируете Поток отправки событий .Ничто не может быть перекрашено до тех пор, пока вы не освободите контроль над потоком, поэтому ваши запросы на перерисовку сразу же запускаются и запускаются сразу после завершения действия вашего метода actionPerformed.

Простое решение - использовать javax.swing.Timer для запускасобытия с регулярным интервалом, что-то вроде этого:

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