Попытка воспроизвести игру жизни Конвея не расширяется и не работает должным образом - PullRequest
0 голосов
/ 21 сентября 2019

Если вы не знаете, что такое игра жизни Конвея, проверьте это, это игра для нулевого игрока и клеточная автоматизация.https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life

Мне нужна помощь Отладка Следующие проблемы в моем коде.При необходимости я могу отредактировать этот вопрос, включив в него более старые версии моей программы, которые не предназначены для расширения.

Я также приму советы по улучшению моей программы, в том числе (но не ограничиваясь) эффективностью времени, (однако не по теме, так как это не главный вопрос) и некорректное использование существующих методов.(Мой метод paint ())

Проблемы:

Изучите планер A на изображении 1. (Ожидаемое поведение) Весь смысл программы состоял в том, чтобы уменьшить ячейки в JFrameи добавьте еще одну строку или столбец мертвых клеток в ArrayList<ArrayList<Boolean>> grid.Этот планер, к сожалению, не вызывает этого.Вместо этого результат (неожиданное поведение) состоял в том, что он просто «сплющился в квадрат», как показано на рисунке 2 (квадрат помечен буквой A).

Изучите планер B на рисунке 1. (Ожидаемое поведение) ВидяРезультаты Glider A на изображении 1 заставили меня думать, что планер B закончится так же.Однако это далеко не так.Посмотрите на планер B на рисунке 2. По какой-то причине он даже не достигает границы.(Неожиданно)

Для чего предназначена и предназначена эта программа: игра жизни Конвея находится в бесконечной 2D-плоскости, поэтому я хотел повторить это.В других моих программах использовался фиксированный размер массива, но для расширения использовались вложенные списки ArrayLists, и они действительно были бесконечными (до тех пор, пока не достигнуто ограничение памяти)

К сожалению, эта программа расширения просто не может расширить границу.(Граница на самом деле меньше, чем кажется. По сути, (притворяясь, что моя сетка ArrayList> является массивом) grid[0][0 to grid.length-1] включительно, grid[grid.length-1][0 to grid.length-1] включительно, grid[1 to grid.length-1][0] включительно и grid[1 to grid.length-1][grid.length-1] включительно.) Вместо выполнения указанногошаги, чтобы освободить место, планер А на изображении 1 сплющен к границе.(Граница находится под сеткой ячеек, где серые линии отсутствуют)

Изображение 1 enter image description here Изображение 2 enter image description here

Эти изображения соответствуют друг другу;планер A из изображения 1 Заголовок создает квадрат на изображении 2, также помеченный как A. Если вы видите какие-либо слова, описывающие «линию 74», указывающие на «линию 74», или такие слова, как «ВВЕРХ» (без какого-либо другого значения) в комментариях вкод, пожалуйста, скажите мне, чтобы я мог удалить их.Это была отдельная, уже исправленная ошибка.

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Expansion {
    static int delay = 50;
    static SquarePaint sp = new SquarePaint();
    static int K = 75; // An integer used below to create the starting setup for the grid.
    static{
        // 001 101 011
        boolean[][] array = new boolean [300][200];
        //      array[30][30]
        array[K][K+2] = true;
        array[K+1][K] = true;
        array[K+1][K+2] = true;
        array[K+2][K+1] = true;
        array[K+2][K+2] = true;
        sp.define(array); // Uses array to make first setup
    }
    public static void main (String[] args){
        // It is possible to put this information in a constructor instead
        JFrame j = new JFrame();
        j.add(sp); // Must add a custom paint component overriding the paint component, 
        //a class could and will do this
        j.setVisible(true);
        j.setSize(2000, 1000);
        j.setResizable(false);
        j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static class SquarePaint extends Component{
        static boolean VALUE = false;
        public static final int screenX = 1000, screenY = 500;
        static int cellSize = 5;
        int cellsX = screenX / cellSize, cellsY = screenY / cellSize, frames = 0;

        ArrayList<ArrayList<Boolean>> grid = new ArrayList<ArrayList<Boolean>>(); ////
        Timer timer = new Timer(delay, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent A) {
                //UPDATE FUNCTION
                frames++;
                boolean [][] oldGrid = new boolean[cellsX][cellsY];
                for(int i=0; i<cellsX && i<grid.get(1).size(); i++){
                    for(int j=0; j<cellsY && j<grid.get(1).size(); j++){
                        oldGrid[i][j] = grid.get(i).get(j); // <<Line 74>><<Line 74>><<Line 74>>

                    }
                }
                /* These are notes
                 * How would I:
                 * Expand LinkedLists, for example
                         (Grid in a picture, 0 = variable, + = new cell)
                            0 0 0 +
                            0 0 0 +
                            0 0 0 +
                            0 0 0 +
                 * Adjust existing variables (and poorly coded methods if they exist) to suit this new change
                 */
                for(int i=1; i<cellsX-2; i++) {
                    for(int j=1; j<cellsY-2; j++) { // TODO
//                      System.out.println(i + " " + j);
                        int nearbyCells = nearbyCells(oldGrid, i, j);
                        /////////////////////////////////////////////
                        if(oldGrid[i][j]){ 
                            // If the cell is alive 
                            // and is beside the no interact border, expand it by 1
                            // (Basically, to prevent ArrayOutOfBoundsException s, 
                            // (the ArrayList equivalent) only cells from 1 to cellsX-1(-1)/cellsY-1(-1) 
                            // are counted,)
                            // meaning that a whole row/column of cells is ignored and is not interacted with,
                            // until the grid expands.
                            ArrayList <Boolean> l = new ArrayList<Boolean>();
                            for(int k=0; k<cellsX; k++){
                                l.add(false);
                            }
                            if(i <= 1){ // You may notice that the above comments are wrong.
                                // This is because I thought this might be a small chance for it to succeed
                                // while I was frustrated this was not working.
                                grid.add(0, l);
                                cellSize = screenX / (cellSize + 1);
                                cellsX++;
                                VALUE = true;
                                repaint();
                                System.out.println("i<=5");
                            }
                            if(i >= cellsX-1){
                                grid.add(l);
                                cellSize = screenX / (cellSize + 1);
                                cellsX++;
                                VALUE = true;
                                repaint();
                                System.out.println("i>=cellsX");
                            }
                            if(j <= 1) {
                                for(int k=0; k<cellsY; k++){
                                    grid.get(k).add(false);
                                }
                                cellSize = screenY / (cellSize + 1);
                                cellsY++;
                                VALUE = true;
                                System.out.println("j<=5");
                                repaint();
                            }
                            if(j >= cellsY-1) {
                                for(int k=0; k<cellsY; k++){
                                    grid.get(k);
                                }
                                cellSize = screenY / (cellSize + 1);
                                cellsY++;
                                VALUE = true;
                                System.out.println("j>cellsY");
                                repaint();
                            }
                            //corner cases aren't a problem, it'll add to both sides
                            //  && (i == 1 || i == cellsX-1 || j == 1 || j == cellsY-1)
                            /* i.e.
                             * 0 = dead cells
                             * 1 = annoying cells in the corner
                             * + = new cells
                             * First, it'll do this
                             * + + +
                             * 0 1 1
                             * 0 1 1 // Note that the square is a "still life form" meaning that it will
                             * 0 0 0 // simply sit there and do nothing for infinite generations if 
                             *      // untouched
                             * But the if statements above will return true more than once, so
                             * 0 0 0 +
                             * 0 1 1 +
                             * 0 1 1 +
                             * 0 0 0 +
                             */
                        }
                        /////////////////////////////////////////////
                        if (oldGrid[i][j] && !(nearbyCells == 2 || nearbyCells == 3)){ 
                            // if it is alive, sustain rules
                            grid.get(i).set(j, false);
                        }
                        else if (!oldGrid[i][j] && nearbyCells == 3){ // if it is dead, birth rules
                            grid.get(i).set(j, true);
                        }
                    }
                }
                repaint(); // never erase, note that in bigger applications I assume that they 
                // draw to pictures that get slapped onto the screen so the paint function doesn't 
                // get called 9999 times and slow the fps down

            }
        });
        int nearbyCells(boolean[][] oldGrid, int i, int j) { // A method that calculates how many cells are
            //alive near it, i.e.
            /* 0 = Dead
             * 1 = Alive
             * "+" = center
             * 1 0 0
             * 0 + 1
             * 0 0 1
             * If you called nearbyCells on the center in the example, then it would return 3.
             */
            int nearbyCells = 0;

            if(oldGrid[i+1][j+1]) nearbyCells++;
            if(oldGrid[i+1][j]) nearbyCells++;
            if(oldGrid[i+1][j-1]) nearbyCells++;

            if(oldGrid[i][j+1]) nearbyCells++;
            if(oldGrid[i][j-1]) nearbyCells++; // i, j is where the to-be-changed cell is, skip it

            if(oldGrid[i-1][j+1]) nearbyCells++;
            if(oldGrid[i-1][j]) nearbyCells++;
            if(oldGrid[i-1][j-1]) nearbyCells++;
            return nearbyCells;
        }
        public SquarePaint(boolean[][] grid){
            define(grid);
            timer.start();
        }
        public SquarePaint(){
            timer.start();
        }
        public void define (boolean[][] grid){ // define cannot be called twice, not intended
            for(int i=0; i<cellsX; i++){
                ArrayList<Boolean> l = new ArrayList<Boolean>();
                for(int j=0; j<cellsY; j++){
                    l.add(grid[i][j]);
                }
                this.grid.add(l);
            }
        }
        @Override
        public void paint(Graphics g) {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, screenX, screenY); // Warning: Color must be set 
            // each time if the paint command is ever to be called again


            for(int i=0; i<cellsX-1; i++){
                for(int j=0; j<cellsY-1; j++){
                    try{
                        if(grid.get(i).get(j)){
                            g.setColor(Color.WHITE);
                            g.fillRect(i * cellSize, j * cellSize, cellSize, cellSize); 
                        } // Basically, 2 for loops
                    }// Nested for loops draw each cell on the potentially expanding ArrayList "grid" of cells

                    catch(java.lang.IndexOutOfBoundsException e){
                        System.out.println(i + " " + j);
                        e.getStackTrace();
                    }
                    g.setColor(Color.GRAY);
                    g.drawRect(i * cellSize, j * cellSize, cellSize, cellSize);
                }
            }


        }

    }

}

1 Ответ

1 голос
/ 21 сентября 2019

Я понятия не имею, что должна делать логика в середине вашего приложения.Не должно быть так сложно.Это запускает симуляцию в другом потоке и, возможно, помогает повысить производительность.

public class GameOfLife extends JFrame {
    private static final long serialVersionUID = 1L;
    private Thread thread;
    private SimulationThread simulationThread;

    public GameOfLife() {
        super("GameOfLife");
    }


    class MyPanel extends JPanel {
        private static final long serialVersionUID = 1L;

        public MyPanel() {
            setBorder(BorderFactory.createLineBorder(Color.black));
        }

        public Dimension getPreferredSize() {
            return new Dimension(1000, 1000);
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);       
            Graphics2D g2d = (Graphics2D)  g;
            simulationThread.drawScreenItems(g2d);
        }
    }
    /**
     * Create the GUI and show it. For thread safety, this method should be invoked
     * from the event-dispatching thread.
     */
    public void createAndShowGUI() {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MyPanel myPanel = new MyPanel();
        add(myPanel);

        // Display the window.
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        // Create and set up the window.

        // create thread with genetic reproduction callback code.
        simulationThread = new SimulationThread(myPanel);
        thread = new Thread(simulationThread);
        thread.start();
    }

    public static void main(String[] args) {
        final GameOfLife swingGa = new GameOfLife();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                swingGa.createAndShowGUI();
            }
        });
    }
}

public class SimulationThread implements Runnable {
    private MyPanel myPanel;
    public boolean run = true;
    static final int GAME_SIZE = 200;

    boolean[][] cells;
    boolean[][] newCells;

    public SimulationThread(MyPanel myPanel) {
        this.myPanel = myPanel;
        cells = new boolean[GAME_SIZE][GAME_SIZE];
        for (int i = 1; i < cells.length - 1; i++) {
            for (int j = 1; j < cells[0].length - 1; j++) {
                cells[i][j] = Math.random() > 0.5;
            }
        }
        newCells = new boolean[GAME_SIZE][GAME_SIZE];
    }

    @Override
    public void run() {
        while (run) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // Iterate through the array, follow game of life rules
            for (int i = 1; i < cells.length - 1; i++) {
                for (int j = 1; j < cells[0].length - 1; j++) {
                    int surrounding = 0;
                    if (cells[i - 1][j - 1]) surrounding++;
                    if (cells[i - 1][j]) surrounding++;
                    if (cells[i - 1][j + 1]) surrounding++;
                    if (cells[i][j - 1]) surrounding++;
                    if (cells[i][j + 1]) surrounding++;
                    if (cells[i + 1][j - 1]) surrounding++;
                    if (cells[i + 1][j]) surrounding++;
                    if (cells[i + 1][j + 1]) surrounding++;
                    newCells[i][j] = false;
                    if (cells[i][j]) {
                        // Cell is alive, Can the cell live? (2-3)
                        if ((surrounding == 2) || (surrounding == 3)) {
                            newCells[i][j] = true;
                        }
                    } else {
                        // Cell is dead, will the cell be given birth? (3)
                        if (surrounding == 3) {
                            newCells[i][j] = true;
                        }
                    }
                }
            }
            synchronized(cells) {
                for (int i = 1; i < cells.length - 1; i++) {
                    for (int j = 1; j < cells[0].length - 1; j++) {
                        cells[i][j] = newCells[i][j];
                    }
                }
            }
            myPanel.repaint();
        }

    }

    public void drawScreenItems(Graphics2D g2d) {
        synchronized(cells) {
            for (int i = 1; i < cells.length - 1; i++) {
                for (int j = 1; j < cells[0].length - 1; j++) {
                    if (cells[i][j])
                        g2d.fillRect(i * (1000 / GAME_SIZE), j * (1000 / GAME_SIZE), 1000 / GAME_SIZE, 1000 / GAME_SIZE);
                }
            }
        }
    }
}
...