I am doing a version of the 8 queens problem, but not using the backtracking method. For one of the methods, I have to "score the square", basically I need to find the number of cells that would become unavailable were there to be a queen placed in the box. My problem is that I cannot get my code to return the score of the square. Is there something wrong with my for loops or something?
import java.util.ArrayList;
public class Chessboard {
private int[][] board;
public static final int QUEEN = -2;
public static final int SQUIGGLE = -1;
/**
* constructor initializes board to be of size n-by-n and containing all
* zeros
*/
public Chessboard(int n) {
board = new int[n][n];
}
/**
* returns the board
*/
public int[][] getBoard() {
return board;
}
/**
* returns SQUIGGLE if square at row, col contains SQUIGGLE returns QUEEN if
* square at row, col contains QUEEN otherwise, counts the number of squares
* that would become unavailable if the square at row, col were to receive a
* queen; this count is returned
*/
public int scoreSquare(int row, int col) {
if (board[row][col] == -1) {
return SQUIGGLE;
} else if (board[row][col] == -2) {
return QUEEN;
}
else {
int countsquare = 1;
for (int r = 0; r < board[col].length; r++) {
countsquare++;
}
for (int c = 0; c < board[row].length; c++) {
countsquare++;
}
for (int r = row + 1, c = col + 1; r < board.length
&& c < board.length; r++, c++) {
countsquare++;
}
for (int r = row + 1, c = col - 1; r < board.length && c < 0; r++, c--) {
countsquare++;
}
for (int r = row - 1, c = col + 1; r < 0 && c < board.length; r--, c++) {
countsquare++;
}
for (int r = row - 1, c = col - 1; r < 0 && c < 0; r--, c--) {
countsquare++;
}
return countsquare;
}
}
In every loop where you compare r or c to zero, you need to use >= instead of <. For example, in this loop, you need to use c >= 0 as opposed to c < 0:
for (int r = row + 1, c = col - 1; r < board.length && c < 0; r++, c--) {
This is because you are counting down to zero and so you want to keep counting while your counter is above zero.
Finally, although it shouldn't affect your results, you don't really need your first two loops as each of them should just result in adding n (which is board.length, i.e., the size of any row or column).
Related
Given a 2 X 2 matrix, return different island sizes that is possible
For example, the following matrix should return [5, 7].
1 0 0 0 1
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1
This is fairly straightforward problem. I am using a boolean visited matrix of same size and traverse the matrix in DFS fashion. I have implemented it here. for some reason, I am getting output as [1]. I tried debugging but my mind stopped working now. I am missing something silly I believe.
public class IslandConnectedCell {
public static void main(String[] args) {
int[][] input = {
{1,0,0,0,1},
{1,1,1,1,1},
{0,0,0,0,0},
{1,1,0,1,1}
};
dfsIsland(input);
}
public static void dfsIsland(int[][] input) {
int rows = input.length;
int cols = input[0].length;
List<Integer> countList = new ArrayList<>();
boolean visited[][] = new boolean[rows][cols];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; cols++) {
if (input[row][col] == 1 && !visited[row][col]) {
int count = mark(row, col, input, visited, rows, cols, 0);
countList.add(count);
}
}
}
System.out.println(countList);
}
public static int mark(int row, int col, int[][] input, boolean[][] visited, int rows, int cols, int count) {
if (row >= rows || row < 0 || col >= cols || col < 0) {
return 0;
}
if (input[row][col] == 0 || visited[row][col]) {
return 0;
}
visited[row][col] = true;
count+=1;
for (int i = row - 1; i <= row + 1; i++) {
for (int j = col - 1; j <= col + 1; j++) {
if (i != row || j != col) {
mark(i, j, input, visited, rows, cols, count);
}
}
}
return count;
}
}
There are two errors in your code.
See comment by Mick for first error:
One obvious problem in dfsIsland() is at least that for (int col = 0; col < cols; cols++) should probably be for (int col = 0; col < cols; col++) instead (maybe even better to use the common i and j for the row/col indices).
Second error is your use of count in the mark method, most glaringly the lack of using the return value in the recursive call. Remember, Java is pass-by-value.
Hint: I suggest you remove count as a parameter.
Once you fix the errors, output will be:
[7, 2, 2]
public class IslandConnectedCell {
public static void main(String... args) {
int[][] board = { {1,0,0,0,1},
{1,1,1,1,1},
{0,0,0,0,0},
{1,1,0,1,1} };
System.out.println(new IslandConnectedCell(board).getIslandSizes());
}
private final int[][] board;
private final int rows;
private final int cols;
public IslandConnectedCell(int[][] board) {
this.board = board;
this.rows = board.length;
this.cols = board[0].length;
}
public List<Integer> getIslandSizes() {
boolean visited[][] = new boolean[this.rows][this.cols];
List<Integer> countList = new ArrayList<>();
for (int row = 0; row < this.rows; row++)
for (int col = 0; col < this.cols; col++)
if (this.board[row][col] == 1 && ! visited[row][col])
countList.add(mark(row, col, visited));
return countList;
}
private int mark(int row, int col, boolean[][] visited) {
if (row >= this.rows || row < 0 || col >= this.cols || col < 0 || this.board[row][col] == 0 || visited[row][col])
return 0;
visited[row][col] = true;
int count = 1;
for (int r = -1; r <= 1; r++)
for (int c = -1; c <= 1; c++)
if (r != 0 || c != 0)
count += mark(row + r, col + c, visited);
return count;
}
}
UPDATE
To get the desired output of [7, 4] (original question), the board would need to use horizontal wraparound, so the two small islands on the bottom line becomes a single larger island.
That is easily accomplished by modifying one line of code to wraparound the column index using the % modulus operator:
count += mark(row + r, (col + c + this.cols) % this.cols, visited);
I have a project at school where I have to create a Sudoku Program. I have managed to get a Solver algorithm working but not a Generator. I spent a lot of time online to see if people had found ways to make a working one and I found a man named Mark Fredrick Graves, Jr. (https://www.youtube.com/user/mfgravesjr) who provided a very detailed code on the creation of a sudoku grid on his GitHub (https://github.com/mfgravesjr/finished-projects/tree/master/SudokuGridGenerator). However, I felt that using a one dimensional array was unnecessarily difficult in terms of finding the equations to access lines, columns and boxes. I therefore tried to translate his code into a two dimensional array but I am running into issues with some of his sorting methods and what some variables represent like "int step = (a%2==0? rowOrigin + j: colOrigin + j*9);". What I would like to know is how to translate the methods he uses from one dimensional arrays into two dimensional arrays. Below are the methods (code snippets) in question and my half attempt at translating it myself.
public int[] generateGrid(){
ArrayList<Integer> arr = new ArrayList<Integer>(9);
solvedGrid = new int[81];
for(int i = 1; i <= 9; i++) arr.add(i);
//loads all boxes with numbers 1 through 9
for(int i = 0; i < 81; i++){
if(i%9 == 0) {
Collections.shuffle(arr);
}
int perBox = ((i / 3) % 3) * 9 + ((i % 27) / 9) * 3 + (i / 27) * 27 + (i % 3);
solvedGrid[perBox] = arr.get(i%9);
}
//tracks rows and columns that have been sorted
boolean[] sorted = new boolean[81];
for(int i = 0; i < 9; i++){
boolean backtrack = false;
//0 is row, 1 is column
for(int a = 0; a<2; a++){
//every number 1-9 that is encountered is registered
boolean[] registered = new boolean[10]; //index 0 will intentionally be left empty since there are only number 1-9.
int rowOrigin = i * 9;
int colOrigin = i;
ROW_COL: for(int j = 0; j < 9; j++){
//row/column stepping - making sure numbers are only registered once and marking which cells have been sorted
int step = (a%2==0? rowOrigin + j: colOrigin + j*9);
int num = solvedGrid[step];
if(!registered[num]) {
registered[num] = true;
}else {
//if duplicate in row/column
//box and adjacent-cell swap (BAS method)
//checks for either unregistered and unsorted candidates in same box,
//or unregistered and sorted candidates in the adjacent cells
for(int y = j; y >= 0; y--){
int scan = (a%2==0? i * 9 + y: i + 9 * y);
if(solvedGrid[scan] == num){
//box stepping
for(int z = (a%2==0? (i%3 + 1) * 3: 0); z < 9; z++){
if(a%2 == 1 && z%3 <= i%3) {
continue;
}
int boxOrigin = ((scan % 9) / 3) * 3 + (scan / 27) * 27;
int boxStep = boxOrigin + (z / 3) * 9 + (z % 3);
int boxNum = solvedGrid[boxStep];
if((!sorted[scan] && !sorted[boxStep] && !registered[boxNum]) || (sorted[scan] && !registered[boxNum] && (a%2==0? boxStep%9==scan%9: boxStep/9==scan/9))){
solvedGrid[scan] = boxNum;
solvedGrid[boxStep] = num;
registered[boxNum] = true;
continue ROW_COL;
}else if(z == 8) {
//if z == 8, then break statement not reached: no candidates available
//Preferred adjacent swap (PAS)
//Swaps x for y (preference on unregistered numbers), finds occurence of y
//and swaps with z, etc. until an unregistered number has been found
int searchingNo = num;
//noting the location for the blindSwaps to prevent infinite loops.
boolean[] blindSwapIndex = new boolean[81];
//loop of size 18 to prevent infinite loops as well. Max of 18 swaps are possible.
//at the end of this loop, if continue or break statements are not reached, then
//fail-safe is executed called Advance and Backtrack Sort (ABS) which allows the
//algorithm to continue sorting the next row and column before coming back.
//Somehow, this fail-safe ensures success.
for(int q = 0; q < 18; q++){
SWAP: for(int b = 0; b <= j; b++){
int pacing = (a%2==0? rowOrigin+b: colOrigin+b*9);
if(solvedGrid[pacing] == searchingNo){
int adjacentCell = -1;
int adjacentNo = -1;
int decrement = (a%2==0? 9: 1);
for(int c = 1; c < 3 - (i % 3); c++){
adjacentCell = pacing + (a%2==0? (c + 1)*9: c + 1);
//this creates the preference for swapping with unregistered numbers
if((a%2==0 && adjacentCell >= 81)
|| (a%2==1 && adjacentCell % 9 == 0)) {
adjacentCell -= decrement;
}else {
adjacentNo = solvedGrid[adjacentCell];
if(i%3!=0
|| c!=1
|| blindSwapIndex[adjacentCell]
|| registered[adjacentNo]) {
adjacentCell -= decrement;
}
}
adjacentNo = solvedGrid[adjacentCell];
//as long as it hasn't been swapped before, swap it
if(!blindSwapIndex[adjacentCell]){
blindSwapIndex[adjacentCell] = true;
solvedGrid[pacing] = adjacentNo;
solvedGrid[adjacentCell] = searchingNo;
searchingNo = adjacentNo;
if(!registered[adjacentNo]){
registered[adjacentNo] = true;
continue ROW_COL;
}
break SWAP;
}
}
}
}
}
//begin Advance and Backtrack Sort (ABS)
backtrack = true;
break ROW_COL;
}
}
}
}
}
}
if(a%2==0) {
for(int j = 0; j < 9; j++) {
sorted[i*9+j] = true; //setting row as sorted
}
}else if(!backtrack) {
for(int j = 0; j < 9; j++) {
sorted[i+j*9] = true; //setting column as sorted
}
}else {//reseting sorted cells through to the last iteration
//backtrack = false;
for(int j = 0; j < 9; j++) {
sorted[i*9+j] = false;
}
for(int j = 0; j < 9; j++) {
sorted[(i-1)*9+j] = false;
}
for(int j = 0; j < 9; j++) {
sorted[i-1+j*9] = false;
}
for(int j = 0; j < 81; j++) {
sorted[j] = false;
}
i-=2;
}
}
}
if(!isPerfect(solvedGrid)) {
throw new RuntimeException("ERROR: Imperfect grid generated.");
}
return solvedGrid;
}
My code (unfinished)
public int[][] generateGrid(){
ArrayList<Integer> arr = new ArrayList<Integer>(9);
ArrayList<Integer> values = new ArrayList<Integer>(9);
solvedGrid = new int[9][9];
for(int i = 1 ; i <= 9; i++) {
arr.add(i);
values.add(i);
}
//Fill all boxes with number 1 to 9
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(j == 0) {
Collections.shuffle(arr);
}
solvedGrid[(i/3)*3+(j/3)][(i%3)*3+(j%3)] = arr.get(j);
}
}
//boolean[][] sorted = new boolean[9][9];
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
int[] rowColValues = new int[9];
rowColValues[j] = solvedGrid[0][j];
ArrayList<Integer> occurence = new ArrayList<Integer>();
for(int k = 0; k < rowColValues.length; k++) {
occurence.add((k+1), occurence.get(k+1)+1);
if(occurence.get(k+1) != 1) {
//swap with number in the box that isn't already in rowColValues
//Not sure how to do this...
//Create a method that takes the correct variables as parameters ?
break;
}
}
//Read the sudoku row then column wise and swap values that already exist in the column or row.
}
}
print2DGrid(solvedGrid);
return solvedGrid;
}
Conway's game of life with each cell being a thread
Hey guys,
So like the title says, I have to make a program that implements threading in Conway's game of life, where each dead or alive cell is a thread.
My first goal was to simply get the game working, which i did (pretty fun challenge)
So i can print the 20x20 grid, and each cell is initialized as a random number 1 or 0, where 1 is alive, and 0 is dead.
Now, I've been watching videos on how to use threading, but i'm still unsure as to how i'm supposed to implement this for each cell...
I have 3 classes, Main, Cell, and CellRules
my Cell class looks like:
public class Cell implements Runnable
{
public static int myCount = 0;
private String name;
private int neighbors;
private int alive; // 0 is dead; 1 is alive.
Random rand = new Random();
public Cell (String nm)
{
name = nm;
myCount = rand.nextInt(999);
neighbors = 0;
// 2 because it is exclusive
this.setLife(rand.nextInt(2));
}
public void run()
{
while(Cell.myCount <= 10){
try
{
System.out.println("Expl Thread: " + (++Cell.myCount));
Thread.sleep(100);
} catch (InterruptedException iex)
{
System.out.println("Exception in thread:
"+iex.getMessage());
}
}
}
There are a few other things in there, that are really for simplicity, i don't believe they are necessary to be shown, and same thing for the Cell Rules class. Cell Rules looks like:
/**
* This function simply gets the number of neighbors for each cell, and saves the future generation
* based on the number neighbors from arr to future array.
*
* #param arr Arr that will be checked for neighbors
* #param futureGen This array will keep track of the future generation
* #param columns numbers of columns
* #param rows numbers of rows
*/
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows)
{
for (int x = 0; x < rows; x++)
{
for (int y = 0; y < columns; y++)
{
arr[x][y].setNeighbors(0);
// Upper left corner
if (x == 0 && y == 0)
for (int i = 0; i <= 1; i++)
for (int j = 0; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Upper margin checks
if ((x == 0) && (y != 0 && y <= columns - 2))
for(int i = 0; i <= 1; i++)
for(int j = -1; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Upper right corner
if ((x == 0) && (y == columns - 1))
for(int i = 0; i <= 1; i++)
for(int j = -1; j <= 0; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Left margin checks
if ((y == 0) && (x != 0 && x <= rows - 2))
for (int i = -1; i <= 1; i++)
for (int j = 0; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Lower left corner
if ((x == rows - 1) && y == 0)
for (int i = -1; i <= 0; i++)
for (int j = 0; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Bottom margin checks
if ((x == rows - 1) && (y != 0 && y <= columns - 2 ))
for (int i = -1; i <= 0; i++)
for (int j = -1; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Lower right corner
if ((x == rows - 1) && (y == columns - 1))
for (int i = -1; i <= 0; i++)
for (int j = -1; j <= 0; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Right margin checks
if ((y == columns - 1) && (x != 0 && x <= rows - 2))
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 0; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Middle area checks ( can check all around now )!
if ((x > 0) && (x < rows - 1) && (y > 0) && (y < columns - 1) )
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
// Do not add yourself!
if (arr[x][y].getLife() == 1)
arr[x][y].subNeighbor();
// Get the new generation through the neighbors
if ((arr[x][y].getLife() == 1) &&
(arr[x][y].getNeighbors() < 2))
futureGen[x][y].setLife(0);
else if ((arr[x][y].getLife() == 1) &&
(arr[x][y].getNeighbors() > 3))
futureGen[x][y].setLife(0);
else if ((arr[x][y].getLife() == 0) &&
(arr[x][y].getNeighbors() == 3))
futureGen[x][y].setLife(1);
else
futureGen[x][y].setLife(arr[x][y].getLife());
}
}
}
I'm not sure where the implementation of the threads really goes, Any guidance or explanations would be greatly appreciated!
Have a nice day :)
First of all, your checkN function is way overengineered. Let's simplify it a bit.
/**
* This function simply gets the number of neighbors for each cell, and saves the future generation
* based on the number neighbors from arr to future array.
*
* #param arr Arr that will be checked for neighbors
* #param futureGen This array will keep track of the future generation
* #param columns numbers of columns
* #param rows numbers of rows
*/
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) {
for (int x = 0; x < rows; x++) {
for (int y = 0; y < columns; y++) {
arr[x][y].setNeighbors(0);
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
if(i == 0 && j == 0) continue; //don't check self
if(x + i < 0 || x + i >= rows) continue; //bounds checking
if(y + j < 0 || y + j >= columns) continue; //bounds checking
if (arr[x + i][y + j].getLife() == 1)
arr[x][y].addNeighbor();
}
}
// Get the new generation through the neighbors
if(arr[x][y].getLife() == 1 &&
(arr[x][y].getNeighbors() == 2 || arr[x][y].getNeighbors() == 3))
futureGen[x][y].setLife(1);
else if(arr[x][y].getLife() == 0 && arr[x][y].getNeighbors() == 3)
futureGen[x][y].setLife(1);
else
futureGen[x][y].setLife(0);
}
}
}
We can then refactor this into a few extra functions:
private void countNeighbors(Cell[][] arr, int row, int column, int rows, int columns) {
Cell c = arr[row][column];
c.setNeighbors(0);
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
if(i == 0 && j == 0) continue; //don't check self
if(row + i < 0 || row + i >= rows) continue; //bounds checking
if(column + j < 0 || column + j >= columns) continue; //bounds checking
if (arr[row + i][column + j].getLife() == 1)
c.addNeighbor();
}
}
}
private void evaluateNeighbors(Cell oldCell, Cell newCell) {
if (oldCell.getLife() == 1 &&
(oldCell.getNeighbors() == 2 || oldCell.getNeighbors() == 3))
newCell.setLife(1);
else if(oldCell.getLife() == 0 && oldCell.getNeighbors() == 3)
newCell.setLife(1);
else
newCell.setLife(0);
}
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows) {
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
countNeighbors(arr, row, column, rows, columns);
evaluateNeighbors(arr[row][column], futureGen[row][column]);
}
}
}
The reason we're refactoring like this will become apparent in a moment.
So back to the original question: where do we insert threading into this program?
You need to make a decision on how you want to split up threads. Based on your question, it sounds like you want to launch an independent thread for each cell that gets evaluated. While there's not any problems with this approach in theory, this really doesn't guarantee any significant speedup, simply because at thousands of cells (which you will quickly hit for even modest sizes of grids) you'll be creating thousands of threads, and only mega-servers will have enough threads to take advantage of it.
Nonetheless, if that's what you want to do, the code (Java 8 required) looks like this:
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows)
{
ArrayList<Thread> threads = new ArrayList<>();
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
Integer thread_local_row = row;
Integer thread_local_column = column;
Thread t = new Thread(() -> {
countNeighbors(arr, thread_local_row, thread_local_column, rows, columns);
evaluateNeighbors(arr[thread_local_row][thread_local_column], futureGen[thread_local_row][thread_local_column]);
});
t.start();
threads.add(t);
}
}
for(Thread t : threads)
t.join();
}
The end result is that each cell will receive its own dedicated thread. Note how little we had to change once the code was refactored.
Like I mentioned, however, this is overkill in terms of the number of threads we're creating. So an alternative is to create a new thread for each row.
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows)
{
ArrayList<Thread> threads = new ArrayList<>();
for (int row = 0; row < rows; row++) {
Integer thread_local_row = row;
Thread t = new Thread(() -> {
for (int column = 0; column < columns; column++) {
countNeighbors(arr, thread_local_row, column, rows, columns);
evaluateNeighbors(arr[thread_local_row][column], futureGen[thread_local_row][column]);
}
});
t.start();
threads.add(t);
}
for(Thread t : threads)
t.join();
}
This is better, but of course, it once again could become overkill if you have a lopsided grid that has lots of rows but very few columns.
So a third option is to make the number of threads constant, and scale the workload per thread to fit the number of threads.
public void checkN(Cell [][] arr, Cell [][] futureGen, int columns, int rows)
{
ArrayList<Thread> threads = new ArrayList<>();
final int NUM_OF_THREADS = 8; //Or can be passed as an argument
for(int tid = 0; tid < NUM_OF_THREADS; tid++) {
Integer thread_local_row_start = tid * rows / NUM_OF_THREADS;
Integer thread_local_row_end = (tid + 1) * rows / NUM_OF_THREADS;
Thread t = new Thread(() -> {
for (int row = thread_local_row_start; row < thread_local_row_end; row++) {
for (int column = 0; column < columns; column++) {
countNeighbors(arr, row, column, rows, columns);
evaluateNeighbors(arr[row][column], futureGen[row][column]);
}
}
});
t.start();
threads.add(t);
}
for(Thread t : threads)
t.join();
}
This option tends to be the most performant, since you can set NUM_OF_THREADS to be equal to the number of processor cores in your machine, or whatever value you find in testing to yield ideal performance.
You can use any of these techniques, or else come up with a different technique to split up the threads (for example, maybe an algorithm that perfectly splits the workloads, rather than rounding to nearest-row-counts?). The important part is simply keeping your code organized well enough to facilitate your workload splitting mechanism.
If you're limited to Java 7, all of the code written can still be used, but the lambda structure needs to be replaced with an Anonymous Inner Class, and any variables that need to be used in the thread body need to be made final:
public void checkN(final Cell [][] arr, final Cell [][] futureGen, final int columns, final int rows)
{
ArrayList<Thread> threads = new ArrayList<>();
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
final Integer thread_local_row = row;
final Integer thread_local_column = column;
Thread t = new Thread(new Runnable() {
public void run() {
countNeighbors(arr, thread_local_row, thread_local_column, rows, columns);
evaluateNeighbors(arr[thread_local_row][thread_local_column], futureGen[thread_local_row][thread_local_column]);
}
});
t.start();
threads.add(t);
}
}
for(Thread t : threads)
t.join();
}
The following pice of code is my code for my Game of Life. For some reason it works very strangely. The first few steps of the game are wrong, and then the whole output turns to zeroes. I don't know which method is causing the problem, but I assume it is the count neighbors method.
The board is a 2D array called GOLBoard, and the x and y coordinates are cellRow and cellCol. Alive cells are 1, and dead cells are 0s. The way I avoid out of bounds problems are by making the board 12x12, but I use only 1 to 11 for rows and columns.
<code> #Override
public int countNeighbours(int cellRow, int cellCol) {
int neighbours = 0;
for (int i = cellRow-1; i < cellRow + 2; i++) {
for (int j = cellCol - 1; j < cellCol + 2; j++) {
if (GOLBoard[i][j] == 1) {
neighbours += 1;
}
}
}
if (GOLBoard[cellRow][cellCol] == 1) {
return(neighbours-1);
} else {
return(neighbours);
}
}
#Override
public int applyRules(int cellRow, int cellCol) {
int alive = 0;
if (GOLBoard[cellRow][cellCol] == 1) {
if (countNeighbours(cellRow, cellCol) == 2 || countNeighbours(cellRow, cellCol) == 3) {
alive = 1;
} else if (countNeighbours(cellRow, cellCol) < 2 || countNeighbours(cellRow, cellCol) > 3) {
alive = 0;
}
}
if (GOLBoard[cellRow][cellCol] == 0) {
if (countNeighbours(cellRow, cellCol) == 3) {
alive = 1;
}
}
return (alive);
}
#Override
public void takeStep() {
for (int row = 1; row < 11; row++) {
for (int col = 1; col < 11; col++) {
GOLBoard[row][col] = applyRules(row, col);
}
}
}
#Override
public String toString() {
for (int row = 1; row < 11; row++) {
for (int col = 1; col < 11; col++) {
System.out.print("[" + GOLBoard[row][col] + "]");
}
System.out.println("");
}
return("");
}
} <code>
If I am recalling the rules of GOL correctly, the evolution of the board should proceed in a series of "generations", wherein the state of each cell on a "new" board is determined solely by the conditions of the corresponding cell on the "old" board. Your program is trying to continuously evolve a single board, so that changes to previously computed cells are affecting the outcome of cells yet to be computed. Your takeStep routine should be doing something more like this:
newBoard = new int[12][12];
for (int row = 1; row < 11; row++) {
for (int col = 1; col < 11; col++) {
newBoard[row][col] = applyRules(row, col);
}
}
GOLBoard = newBoard;
As far as I can tell, your countNeighbours is OK.
On my program for java programming is not running right. My professor had us download a console.java to help use make a console to display our outputs of the program. I think the program is getting stuck when I am calling the update method and checkCells. My professor said that calling matrix.length for both rows and columns is incorrect but I'm stumped on how to call columns if I am not using matrix.length.
Any input is appreciated
import java.util.*;
public class Life {
private int birthLow = 0;
private int birthHigh = 0;
private int liveLow = 0;
private int liveHigh = 0;
private boolean[][] matrix;
public Life(long seed, int rows, int cols, int birthLow2, int birthHigh2, int liveLow2, int liveHigh2) {
boolean initalMatrix[][] = new boolean[rows][cols];
seedArray(initalMatrix, rows, cols, seed);
birthLow = birthLow2;
birthHigh = birthHigh2;
liveLow = liveLow2;
liveHigh = liveHigh2;
matrix = initalMatrix;
if ((rows < 1) && (cols < 1)) {
throw new IllegalArgumentException("Rows must be positive, not " + rows);
}
if ((rows > 9) && (cols < 9)) {
throw new IllegalArgumentException("Rows and cols cant go over 9, not " + rows + cols);
}
if (birthLow < 1 || (birthHigh > 9) || (liveLow < 1) || (liveHigh > 9)) {
throw new IllegalArgumentException("birth rates can not be below 1 or above 9 " + birthLow + birthHigh);
}
}
public boolean[][] world() {
boolean[][] matrixClone = matrix.clone();
for (int row = 0; row < matrix.length; row++) {
matrixClone[row] = matrix[row].clone();
}
return matrixClone;
}
public void update() {
matrix = checkCells(matrix, matrix.length, matrix.length, birthLow, birthHigh, liveLow, liveHigh);
}
public static void seedArray(boolean[][] matrix, int rows, int cols, long seed) {
// generates a random seed to fill the matrix
Random s = new Random(seed);
for (int r = 1; r < rows - 1; r++) {
for (int c = 1; c < cols - 1; c++) {
boolean x = s.nextBoolean();
matrix[r][c] = x;
}
}
}
public static void printBoard(boolean[][] matrix, int rows, int cols) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (matrix[r][c] == false && c == 0) {
System.out.print("- ");
} else if (matrix[r][c] == false && c > 0) {
System.out.print("- ");
} else if (matrix[r][c] == true) {
System.out.print("# ");
}
}
System.out.println();
}
System.out.println();
}
public static boolean[][] checkCells(boolean[][] matrix, int rows, int cols, int birthLow, int birthHigh,
int liveLow, int liveHigh) {
// clones matrix board
boolean[][] matrixClone = matrix.clone();
for (int row = 0; row < matrix.length; row++) {
matrixClone[row] = matrix[row].clone();
}
// determines if the living cell is going to live or die
for (int r = 1; r < rows; r++) {
for (int c = 1; c < cols; c++) {
if (neighbors(matrixClone, r, c) < liveLow || neighbors(matrixClone, r, c) > liveHigh || c == 0
|| r == 0 || c == cols - 1 || r == rows - 1) {
matrix[r][c] = false;
} else if (neighbors(matrixClone, r, c) >= birthLow && neighbors(matrixClone, r, c) <= birthHigh) {
matrix[r][c] = true;
}
}
}
return matrixClone;
}
public static int neighbors(boolean[][] matrixClone, int r, int c) {
int neighbors = 0;
// checks all neighbors for life or death
for (int rn = (r - 1); rn <= (r + 1); rn++) {
for (int cn = (c - 1); cn <= (c + 1); cn++) {
try {
if (matrixClone[rn][cn] == true) {
neighbors++;
}
// catches the array if it checks out the perimeter
} catch (ArrayIndexOutOfBoundsException f) {
continue;
}
}
}
return neighbors;
}
}
Don't use matrix.length for columns. You already know that. The reason is that it gives you the number of rows. Instead, just save the values of row and col and use them.
One way to do that is to make them fields, and initialize them in your constructor.
Do not initialize a random boolean[][] called initialMatrix. Instead, initialize the boolean[][] matrix that you have in the fields up above (matrix = new boolean[rows][cols]). Then for seedArray, call seedArray(matrix, rows, cols, seed).
Finally, in the update() method, do not use matrix.length, but rather rows and cols.