I saw Conway's Game of Life and wanted to make my own. However the cells at the edges somehow don't follow the rules and just stay alive (or dead) the whole time. Does anybody know where I made the mistake?
This is my code: (I only uploaded the class where I applied the rules. If the other classes are needed to solve the problem, I can upload them as well)
import java.util.Arrays;
/**
* The class Grid does the initialization of the game of life and the application of the rules.
* It is a 2D array of the type Cell. It saves the cells and uses a copy of it to apply the rules.
*
*/
public class Grid
{
public int col;
public int row;
public int x,y;
public Cell [][] array; //2D array of the type Cell
public Cell [][] arraycopy;
/**
* This constructor is to create the initial generation of cells and set the state of random 20% to true (=alive).
* #param col the number of columns
* #param row the number of rows
*
*/
public Grid(int col, int row)
{
this.col = col;
this.row = row;
this.array = new Cell [col][row];
//Loops through every spot in the 2D array
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
//set randomly 20% of the cells' state to "true"
if (Math.random() <= 0.2)
{
Cell cell = new Cell (true);
this.array[x][y]= cell;
}
else
{
Cell cell = new Cell (false);
this.array[x][y]= cell;
}
}
}
}
/**
* This method will count the alive cells in a 3*3 neighboorhood and apply the rules of life.
* This method uses arraycopy.
*
*/
public void lifeSteps()
{
//Works with a copy of the array and the cells
this.arraycopy = new Cell [col][row];
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
this.arraycopy [x][y] = new Cell(this.array[x][y].getState());
}
}
//Looping through the cells, but the cells at the edge are skipped
for (int x = 1; x < col-1; x++)
{
for (int y= 1; y < row-1; y++)
{
//Looping through all the neighbors
int numNeighborsAlive = 0;
for (int i = x-1; i <= x+1; i++)
{
for (int j = y-1; j <= y+1; j++)
{
//In a 3x3 neighborhood the middle cell needs to be skipped
if ((x != i) && (y != j))
{
//Only the cells that are alive (true) are added
if (arraycopy [i][j].getState() == true)
{
numNeighborsAlive += 1;
}
}
}
}
//Apply the rules of life
if ((array [x][y].getState()) && (numNeighborsAlive < 2 || numNeighborsAlive >3)) //Loneliness and Overpopulation
{
array[x][y].setState(false);
}
else if ((array [x][y].getState() == false) && (numNeighborsAlive ==3)) //Birth
{
array[x][y].setState(true);
}
else
{ //stasis
}
}
}
}
/**
* This method will return the statement for the array.
* #return the 2D array of the type Cell
*/
public Cell[][] returnGrid ()
{
return this.array;
}
/**
* This method will test if everything is working well by printing zeros and ones.
*
*/
public void printTest()
{
System.out.println("\t"); // a new line
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
// assigns 1 if the cell is alive and 0 if it is dead
if (array[x][y].getState() == true)
{
System.out.print("1");
}
else
{
System.out.print("0");
}
}
System.out.println(""); // will be displayed as colums and rows
}
System.out.println("\t"); // a new line
}
}
The borders are not processed, so there are always 8 neighbors.
One can handle all array positions, and determine the neighbors. These could be hardwired in the cell at initialisation, or - as below - determined dynamically.
For that I use an offset vector with a delta x and delta y in -1, 0, 1.
private static final int[][] MIDDLE_NEIGHBORS =
{
{-1, -1}, {-1, 0}, {-1, 1},
{0, -1}, {0, 1},
{1, -1}, {1, 0}, {1, 1}
};
private static final int[][] LEFT_TOP_NEIGHBORS =
{
{0, 1},
{1, 0}, {1, 1}
};
...
int[][] neighborDeltaXY(int x, int y, int col, int row) {
if (1 < x && x < col-1 && 1 < y && y < row-1) {
return MIDDLE_NEIGHBORS;
}
if (x == 0 && row == 0) {
return LEFT_TOP_NEIGHBORS;
}
...
}
Or you might be more comfortable with nested conditions:
int[][] neighborDeltaXY(int x, int y, int col, int row) {
if (x == 0) {
if (y == 0) {
return LEFT_TOP_NEIGHBORS;
} else if (y == row - 1) {
return ...;
} else {
return ...;
}
} else if (x == col - 1) {
if (y == 0) {
return ...;
} else if (y == row - 1) {
return ...;
} else {
return ...;
}
} else {
if (y == 0) {
return ...;
} else if (y == row - 1) {
return ...;
} else {
return MIDDLE_NEIGHBORS;
}
}
}
Useful is to have a method doing the actual counting on the board:
int countNeighborsAlive(Cell[][] old, int x, int y, int col, int row) {
int numNeighborsAlive = 0;
int[][] neighbors = neighborDeltaXY(x, y, col, row);
for (int[] neighbor : neighbors) {
int xn = x + neighbor[0];
int yn = y + neighbor[1];
if (old[xn][yn].getState()) {
++numNeighborsAlive;
}
}
return numNeighborsAlive;
}
So the time loop becomes simpler:
for (int x = 0; x < col; x++) {
for (int y= 0; y < row; y++) {
int numNeighborsAlive = countNeighborAlive(arraycopy, x, y, col, row);
... numNeighborsAlive
In the game of life one could make different geometries, having above y == 0 the y == row - 1, so the world wraps around the borders.
Also feasible is to take the original board and place it in a larger grid, so the visible cells are in [1, col - 1), [1, row - 1). The invisible borders then always remain 0. Not so nice for the game of life, but other grid based games are so walled in.
Instead Do Or
x += 1; ++x; x++
if (c == true) if (c)
if (d == false) if (!d)
Related
So this question is really 2 questions in 1 relating to an assignment. I have to make a program that reads a map from a file containing land, water, sandbag, and house tiles into a 2d array and GUI displaying the map.
When a button is pressed the water tiles spread to all land and house tiles that are touching it (horizontal, vertical, and diagonal) and then displays a message that tells you if the house was flooded or not.
This has to be done via a recursive method, I have a program that works for the most part utilizing 8 if statements which I believe is incredibly inefficient and also doesn't really fit the assignment requirements. How could I make this recursive?
My second problem which I think is related to the way I approached the flooding question is that my method that checks if the house is still standing always displays the house was flooded message even if the house was standing.
I've been trying to fix this for days, any insight would be much appreciated. (I also previously had a problem where having for loops in my checkForHouse method would cause my program to freeze and have to be closed through task manager, it randomly stopped doing this even though I didn't change anything not sure if that helps).
public static void Flood(JLabel[][] labelArray, JPanel panel) {
//Timer that allows the GUI to update slowly so progression can be seen
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
boolean running = true;
while(running) {
//Checks through the entire array to find water tiles
for (int i = 0; i < labelArray.length; i++) {
for (int j = 0; j < labelArray[0].length; j++) {
if (labelArray[i][j].getText().equals("W")) {
if(i > 0 && (labelArray[i-1][j].getText().equals("L") || labelArray[i-1][j].getText().equals("H"))) {//Checks the tile left of the water tile
labelArray[i-1][j].setText("W");
labelArray[i-1][j].setBackground(Color.BLUE);
}
else if(j > 0 && (labelArray[i][j-1].getText().equals("L") ||labelArray[i][j-1].getText().equals("H"))) {//Checks the tile above the water tile
labelArray[i][j-1].setText("W");
labelArray[i][j-1].setBackground(Color.BLUE);
}
else if(i < labelArray.length-1 && (labelArray[i+1][j].getText().equals("L") || labelArray[i+1][j].getText().equals("H"))){//Checks the tile to the right of the water tile
labelArray[i+1][j].setText("W");
labelArray[i+1][j].setBackground(Color.BLUE);
}
else if(j < labelArray[0].length-1 && (labelArray[i][j+1].getText().equals("L") || labelArray[i][j+1].getText().equals("H"))) {//Checks the tile below the water tile
labelArray[i][j+1].setText("W");
labelArray[i][j+1].setBackground(Color.BLUE);
}
else if(j < labelArray[0].length-1 && i < labelArray.length-1 && (labelArray[i+1][j+1].getText().equals("L") || labelArray[i+1][j+1].getText().equals("H"))) {//Checks the tile to the bottom right of the water tile
labelArray[i+1][j+1].setText("W");
labelArray[i+1][j+1].setBackground(Color.BLUE);
}
else if(j > 0 && i > 0 && (labelArray[i-1][j-1].getText().equals("L") || labelArray[i-1][j-1].getText().equals("H"))) {//Checks the tile to the top left of the water tile
labelArray[i-1][j-1].setText("W");
labelArray[i-1][j-1].setBackground(Color.BLUE);
}
else if(j > 0 && i < labelArray.length-1 && (labelArray[i+1][j-1].getText().equals("L") || labelArray[i+1][j-1].getText().equals("H"))) {//Checks the tile to the top right of the water tile
labelArray[i+1][j-1].setText("W");
labelArray[i+1][j-1].setBackground(Color.BLUE);
}
else if(j < labelArray[0].length-1 && i > 0 && (labelArray[i-1][j+1].getText().equals("L") || labelArray[i-1][j+1].getText().equals("H"))) {//Checks the tile to the bottom left of the water tile
labelArray[i-1][j+1].setText("W");
labelArray[i-1][j+1].setBackground(Color.BLUE);
}
}
}
}
running = false;
checkForHouse(labelArray);
}
}
};
new Timer(250, taskPerformer).start();
}
public static void checkForHouse (JLabel[][] labelArray) {
for (int r =0; r<labelArray.length; r++) {
for (int c =0;c<labelArray[0].length; c++) {
if(labelArray[r][c].getText().equals("H")) {
textArea.setText(safeHouse);
}
else {
textArea.setText(floodedHouse);
}
}
}
}
Updated based on comment
water can flow all the way to boundary
water can flow to adjacent land or adjacent house and they become water
water can not flow to adjacent sandbag
based on point 3, water surrounded on all sides by sandbag will not flow
traverse recursively from every newly filled land or house
using 2 for loop, iterate over all the cells
for any cell that has 'W', call another function
the another function will recursively update any adjacent land or house
final int[] x = new int[] {-1, -1, -1, 0, 0, 1, 1, 1};
final int[] y = new int[] {-1, 0, 1, -1, 1, -1 0, 1};
final char HOUSE = 'H'
final char LAND = 'L';
final char WATER = 'W';
final char WATERED_HOUSE = 'A';
final char WATERED_LAND = 'B';
final char SANDBAG = 'S'; // not used and is not needed
void process(char[][] input) {
for (int row = 0; row < input.length; row++) {
for (int col = 0; col < input[row].length; col++) {
if (input[row][col] == WATER) {
processNeighbor(input, row, col);
}
}
}
// if a cell is WATERED_HOUSE, then update text (if not done in processNeighbor function)
for (int row = 0; row < input.length; row++) {
for (int col = 0; col < input[row].length; col++) {
if (input[row][col] == WATERED_HOUSE) {
// set text
}
// if needed for WATERED_HOUSE and WATERED_LAND,
// change back to WATER and LAND respectively
}
}
}
void processNeighbor(char[][] input, final int row, final int col) {
for (int adj = 0; adj < adjCount; adj++) {
final int hor = col + x[adj];
final int ver = row + y[adj];
// stop recursion if neighbor is a not any one of house or land.
if (!isValid(input, ver, hor) || !(input[ver][hor] == LAND || input[ver][hor] == HOUSE)) {
continue;
}
// modify state to help recursion to end
// if modification is not allowed, then maintain separate visited state
if (input[ver][hor] == HOUSE) {
input[ver][hor] = WATERED_HOUSE;
// note: can set flooded here or in a separate loop later
} else if (input[ver][hor] == LAND) {
input[ver][hor] = WATERED_LAND;
}
// process any unprocessed neighbor recursively
processNeighbor(input, ver, hor);
}
}
// check whether given cell is within grid
boolean isValid(char[][] input, final int row, final int col) {
return row >= 0 && row < input.length && col >= 0 && col < input[row].length;
}
Original
This following logic assumes that water will flow only to 1 adjacent tile. Is that a valid assumption?
separation of logic and bfs
Use additional labels. 'A' can represent watered house.
using additional label simplifies the code and avoid forward modifications of 'H' to 'W', which the subsequent iterations will consider as 'W' incorrectly (while its actually a 'H' with 'W' and not initially a 'W')
2 loops in another outer function which calls another function if 'W' is seen at the cell
the second function will run a for loop with directions and updates the adjancent locations if they are 'H'
finally run one more 2 loop and change all 'A' to 'W' and change color
you can add similar check for land also
// can make this an unmodifiable list to avoid accidental modification
// LU L LD U D RU R RD
final int[] x = new int[] {-1, -1, -1, 0, 0, 1, 1, 1};
final int[] y = new int[] {-1, 0, 1, -1, 1, -1 0, 1};
final int adjCount = 8;
final char WATER = 'W';
final char HOUSE = 'H'
final char WATERED_HOUSE = 'A';
int process(char[][] input) {
int count = 0; // this is just to track and for any optimization
// initial processing to process cells adjacent to water
for (int row = 0; row < input.length; row++) {
for (int col = 0; col < input[row].length; col++) {
if (WATER == input[row][col]) {
count += processAdjacents(input, row, col);
}
}
}
final int modified = count;
// second round to set watered house to water and color
for (int row = 0; row < input.length; row++) {
// if needed can use count == 0 to break;
for (int col = 0; col < input[row].length; col++) {
// if needed can use count == 0 to break;
if (WATERED_HOUSE == input[row][col]) {
input[row][col] = WATER;
// set background color also
count--;
}
}
}
return modified;
}
// process adjacent cells of water cell
int processAdjacents(char[][] input, final int row, final int col) {
int count = 0;
for (int adj = 0; adj < adjCount; adj++) {
final int hor = col + x[adj];
final int ver = row + y[adj];
if (isValid(input, ver, hor) && HOUSE == input[ver][hor]) {
input[ver][hor] = WATERED_HOUSE;
count++;
}
}
return count;
}
// check whether given cell is within grid
boolean isValid(char[][] input, final int row, final int col) {
return row >= 0 && row < input.length && col >= 0 && col < input[row].length;
}
Disclaimer
Untested code and typed in SO
Did not use DFS
land not handled
Problem
You are given a two-dimensional array (matrix) of potentially unequal height and width containing only 0s and 1s. Each 0 represents land, and each 1 represents part of a river. A river consists of any number of 1s that are either horizontally or vertically adjacent (but not diagonally adjacent). The number of adjacent 1s forming a river determine its size. Write a function that returns an array of the sizes of all rivers represented in the input matrix. Note that these sizes do not need to be in any particular order.
Input
[
[1,0,0,1,0],
[1,0,1,0,0],
[0,0,1,0,1],
[1,0,1,0,1],
[1,0,1,1,0],
]
Output [1,2,2,2,5]
My Approach
After evaluating the problem i felt like this should be done using a graph traversal like algorithm maybe depth first search. So that is exactly what i do .
I traverse the matrix from top left and see if the value is visited and if it is not then and if the value is 1 then i traverse all it's nodes and keep a counter to keep size of the river. In the end i update an array list with the total river size.
For some reason my result is not correct and i am not sure what i did wrong. I hand traced my code too but can't figure out the issue.
My Code
import java.util.ArrayList;
class Program {
public static ArrayList<Integer> riverSizes(int[][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer>();
boolean [][] visitStatus = new boolean [matrix.length][matrix[0].length];
for(int row = 0; row<matrix.length; row++){
for(int col = 0; col<matrix.length; col++){
int count = 0;
count = traverseMatrix(row,col,matrix,visitStatus,count);
result.add(count);
}
}
return result;
}
public static int traverseMatrix(int row, int col, int [][] matrix, boolean [][] visitStatus, int count){
if(visitStatus[row][col] == true){
return count;
}else if(matrix[row][col] == 0){
visitStatus[row][col] = true;
return count;
}else{
count++;
visitStatus[row][col] = true;
if(isValid(row,col-1,matrix)){
return traverseMatrix(row,col-1,matrix,visitStatus,count);
}
if(isValid(row,col+1,matrix)){
return traverseMatrix(row,col+1,matrix,visitStatus,count);
}
if(isValid(row-1,col,matrix)){
return traverseMatrix(row-1,col,matrix,visitStatus,count);
}
if(isValid(row+1,col,matrix)){
return traverseMatrix(row+1,col,matrix,visitStatus,count);
}
}
return count;
}
public static boolean isValid(int row, int col,int[][] matrix){
return (row >= 0 && row < matrix.length) && (col >= 0 && col < matrix[0].length);
}
}
you are given a two-dimensional array (matrix) of potentially unequal height and widthÂ
But you are doing the operation for always same size of matrix both in height and width
for(int row = 0; row<matrix.length; row++){
for(int col = 0; col<matrix.length; col++){ .. }}
you should use the dimension like following way, rest of the things are enough well I guess
..
for(int row = 0; row<matrix.length; row++){
for(int col = 0; col<matrix[row].length; col++){ .. }}
and the changes need to apply in function 'isValid' also
public static boolean isValid(int row, int col,int[][] matrix){
return (row >= 0 && row < matrix.length) && (col >= 0 && col < matrix[row].length);
}
Convert count to a local variable and accumulate it:
static int traverseMatrix(int row, int col, int[][] matrix, boolean[][] visitStatus) {
if (visitStatus[row][col] || matrix[row][col] == 0) {
return 0;
}
visitStatus[row][col] = true;
int count = 1;
if (isValid(row, col - 1, matrix)) {
count += traverseMatrix(row, col - 1, matrix, visitStatus);
}
...
return count;
}
In addition to #OleksandrPyrohov's answer, also check if the current cell is visited already before calling traverseMatrix :
public static ArrayList<Integer> riverSizes(int[][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer>();
boolean [][] visitStatus = new boolean [matrix.length][matrix[0].length];
for(int row = 0; row<matrix.length; row++){
for(int col = 0; col<matrix.length; col++){
if ( !visitStatus[row][col] ) {
int count = 0;
count = traverseMatrix(row,col,matrix,visitStatus,count);
result.add(count);
}
}
}
return result;
}
My solution is written in C#, but it's similar to Java:
You can replace List with ArrayList
Code:
public static List<int> RiverSizes(int[,] matrix)
{
var sizes = new List<int>();
bool[,] visited = new bool[matrix.GetLength(0), matrix.GetLength(1)];
for (int row = 0; row < matrix.GetLength(0); row++)
for (int col = 0; col < matrix.GetLength(1); col++)
if (visited[row, col])
continue;
else
Traverse(matrix, row, col, visited, sizes);
return sizes;
}
public static void Traverse(int[,] matrix, int row, int col, bool[,] visited, List<int> sizes)
{
int currentSize = 0;
var toExplore = new List<int[]>
{
new int[] { row, col }
};
while (toExplore.Count > 0)
{
var current = toExplore[^1];
toExplore.RemoveAt(toExplore.Count - 1);
row = current[0];
col = current[1];
if (visited[row, col])
continue;
visited[row, col] = true;
if (matrix[row, col] == 0)
continue;
currentSize++;
foreach (int[] item in GetNeighbours(matrix, row, col, visited))
toExplore.Add(item);
}
if (currentSize > 0)
sizes.Add(currentSize);
}
public static List<int[]> GetNeighbours(int[,] matrix, int row, int col, bool[,] visited)
{
List<int[]> neighbours = new List<int[]>();
if (row > 0 && !visited[row - 1, col])
neighbours.Add(new int[] { row - 1, col });
if (row < matrix.GetLength(0) - 1 && !visited[row + 1, col])
neighbours.Add(new int[] { row + 1, col });
if (col > 0 && !visited[row, col - 1])
neighbours.Add(new int[] { row, col - 1 });
if (col < matrix.GetLength(1) - 1 && !visited[row, col + 1])
neighbours.Add(new int[] { row, col + 1 });
return neighbours;
}
I hope it helps ^-^
Please help me understand what I am doing wrong with my code. I am trying to get the shortest path using BFS to solve the problem but it's either giving me -1 or 2. It should give me 6 as the answer. What am I doing wrong? This is the problem:
Given a chess board, find the shortest distance(minimum number of steps) taken by a knight to reach given destination from given source.
For example, N = 8 (8 x 8 board), Source = (7, 0) Destination = (0, 7)
Minimum number of steps required is 6
My code is below:
class Point {
int x, y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
class knightShortestPath {
int N = 8;
public static boolean visited[][];
public boolean isPositionValid(int x, int y){
if( x < 0 || y < 0 || x > this.N || y > this.N){
return false;
}
return true;
}
public void createChessBoard(int N) {
this.N = N;
visited = new boolean[this.N][this.N];
for (int i = 0; i < this.N; i++) {
for (int j = 0; j < this.N; j++) {
visited[i][j] = false;
}
}
}
public int BFS(Point source, Point destination) {
int row[] = {2, 2, -2, -2, 1, 1, -1, -1};
int col[] = {1, -1, 1, -1, 2, -2, 2, -2};
Queue<Point> queue = new LinkedList<>();
queue.offer(source);
visited[source.x][source.y] = true;
int minimumNumSteps = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
Point pt = queue.poll();
if (pt.x == destination.x && pt.y == destination.y) {
return minimumNumSteps;
}
for (int j = 0; j < size; j++) {
Point next = new Point(pt.x + row[i], pt.y + col[j]);
if (isPositionValid(pt.x + row[i], pt.y + col[j]) && !visited[i][j]) {
visited[i][j] = true;
queue.offer(next);
}
}
}
minimumNumSteps++;
}
return minimumNumSteps;
}
public static void main(String[] args) {
knightShortestPath position = new knightShortestPath();
position.createChessBoard(8);
Point src = new Point(0,7);
Point dest = new Point(7,0);
System.out.println("The minimum number of steps are: " + position.BFS(src, dest)); //answer is 6
}
}
First thing: I have no idea how you can end up with a negative value. You never decrease minimumNumSteps after initializing it with 0. An overflow possibly? Seems weird to me ..
Besides that, I see two issues:
The two for loops are incorrect. You currently iterate over the queue.size(). What you want to do instead is iterating over all children of the current node.
Poll the current point outside of the for loops.
So:
while(!queue.isEmpty()) {
Point pt = queue.poll();
// check if it's target
// ...
for (int i = 0; i < row.length; i++) {
// ...
for (int j = 0; j < col.length; j++) {
// ...
}
}
}
Another note: When the queue is empty and you have not reached the goal, there is no solution. Currently, you are returning some value that may be interpreted falsely.
Since the board is 5x5 there should be 25 moves.
I used a print statement to verify that the recursive method only runs 5 times successfully.
When it gets to the fifth move in the last row it doesn't keep going, even though there are 4 valid moves from that position. It's able to change direction horizontally after hitting the right-most column.
I'm not sure why it can't recover from reaching the bottom row.
public class KnightsTour {
public boolean isSafe(int[][] board, int y, int x) {
if (y >= 0 && x >= 0 && y < board.length && x < board.length) {
return true;
}
return false;
}
public boolean knightsTour(int[][] board, int y, int x, int move) {
if (board[y][x] != 0) {
// already been here
return false;
}
System.out.println("Move " + move + " happened!");
board[y][x] = move;
move++;
if (move == (board.length * board.length)) {
// board is full, you completed the tour, end game
return true;
}
int[][] moves =
{
{1, 2},
{1, -2},
{-1, 2},
{-1, -2},
{2, 1},
{2, -1},
{-2, -1},
{-2, 1}
};
for (int i = 0; i < moves.length; i++) {
if (isSafe(board, y + moves[i][0], x + moves[i][1])) {
return knightsTour(board, y + moves[i][0], x + moves[i][1], move);
}
}
// if the board isn't full and there are no valid moves you can make
// from here then this is not a part of the valid solution
board[y][x] = 0;
return false;
}
public static void main(String[] args) {
KnightsTour tour = new KnightsTour();
int[][] board = new int[5][5];
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
board[i][j] = 0;
}
}
tour.knightsTour(board, 0, 0, 1);
// print board
System.out.println("Board:");
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
System.out.print(board[i][j] + "\t");
}
System.out.println("");
}
}
}
I believe your problem lies in this section of code:
for (int i = 0; i < moves.length; i++) {
if (isSafe(board, y + moves[i][0], x + moves[i][1])) {
return knightsTour(board, y + moves[i][0], x + moves[i][1], move);
}
}
For the first 'isSafe' move, you send the knight there, and if it has already been, you will fully return out false from the Tour. You should either modify this section to continue checking the moves if the tour fails, or modify your 'isSafe' method to say that board positions of non-zero are not actually safe.
I have a defined matrix in Java
int[][] a={
{0,0,0,0,0,0},
{0,0,0,1,0,0},
{0,1,1,0,1,0},
{1,0,0,0,0,1},
{0,1,0,1,0,1},
{0,0,1,0,1,0}
};
So I want to know what positions on matrix are surrounded by the lines made of "1" values, i.e., the group of positions with value of "0", as if the "1" were the perimeter of a irregular figure, and "0" values within the perimeter its area (in this case: a[2][3], a[3][1], a[3][2], a[3][3], a[3][4], a[4][2] and a[4][4]).
How can I get these positions automatically?
One way to do what you want is to use flood fill, with no filling across diagonals. This will not help you by itself, but you can fill all regions that are connected to the edges of your array with some non-zero value. The remaining zeros in the array will be the elements that you crave.
Here is a simple implementation of flood fill:
import java.util.ArrayDeque;
import java.awt.Point; // This is probably superfluous, an int[] with two elements would do fine here too
public class Test
{
private static int[][] a = new int[][] {
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0},
{0, 1, 1 ,0, 1, 0},
{1, 0, 0, 0, 0, 1},
{0, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 1, 0}
};
/*
* Applies flood fills all elements accessible from array[row][col] with
* value. If the element at (row, col) is already value, this method does
* nothing.
*/
private static void floodFill(int[][] array, int row, int col, int value)
{
int oldValue = array[row][col];
if(oldValue == value)
return;
ArrayDeque<Point> queue = new ArrayDeque<>();
queue.add(new Point(col, row));
while(queue.size() > 0) {
// Technically, removeLast would be more efficient, especially
// since the order does not matter, but this is just an example
Point point = queue.pop();
int r = point.y;
int c = point.x;
array[r][c] = value;
if(r > 0 && array[r - 1].length > c && array[r - 1][c] == oldValue)
queue.add(new Point(c, r - 1));
if(r < array.length - 1 && array[r + 1].length > c && array[r + 1][c] == oldValue)
queue.add(new Point(c, r + 1));
if(c > 0 && array[r][c - 1] == oldValue)
queue.add(new Point(c - 1, r));
if(c < array[r].length - 1 && array[r][c + 1] == oldValue)
queue.add(new Point(c + 1, r));
}
}
/*
* Walks around the edges of the array and floods everthing connected to
* them with ones. This relies on floodFill exiting early for areas that
* were already filled.
*/
private static void fillEdges(int[][] array)
{
// top row
for(int col = 0; col < array[0].length; col++)
floodFill(array, 0, col, 1);
// left column
for(int row = 0; row < array.length; row++)
floodFill(array, row, 0, 1);
// bottom row
for(int col = 0; col < array[array.length - 1].length; col++)
floodFill(array, array.length - 1, col, 1);
// all trailing row segments (allows for ragged arrays)
for(int row = 1; row < array.length - 1; row++) {
int lengthToFill = array[row].length - Math.min(array[row - 1].length, array[row + 1].length);
lengthToFill = (lengthToFill < 0) ? 1 : lengthToFill + 1;
for(int col = array[row].length - lengthToFill; col < array[row].length; col++)
floodFill(array, row, col, 1);
}
}
public static void main(String[] args)
{
fillEdges(a);
for(int row = 0; row < a.length; row++) {
for(int col = 0; col < a[row].length; col++) {
if(a[row][col] == 0)
System.out.println("[" + row + "][" + col + "]");
}
}
}
}
This particular implementation is nice because it will work for arrays of arbitrary size and shape. I added a bit to check if a point is on the edge of a ragged array as well (comparing the lengths of the rows).
The output is exactly what you expect:
[2][3]
[3][1]
[3][2]
[3][3]
[3][4]
[4][2]
[4][4]
Here is a simple algorithm that uses helper functions to compute the indexes of the predecessor and successor of each element.
public class Test {
public static final int N = 6;
public static int isucc(int i, int j) {
return (i * N + j + 1) / N;
}
public static int jsucc(int i, int j) {
return (i * N + j + 1) % N;
}
public static int ipred(int i, int j) {
return (i * N + j - 1) / N;
}
public static int jpred(int i, int j) {
return (i * N + j - 1) % N;
}
public static void main(String[] args) {
int[][] a={
{0,0,0,0,0,0},
{0,0,0,1,0,0},
{0,1,1,0,1,0},
{1,0,0,0,0,1},
{0,1,0,1,0,1},
{0,0,1,0,1,0}
};
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (i * N + j > 0 && i * N + j < N * N - 1
&& a[ipred(i,j)][jpred(i,j)] == 1
&& a[isucc(i,j)][jsucc(i,j)] == 1) {
System.out.println(i + "," + j);
}
}
}
}
}
It prints:
2,3
2,5
4,0
4,2
4,4
5,3
Note that it can easily be extended to non-square matrices.
Dominique Ubersfeld