I want to memory-efficient this (the game of life code of shiffman in the nature of code book). how can change the below code to have only two arrays and constantly swap them, writing the next set of states into whichever one isn’t the current array?
class GOL {
int w = 8;
int columns, rows;
int[][] board;
GOL() {
// Initialize rows, columns and set-up arrays
columns = width / w;
rows = height / w;
board = new int[columns][rows];
//next = new int[columns][rows];
// Call function to fill array with random values 0 or 1
init();
}
void init() {
for (int i = 1; i < columns - 1; i++) {
for (int j = 1; j < rows - 1; j++) {
board[i][j] = (int) random(2);
}
}
}
// The process of creating the new generation
void generate() {
int[][] next = new int[columns][rows];
// Loop through every spot in our 2D array and check spots neighbors
for (int x = 1; x < columns - 1; x++) {
for (int y = 1; y < rows - 1; y++) {
// Add up all the states in a 3x3 surrounding grid
int neighbors = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
neighbors += board[x + i][y + j];
}
}
// A little trick to subtract the current cell's state since
// we added it in the above loop
neighbors -= board[x][y];
// Rules of Life
if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0;
else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0;
else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1;
else next[x][y] = board[x][y];
}
}
// Next is now our board
board = next;
}
// This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0'
void display() {
for (int i = 0; i < columns; i++) {
for (int j = 0; j < rows; j++) {
if ((board[i][j] == 1)) fill(0);
else fill(255);
stroke(0);
rect(i * w, j * w, w, w);
}
}
}
}
You might not like this, but the honest answer is: don't bother.
how can change the below code to have only two arrays and constantly swap them, writing the next set of states into whichever one isn’t the current array
This is already exactly what the code does.
The Game of Life requires two arrays. If you're coming up against real performance issues, then look for other areas of improvement. Focusing on the array is a red herring.
There's an old saying: premature optimization is the root of all evil. In other words, you shouldn't waste time trying to fix code before it's broken.
One obvious thing you might improve is: why are you using an int[] array instead of a boolean[] array? You only need to store two states: alive or dead, so using int values seems unnecessary. You'll save a little bit of memory if you switch to a boolean[] array, but again, you probably won't even notice the improvement.
Related
This code is for a game of life application.
My code promts a user for a text file the container rows and columns.
The file is read and entered into a 2D array.
The array is then pass to my nextGeneration method and this prints the generation.
I need to pass the future array back to the nextGeneration as many times a required per the users input.
I've been struggling all day on how to pass the nextGeneration the "future" array once it has gone through the first generation.
Any help would be greatly appreciated. Thanks.
static void nextGeneration(int grid[][], int M, int N, int NumberofGenerations)
{
int[][] future = new int[M][N];
// Loop through every cell
for (int l = 1; l < M - 1; l++)
{
for (int m = 1; m < N - 1; m++)
{
// finding no Of Neighbours that are alive
int aliveNeighbours = 0;
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
aliveNeighbours += grid[l + i][m + j];
// The cell needs to be subtracted from
// its neighbours as it was counted before
aliveNeighbours -= grid[l][m];
// Implementing the Rules of Life
// Cell is lonely and dies
if ((grid[l][m] == 1) && (aliveNeighbours < 2))
future[l][m] = 0;
// Cell dies due to over population
else if ((grid[l][m] == 1) && (aliveNeighbours > 3))
future[l][m] = 0;
// A new cell is born
else if ((grid[l][m] == 0) && (aliveNeighbours == 3))
future[l][m] = 1;
// Remains the same
else
future[l][m] = grid[l][m];
}
}
if (NumberofGenerations != 0)
{
return NumberofGenerations -1 * nextGeneration(future[l][m], 20, 20,NumberofGenerations -1);
// recursive call
else
return 1;
}
System.out.println("Next Generation");
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
if (future[i][j] == 0)
System.out.print(" ");
else
System.out.print("*");
}
System.out.println();
}
}
Generally speaking - Recursion is a good idea but not good for implementation, it can usually be achieved iteratively and takes much more time and memory than an iterative way. Therefore I will show you how to implement your algorithm iteratively.
Pseudo code:
1. Call nextGeneration
2. loop 1 to NumberofGenerations
2.1. init future
2.2. put next generation in future
2.3. print future
2.4. copy future to grid
Since your code creates the next generation regardless of what in future array, it will work.
You already have steps 1, 2.1, 2.2, 2.3, all you need to do is to remove your recursive call, add a loop (stage 2.) and copy future to grid (stage 2.4).
Copy code:
for (int i=0; i < grid.length; i++)
for (int j=0; j < grid[i].length; j++)
grid[i][j] = future[i][j];
I've created a 12x12 grid, and within this grid I have created 'infected' tiles, when one infected tile is surrounded by other infected tiles, the surrounded cell becomes a diseased tile. I was wondering if there was a nice way of checking adjacent, in bounds cells for their value?
public static void diseaseTiles() {
int i, j;
for(i = 0; i < 12; i++) {
for(j = 0; j < 12; j++) {
if(myGrid[i][j] == 'I'){
int left, right, up, down;
if(i == 0) {
left = 1;
}
if(i == 11) {
right = 1;
}
if(j == 0) {
up = 1;
}
if(j == 11) {
down = 1;
}
//this is where I've gotten stuck
//I was going to use the above int's to determine
//whether or not the adjacent tile in that direction
//should be checked (they're the border of the grid)
}
}
}
}
You can check if a cell is infected by taking advantage of short-circuited evaluation:
boolean leftInfected = (i!=0) && myGrid[i-1][j]=='I';
boolean rightInfected = (i!=11) && myGrid[i+1][j]=='I';
boolean topInfected = (j!=0) && myGrid[i][j-1]=='I';
boolean bottomInfected = (j!=11) && myGrid[i][j+1]=='I';
After that, you could check if all four are infected:
if (leftInfected && rightInfected && topInfected && bottomInfected) {
myGrid[i][j] = 'D';
}
You might consider padding your array with a boundary one cell deep around each edge, so your 12x12 would become a 14x14. Make each cell in the boundary infected. You can then loop over the interior cells (ie rows 1:12, cols 1:12) without having to check that the cell is at the edge all the time.
I believe a better option is to define a helper array that defines the valid neighbors and iterate using it. Advantage of my approach is that it makes it very easy to change which are the valid neighbors(say you want to have 8 neighbors allowing to go by diagonal instead of only 4):
int moves[][] = {{-1,0}, {0, -1}, {1, 0}, {0, 1} };
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
for (int l = 0; l < 4 /* moves.length */; ++l) {
int ti = i + move[l][0];
int tj = j + move[l][1];
if (ti <= 0 || ti >= 12 || tj < 0 || tj >= 12) {
continue;
}
// cell (ti, tj) is valid neighbor do something with it.
}
}
}
A while I did an assignment creating a tictactoe program through eclipse. It works well enough, with me clicking empty boxes to place O's, and the program inputting X's afterward. However, I was using a pretty simple code for the placement of X's:
public int putX(){
for(int i=0; i<3;i++)
for(int j = 0;j<3;j++) {
if(position[i][j]==' ') {
position[i][j]='X';
return 0;
}
}
return -1; //some error occurred. This is odd. No cells were free.
}
Because of this, the X's are just placed in the row of each column, going down until the next column. Can someone show me a simple way to randomize this program?
What we want to do is generate an array of all the possible points, and pick one of those points at random. We use a for loop to iterate through all points in the 3x3 array, and add the valid ones to our temporary array, and then we choose a random index, and place an X there.
String[] list = new String[9]; // maximum 9 points
int size = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(position[i][j] == ' ') {
list[size] = "" + i + j;
size++;
}
}
}
int index = (int) (Math.random() * (size+1));
position[Integer.parseInt(list[index].charAt(0))][Integer.parseInt(list[index].charAt(1))] = 'X';
Alternatively, instead of storing the x,y coordinates of the point in a String we could store them in a java.awt.Point like so:
Point[] list = new Point[9]; // maximum 9 points
int size = 0;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(position[i][j] == ' ') {
list[size] = new Point(i, j);
size++;
}
}
}
int index = (int) (Math.random() * (size+1));
position[list[index].getX()][list[index].getY()] = 'X';
As you can see, the code for using a Point is practically the same, but instead of parsing the coordinates out of the String, we can just access them directly from the Class.
You should also check to make sure that there are some elements left, by checking if size is still 0 after the for loop. If so, you should probably return -1 (what your existing code does). Otherwise, at the end of the whole code return 0.
I was working on a Conway's game of life clone because it is good practice, but I ran into a problem. I see there are pixels deleting and rebirthing, but all the pixels just spread out the very end of the screen and then other pixels are rebirthing, but it is just idling at that point.
Here are some screenshots:
I'll show you some of my code for the logic of this. It is all handled in the change method:
package main;
import java.awt.Color;
import java.awt.Graphics;
public class Functions {
public static int pixelsize=6,gridwidth=800/6,gridheight=600/6;
static int[][] pixels = new int[gridwidth][gridheight];
static boolean first = true;
public static void change(){
for(int i = 0; i < gridwidth; i++){
for(int j = 0; j < gridheight; j++){
int neighbors = 0;
//check each cell
try{
if(pixels[i+1][j] == 1){neighbors++;}
if(pixels[i-1][j] == 1){neighbors++;}
if(pixels[i+1][j-1] == 1){neighbors++;}
if(pixels[i][j+1] == 1){neighbors++;}
if(pixels[i][j-1] == 1){neighbors++;}
if(pixels[i+1][j+1] == 1){neighbors++;}
if(pixels[i-1][j-1] == 1){neighbors++;}
if(pixels[i-1][j+1] == 1){neighbors++;}
}catch(ArrayIndexOutOfBoundsException e){
}
if(neighbors == 3 || neighbors == 2 ){
pixels[i][j] = 1;
}else if(neighbors < 2 || neighbors >= 4){
pixels[i][j] = 0;
}
}
}
}
public static void render(Graphics g){
for(int i = 0; i < gridwidth;i++){
for(int j = 0; j < gridheight; j++){
if(pixels[i][j] == 1){
g.setColor(Color.red);
g.fillRect(i*6, j*6, 6, 6);
}
}
}
}
}
thanks for all the help. Sadly it still isn't working correctly.Now it is doing the same thing but in diamond formation like so:
The main problem I do see here is the fact that you are updating values while discovering them.
You should cache your whole grid (or at least neighbours count) before updating, otherwise, while you update element at (x, y), you are alterating the neighbours count for element that are successive as (x+1,y), (x+1,y+1), (x,y+1) by counting the outcome of current iteration.
For example you could update a separate array called cachedPixels like so:
for(int i = 0; i < gridwidth; i++){
for(int j = 0; j < gridheight; j++){
int neighbors = 0;
// find the proper boundaries
int minI = Math.max(0, i - 1);
int maxI = Math.min(gridwidth, i + 2)
int minJ = Math.max(0, j - 1);
int maxJ = Math.min(gridheight, j + 2)
for (int i2 = minI; i2 < maxI; i2++) {
for (int j2 = minJ; j2 < maxJ; j2++) {
if (i2 != i || j2 != j) {
if (pixels[i2][j2] == 1) {
neighbors++;
}
}
}
}
if (neighbors == 2 || neighbors == 3) {
cachedPixels[i][j] = 1;
} else {
cachedPixels[i][j] = 0; // probably not even necessary as 0 is default value
}
}
}
Then after completing this process for the entire array set using the arraycopy function:
for (int i = 0; i < length; i++) {
System.arraycopy(cachedPixels[i], 0, pixels[i], 0, cachedPixels[i].length);
}
Simply setting pixels = cachedPixels would point "pixels" to the "cachedPixels" array and so changing one would change the other, and the system would collapse.
P.S. The rules you're using for your GoL are not the same as John H. Conway's. Cells always live on the next time step if they have 3 neighbours, and live on the next time step with 2 neighbours only if they are alive in this time step, else they die:
cachedPixels[i][j] = 0; // Default value - death.
if (neighbors == 3) {
cachedPixels[i][j] = 1;
} else if (thisCell == 1 && neighbors == 2) {
cachedPixels[i][j] = 1;
}
Your newborn pixels should not be counted as neighbours for this move, and your dying pixels should be counted. It can be achieved by having another values, say 2 and 3, for newborn and dying pixels. After processing the field, you commit its state by replacing a value for newborn with 1 and a value for dying with 0.
I've been lurking and found heaps of great information form here, however the last few days I have been stuck and haven't been able to find help with my issue so I thought id post.
I have some homework and I have to make the contents of my array drop down to the bottom row. If i rotate the grid the items should still drop down to the bottom row and if i eat an object from the bottom row, everything above it in that column should drop down too.
Any help is greatly appreciated.
Here is a demo video of what should happen:
http://youtu.be/CB07vN-C_-Y
This is what i have so far:
`public class Assignment
{
// This method should return a *new copy* of
// the 2D cell matrix, with entries rotated clockwise
// The original matrix should not be changed
public static int[][] rotateClockwise(int[][] cells)
{
int w = cells.length;
int h = cells[0].length;
int[][] matrix = new int[h][w];
for (int i = 0; i < h; ++i)
{
for (int j = 0; j < w; ++j)
{
matrix[i][j] = cells[j][h - i - 1];
}
}
return matrix;
}
// This method should return a *new copy* of
// the 2D cell matrix, with entries rotated anti-clockwise
// The original matrix should not be changed
public static int[][] rotateAnticlockwise(int[][] cells)
{
int w = cells.length;
int h = cells[0].length;
int[][] matrix = new int[h][w];
for (int i = 0; i < h; ++i)
{
for (int j = 0; j < w; ++j)
{
matrix[i][j] = cells[w - j - 1][i];
}
}
return matrix;
}
// This method should return a *new copy* of the array, except
// that if there is a 0 that has a non-zero in the preceding
// slot in the array, then those two entries should be swapped
// See ProgrammingProject.pdf for an example
// The original array should not be changed
public static int[] dropOne(int[] column)
{
return column; // this will compile but gives the wrong result
}
}`
I'd model a column as a Queue<Icon> col = new LinkedList<Icon>(); there's an outline here for Queue<Segment> and a complete example here for Queue<Bauble>. You can peek() at the head (bottom) of the queue; if it's empty, you remove() a block from the column and add() it to the tail (top).
Addendum: You might start with this example, drop the getGray(), change the layout to new GridLayout(0, 1). Then, instead of shuffle(list), you'd cycle the queue.
for(int i = 0; i < arrayWidth; i++) {
boolean reachedZero = false;
for( int j = 0; j < arrayHeight; j++) {
if(array[i][j] == 1 && reachedZero == true) {
while( j >=0 && array[i][j - 1] == 0) {
array[i][j-1] = array[i][j];
array[i][j] = 0;
j--;
reachedZero = false;
}
j--; // Maybe an error here, it's late
if( array[i][j] == 0) {
reachedZero = true;
}
}
}
This was posted by a lovely redditor (RankWeis) from the /learnprogramming sub-reddit.
http://www.reddit.com/r/learnprogramming/comments/126597/java_help_needed_on_adding_a_gravity_effect_to/