I've had that project in my head for a few weeks so I made a game of life simulation program but after comparing it to this simulation (https://playgameoflife.com/), none of what i've codded is accurate even tho I respected the rules in my code ...
is my code not correct ? what's wrong ?
(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");}
}
}
and then the game grid 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);
}
}
thing that triggers me the most is that everything works fine and the after looking at my code I can't find what can cause the simulation to be inaccurate
CodePudding user response:
new_board = board
doesn't do what you want it to. It just sets one the value of the new_board
variable to the current value of the board
variable... both are references. That means you're modifying the same board that you're examining... whereas you want to construct a new board based solely on the contents of the old board.
Remove the new_board
field (which you don't need), then change this:
new_board = board;
to
boolean[][] new_board = new boolean[gol.dimX][gol.dimY];
and then at the end of the method, add:
board = new_board;
... so that the old board is replaced with the new board. It's possible that there are other problems with your logic, but that's the most obvious one.
I'd also strongly advise you to get rid of all your threading code in calcBoard
and genImage
. All you're doing is creating a new thread to do something, then waiting for that thread to finish... that doesn't do any good (it still blocks until the work is complete) but it makes the code more complex.
(I'd also suggest reformatting the stop
method so that it's not all on one line, which makes it really hard to read. In general, I'd suggest reformatting the whole code, in fact. Just tell your IDE to reformat the whole thing.)