为什么我的 Game Of Life 模拟如此不准确?

Why is my Game Of Life simulation so inaccurate?

我脑子里已经有几个星期了这个项目,所以我制作了一个生活模拟程序的游戏 但是在将它与这个模拟 (https://playgameoflife.com/) 进行比较之后,我编码的 none 是准确的,即使我尊重我的代码中的规则......

我的代码不正确吗?怎么了?

(https://pastebin.com/SpMFQGJL)

    public class GameOfLife {

    /*
     * STATIC PART - ENTRY POINT
     */
    public static void main(String[] args) {
        GameOfLife gol = new GameOfLife(new Dimension(480,270),4, true, new Random().nextInt(), new Random().nextInt(25)).init();
        gol.start();
    }
    
    /*
     * GameOfLife Class content
     */
    
    /*
     * GameGrid Vars (requiered for game grid)
     * dimX = game of life grid size on X axis
     * dimY = game of life grid size on Y axis
     * cellScale = size of cells on X and Y axis on screen display
     * fillperc = chances of a cell to be alive on grid generation
     * borderTeleporter = is wall teleporter (on other side of map) !!useless at the moment!!
     */
    public int dimX;
    public int dimY;
    public int cellScale;
    public int fillperc;
    public boolean borderTeleporter;
    /*
     * Generation vars
     */
    public int currentSeed = 0;
    public int generation = 0;
    
    //Thread clock = the thread the game of life clock is on
    public Thread clock;
    
    /*
     * frame = the frame the game of life grid is drawn on
     * game_grid = component of game of life
     */
    public JFrame frame;
    public GameGrid game_grid;
    
    /*
     * GameOfLife
     * @params args
     */
    public GameOfLife(Dimension boardDimension, int cellScale, boolean borderTeleporter,int seed,int fillperc) {
        if(seed != 0) currentSeed = seed;
        this.dimX = (int) boardDimension.getWidth();
        this.dimY = (int) boardDimension.getHeight();
        this.cellScale = cellScale;
        this.borderTeleporter = borderTeleporter;
        this.fillperc = fillperc;
    }
    
    public GameOfLife init() {
        if(currentSeed == 0) currentSeed = new Random().nextInt();
        this.game_grid = new GameGrid(this).genBoard();
        frame = new JFrame("Map: " + currentSeed + "   Generation: " + generation);
        frame.setUndecorated(true);
        frame.addWindowListener(new WindowAdapter() {@Override public void windowClosing(WindowEvent e) {running = false;try{clock.join();}catch(Exception exx) {System.out.println("impossible de tuer le thread clock");};System.exit(0);}});
        frame.addKeyListener(new KeyListener() {
            
            @Override
            public void keyTyped(KeyEvent e) {}
            
            @Override
            public void keyReleased(KeyEvent e) {if(e.getKeyCode() == 32) {if(running)stop();else start();}else if(e.getKeyCode() == 116) {stop();fillperc = new Random().nextInt(25);currentSeed = new Random().nextInt();game_grid.genBoard();start();}}
            
            @Override
            public void keyPressed(KeyEvent e) {}
        });
        frame.setPreferredSize(new Dimension(dimX*cellScale,dimY*cellScale));
        frame.pack();
        frame.add(game_grid);
        frame.pack();
        frame.setVisible(true);
        return this;
    }
    public boolean running = false;
    public void start() {
        running = true;
        clock = new Thread(new Runnable() {
            
            @Override
            public void run() {
                while(running) {
                    frame.setTitle("Map: " + currentSeed + "   Generation: " + generation);
                    game_grid.calcBoard();
                    frame.repaint();
                    generation++;
                    try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}
                }
            }
        });
        clock.start();
    }
    public void stop() {
        running = false;try{clock.join();}catch(Exception exx) {System.out.println("impossible de tuer le thread clock");}
    }

}

然后是游戏方格class:

public class GameGrid extends JPanel{
    
    /**
     * 
     */
    private GameOfLife gol;
    private BufferedImage img;
    boolean first = true;
    public GameGrid(GameOfLife gol) {
        this.gol = gol;
    }
    
    public boolean[][] board;
    public boolean[][] new_board;
    
    public GameGrid genBoard() {
        board = new boolean[gol.dimX][gol.dimY];
        Random seed = new Random(gol.currentSeed);
        for(int x = 0; x < gol.dimX; x++) {
            for(int y = 0; y < gol.dimY; y++) {
                board[x][y] = seed.nextInt(100) < gol.fillperc;
            }
        }
        return this;
    }
    
    public void calcBoard() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                new_board = board;
                for(int x = 0; x < gol.dimX; x++) {
                    for(int y = 0; y < gol.dimY; y++) {
                        int n = getAliveNeighbours(x,y);
                        if(board[x][y]) {
                            if(n > 3 || n < 2) new_board[x][y] = false;
                            else new_board[x][y] = true;
                        } else {
                            if(n == 3) new_board[x][y] = true;
                            else new_board[x][y] = false;
                        }
                    }
                }
            }
        });
        t.start();
        try {t.join();} catch (InterruptedException e) {e.printStackTrace();}
    }
    
    public int getAliveNeighbours(int x, int y) {
        int n = 0;
        if(isIn(x+1,y+1)) {if(board[x+1][y+1]) {n+=1;}}
        if(isIn(x,y+1)) {if(board[x][y+1]) {n+=1;}}
        if(isIn(x-1,y+1)) {if(board[x-1][y+1]) {n+=1;}}
        

        if(isIn(x+1,y)) {if(board[x+1][y]) {n+=1;}}
        if(isIn(x-1,y)) {if(board[x-1][y]) {n+=1;}}
        

        if(isIn(x+1,y-1)) {if(board[x+1][y-1]) {n+=1;}}
        if(isIn(x,y-1)) {if(board[x][y-1]) {n+=1;}}
        if(isIn(x-1,y-1)) {if(board[x-1][y-1]) {n+=1;}}
        return n;
    }
    
    public boolean isIn(int x, int y) {
        if(x < 0|| x > gol.dimX-1) return false;
        if(y < 0|| y > gol.dimY-1) return false;
        return true;
    }
    
    public void genImage() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                BufferedImage imag = new BufferedImage(gol.dimX*gol.cellScale,gol.dimX*gol.cellScale,BufferedImage.TYPE_INT_RGB);
                for(int x = 0; x < gol.dimX; x++) {
                    for(int y = 0; y < gol.dimY; y++) {
                        int c = 0x000000;
                        if(board[x][y]) c = 0xCCCCCC;
                        for(int i = 0; i < gol.cellScale; i++) {
                            for(int j = 0; j < gol.cellScale; j++) {
                                imag.setRGB(x*gol.cellScale+i, y*gol.cellScale+j, c);
                            }
                        }
                    }
                }
                img = imag;
            }
        });
        t.start();
        try {t.join();} catch (InterruptedException e) {System.out.println("wesh");}
    }
    
    public void paint(Graphics g) {
        super.paint(g);
        genImage();
        g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
    }

}

最让我触动的是一切正常,在查看我的代码后我找不到导致模拟不准确的原因

new_board = board 没有按照您的意愿进行。它只是将 new_board 变量的值之一设置为 board 变量的当前值……两者都是引用。这意味着您修改的是您正在检查的同一块板...而您想要构建一个仅基于旧板的内容的新板。

删除 new_board 字段(您不需要),然后更改:

new_board = board;

boolean[][] new_board = new boolean[gol.dimX][gol.dimY];

然后在方法的末尾添加:

board = new_board;

...这样旧板就换成了新板。您的逻辑可能还有其他问题,但这是最明显的问题。

我还强烈 建议您删除 calcBoardgenImage 中的所有线程代码。你所做的只是创建一个新线程来做某事,然后等待该线程完成......这没有任何好处(它仍然阻塞直到工作完成)但它使代码更复杂。

(我还建议重新格式化 stop 方法,这样它就不会全部在一行中,这样真的很难阅读。一般来说,我建议重新格式化整个代码,事实上. 告诉你的 IDE 重新格式化整个东西。)