简体   繁体   English

尝试复制康威的生命游戏无法扩展或正常工作

[英]Attempt at Replicating Conway's Game of Life does not expand or work properly

If you don't know what Conway's game of life is check this, it is a zero player game, and a cellular automation.如果您不知道康威的人生游戏是什么,请检查一下,它是零玩家游戏,是细胞自动化。 https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life

I need help debugging the following problems in my code.我需要帮助在我的代码中调试以下问题。 If necessary, I can edit this question to include older versions of my program, which are not intended to expand.如有必要,我可以编辑此问题以包含我的程序的旧版本,这些版本不打算扩展。

I will also accept tips to improve my program, including (but not limited to) time efficiency, (off topic however, as it is not the main question) and incorrect use of existing methods.我还将接受改进我的程序的提示,包括(但不限于)时间效率,(但题外话,因为它不是主要问题)和不正确地使用现有方法。 (My paint() method) (我的 paint() 方法)

Problems:问题:

Examine Glider A in image 1. (Expected behavior) The whole point of the program was to make the cells shrink in the JFrame and add another row or column of dead cells to the ArrayList<ArrayList<Boolean>> grid .检查图 1 中的滑翔机 A。(预期行为)程序的全部目的是使 JFrame 中的单元格缩小,并将另一行或列死单元格添加到ArrayList<ArrayList<Boolean>> grid中。 This glider, unfortunately does not cause this to happen.不幸的是,这架滑翔机不会导致这种情况发生。 Instead, the result (Unexpected behavior) was that it simply "flattened into a square" as shown in image 2 (the square marked with an A).相反,结果(意外行为)是它只是“扁平化为正方形”,如图 2 所示(标有 A 的正方形)。

Examine Glider B in image 1. (Expected behavior) Seeing the results Glider A in image 1 made me think that glider B would end the same.检查图像 1 中的滑翔机 B。(预期行为)看到图像 1 中的滑翔机 A 的结果让我认为滑翔机 B 会以同样的方式结束。 However, this is not remotely true.然而,这远非如此。 Look at glider B in image 2. It, for some reason, does not even reach the border.看看图 2 中的滑翔机 B。由于某种原因,它甚至没有到达边界。 (Unexpected) (意外)

What this program is for and meant to do: Conway's game of life is on an infinite 2D plane, so I wanted to replicate this.这个程序的用途和目的:康威的生命游戏是在一个无限的 2D 平面上,所以我想复制它。 My other programs used a fixed array size, but this used nested ArrayLists to expand, and truly be infinite (until the memory limit comes)我的其他程序使用了固定的数组大小,但这使用了嵌套的 ArrayLists 来扩展,并且真正是无限的(直到 memory 限制出现)

Unfortunately, this expansion program simply fails to expand the border.不幸的是,这个扩展计划根本无法扩展边界。 (The border is actually smaller than it looks. Basically, (pretending my ArrayList> grid is an array) grid[0][0 to grid.length-1] inclusive, grid[grid.length-1][0 to grid.length-1] inclusive, and grid[1 to grid.length-1][0] inclusive, and grid[1 to grid.length-1][grid.length-1] inclusive.) Instead of doing the specified steps to make room, glider A in image 1 flattened against the border. (边框实际上比看起来要小。基本上,(假装我的 ArrayList> grid 是一个数组) 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 中的滑翔机 A 靠着边界展平。 (The border is beneath the grid of cells, where grey lines are not present) (边框位于单元格网格下方,其中不存在灰线)

Image 1图 1 在此处输入图像描述 Image 2图 2 在此处输入图像描述

These images correspond with each other;这些图像相互对应; glider A from image 1 Heading produces the square in image 2, also marked as A. If you see any words describing "line 74," pointing toward "line 74" or words like "UP" (without any other meaning) in comments in the code please tell me, so I can remove them.图 1 中的滑翔机 A 标题生成图 2 中的正方形,也标记为 A。如果您在评论中看到任何描述“第 74 行”的词,指向“第 74 行”或“向上”之类的词(没有任何其他含义)请告诉我代码,这样我就可以删除它们。 That was a separate, already fixed bug.那是一个单独的,已经修复的错误。

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


        }

    }

}

I have no idea what the logic in the middle of your application is supposed to be doing.我不知道您的应用程序中间的逻辑应该做什么。 Shouldn't be that complicated.不应该那么复杂。 This runs the simulation in another thread and so perhaps helps address performance.这在另一个线程中运行模拟,因此可能有助于解决性能问题。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM