为什么我的 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;
...这样旧板就换成了新板。您的逻辑可能还有其他问题,但这是最明显的问题。
我还强烈 建议您删除 calcBoard
和 genImage
中的所有线程代码。你所做的只是创建一个新线程来做某事,然后等待该线程完成......这没有任何好处(它仍然阻塞直到工作完成)但它使代码更复杂。
(我还建议重新格式化 stop
方法,这样它就不会全部在一行中,这样真的很难阅读。一般来说,我建议重新格式化整个代码,事实上. 告诉你的 IDE 重新格式化整个东西。)
我脑子里已经有几个星期了这个项目,所以我制作了一个生活模拟程序的游戏 但是在将它与这个模拟 (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;
...这样旧板就换成了新板。您的逻辑可能还有其他问题,但这是最明显的问题。
我还强烈 建议您删除 calcBoard
和 genImage
中的所有线程代码。你所做的只是创建一个新线程来做某事,然后等待该线程完成......这没有任何好处(它仍然阻塞直到工作完成)但它使代码更复杂。
(我还建议重新格式化 stop
方法,这样它就不会全部在一行中,这样真的很难阅读。一般来说,我建议重新格式化整个代码,事实上. 告诉你的 IDE 重新格式化整个东西。)