Finding path in a boolean matrix - java

The problem I'm trying to solve is a standard interview question. Given a boolean matrix find the path from the starting point to the finishing point.
The start point is assumed the left top corner
The finishing point the right bottom corner.
Only grids with 0 can be moved into.
No diagonal moves are allowed.
Here's my code.
public class PathFinder {
public static ArrayList<Pair> dfs(int[][] arr, int row, int col, Pair sp, Pair fp){
int[][] check = new int[row][col];
ArrayList<Pair> path = new ArrayList<>();
dfs(arr, row, col, path, check, sp, fp);
return path;
}
private static void dfs(int[][] arr, int row, int col, ArrayList<Pair> path, int[][] check, Pair sp, Pair fp){
if(sp.getRow() == fp.getRow() && sp.getCol() == fp.getCol()) return;
if((sp.getRow() +1 < row) &&(arr[sp.getRow() +1][sp.getCol()] == 0) && (check[sp.getRow()+1][sp.getCol()] == 0)){
check[sp.getRow()+1][sp.getCol()] = 1;
path.add(new Pair(sp.getRow()+1, sp.getCol()));
dfs(arr, row, col, path, check, new Pair(sp.getRow()+1, sp.getCol()), fp);
}else if((sp.getRow() -1 >= 0) &&(arr[sp.getRow() -1][sp.getCol()] == 0) && (check[sp.getRow()-1][sp.getCol()] == 0)){
check[sp.getRow()-1][sp.getCol()] = 1;
path.add(new Pair(sp.getRow()-1, sp.getCol()));
dfs(arr, row, col, path, check, new Pair(sp.getRow()-1, sp.getCol()), fp);
}else if((sp.getCol() +1 < col) &&(arr[sp.getRow()][sp.getCol() +1] == 0) && (check[sp.getRow()][sp.getCol()+1] == 0)){
check[sp.getRow()][sp.getCol()+1] = 1;
path.add(new Pair(sp.getRow(), sp.getCol()+1));
dfs(arr, row, col, path, check, new Pair(sp.getRow(), sp.getCol()+1), fp);
}else if((sp.getCol() -1 >= 0) &&(arr[sp.getRow()][sp.getCol() -1] == 0) && (check[sp.getRow()][sp.getCol()-1] == 0)) {
check[sp.getRow()][sp.getCol() - 1] = 1;
path.add(new Pair(sp.getRow(), sp.getCol() - 1));
dfs(arr, row, col, path, check, new Pair(sp.getRow(), sp.getCol() - 1), fp);
}
}
public static void printPath(ArrayList<Pair> list){
for(Iterator itr = list.iterator(); itr.hasNext();){
Pair p = (Pair) itr.next();
System.out.println(p.getRow()+","+p.getCol());
}
}
}
Here's my Pair
public class Pair {
private int row;
private int col;
public Pair(int row, int col){
this.row = row;
this.col = col;
}
public int getRow(){
return row;
}
public int getCol(){
return col;
}
}
And here's my calling code.
public class Main {
public static void printArray(int[][] arr, int row, int col){
for (int i = 0; i < row; i++) {
for (int j = 0; j <col ; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
// write your code here
int row = 5;
int col = 7;
int[][] matrix = new int[row][col];
matrix[0][1] = 1;
matrix[0][3] = 1;
matrix[0][5] = 1;
matrix[1][1] = 1;
matrix[1][3] = 1;
matrix[1][6] = 1;
matrix[2][1] = 1;
matrix[2][2] = 1;
matrix[2][6] = 1;
matrix[3][3] = 1;
matrix[3][5] = 1;
matrix[3][6] = 1;
matrix[4][0] = 1;
printArray(matrix, row, col);
ArrayList<Pair> list = PathFinder.dfs(matrix, row, col, new Pair(0,0), new Pair(row-1, col-1));
PathFinder.printPath(list);
}
}
The issue is that this depth-first-search only works for specific cases. Can someone help me modify the code so that it works for all cases. Please bear in mind I don't want a breath-first search.

Here is a solution with the use of a Stack containing subpaths between junctions and a self implemented linked list of Pairs. The already visited fields are saved in the matrix. At the end the matrix is printed again, where the result-fields (found path) have the value 3 and the other visited fields have the value 2.
public class Pair {
private int row;
private int col;
private Pair next;
public Pair(int row, int col){
this.row = row;
this.col = col;
}
public int getRow(){
return row;
}
public int getCol(){
return col;
}
public Pair getNext() {
return next;
}
public void setNext(Pair next) {
this.next = next;
}
}
///////////////////////
import java.util.*;
public class PathFinder {
private int[][] arr;
private int rowCount;
private int colCount;
private Stack<Pair> junctions = new Stack<>();
public PathFinder(int[][] arr){
this.arr = arr;
this.rowCount = arr.length;
if(rowCount > 0) {
this.colCount = arr[0].length;
}
}
public Pair dfs(Pair sp){
int actualRow = sp.getRow();
int actualCol = sp.getCol();
//we where already here
arr[actualRow][actualCol] = 2;
if(actualRow >= rowCount - 1 && actualCol >= colCount - 1) {
//ready
return sp;
}
boolean deeper = actualRow +1 < rowCount && arr[actualRow +1][actualCol] == 0;
boolean left = actualCol -1 >= 0 && arr[actualRow][actualCol -1] == 0;
boolean right = actualCol +1 < colCount && arr[actualRow][actualCol +1] == 0;
boolean up = actualRow -1 >= 0 && arr[actualRow-1][actualCol] == 0;
//test for junctions
int possibilities = 0;
if(left){
possibilities++;
}
if(right) {
possibilities++;
}
if(deeper){
possibilities++;
}
if(up){
possibilities++;
}
if(possibilities > 1) {
this.junctions.push(sp);
}
Pair nextPair;
if(deeper){
nextPair = new Pair(actualRow + 1, actualCol);
} else if(left) {
nextPair = new Pair(actualRow, actualCol-1);
} else if(right) {
nextPair = new Pair(actualRow, actualCol+1);
} else if(up) {
nextPair = new Pair(actualRow-1, actualCol);
} else {
if(!this.junctions.empty()) {
Pair lastJunction = this.junctions.pop();
lastJunction.setNext(null);
return dfs(lastJunction);
}
return sp;
}
sp.setNext(nextPair);
return dfs(nextPair);
}
}
/////////////////////
public class Main {
public static void printArray(int[][] arr, int row, int col){
for (int i = 0; i < row; i++) {
for (int j = 0; j <col ; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
int rowCount = 6;
int colCount = 8;
int[][] matrix = new int[rowCount][colCount];
matrix[0] = new int[]{0, 1, 0, 1, 0, 0, 0, 1};
matrix[1] = new int[]{0, 1, 0, 0, 0, 1, 0, 0};
matrix[2] = new int[]{0, 0, 0, 1, 0, 1, 0, 0};
matrix[3] = new int[]{0, 1, 1, 1, 1, 0, 0, 1};
matrix[4] = new int[]{0, 0, 0, 0, 0, 1, 0, 0};
matrix[5] = new int[]{0, 1, 0, 1, 0, 0, 1, 0};
printArray(matrix, rowCount, colCount);
Pair pair = new Pair(0,0);
PathFinder finder = new PathFinder(matrix);
Pair finish = finder.dfs(pair);
if(finish.getRow() == rowCount-1 && finish.getCol() == colCount -1) {
while( pair != null){
System.out.println(pair.getRow()+","+pair.getCol());
matrix[pair.getRow()][pair.getCol()] = 3;
pair = pair.getNext();
}
} else {
System.out.println("no path found");
}
printArray(matrix, rowCount, colCount);
}
}

Related

DFS function for finding the clusters of same symbol in 2D matrix

I am trying to write a DFS code for finding the clusters of size greater than or equal to 2 inside a 2D matrix of integers. I am trying to write the DFS for that. Here I am unable to get any output inside the win cluster list of Cluster Object. Can anybody suggest what is going wrong. I have written a DFS function that calls for all neighbouring locations(horizontally and vertically).
Also checking for the valid condition for checking whether the indices are inside the row and column constraints. When the DFS is terminating I am checking for the condition if count of cluster is greater than 2 then I'll add it to the win clusters list else simply return.Please suggest why am I not getting any value in the win_clusters list.
import java.util.*;
public class sample {
static int grid[][]= {{1,3,0,4,0},
{3,2,0,0,1},
{0,4,1,0,1},
{4,0,0,0,2},
{2,4,0,2,4}};
static int ROW;
static int COLUMN;
public static int[][] grid_creation(int numRows, int numCols){
ROW= numRows;
COLUMN=numCols;
int [][]grid = new int[numRows][numCols];
Random rand = new Random();
for(int i = 0; i<numRows ; i++){
for(int j = 0; j<numCols; j++){
grid[i][j]= rand.nextInt(5);
}
}
return grid;
}
public static void print_matrix(int[][]matrix){
for(int i = 0; i< matrix.length;i++){
for(int j = 0; j<matrix[0].length; j++){
System.out.print(matrix[i][j]+" ");
}
System.out.println();
}
}
public static boolean isValid(boolean[][] visited, int row, int col){
if(row<0 ||col<0 || row>=ROW || col>=COLUMN || visited[row][col] )
return false;
return true;
}
public static class Cluster{
List<Integer> cluster_symbol_positions = new ArrayList<Integer>();
int symbol = -1;
int count = 0;
int win = 0;
public void create_new_Cluster(){
cluster_symbol_positions = new ArrayList<>();
symbol = -1;
count = 0;
win= 0;
}
public List<Integer> get_cluster_symbol_positions(){
return cluster_symbol_positions;
}
public int getSymbol(){return symbol;}
public void setSymbol(int a){symbol = a;}
public int getCount(){return count;}
public void add_to_cluster(int row1, int col1 ){
int row = row1;
int col = col1;
cluster_symbol_positions.add(getReelPositionNumber(row,col));
count++;
}
public int cluster_win(Cluster cluster){
int win_amount = 0;
//return win amount from the paytable
return win_amount;
}
}
public static void DFS(int[][] grid,List<Cluster> win_clusters) {
int h = grid.length;
if (h == 0)
return;
int l = grid[0].length;
//created visited array
boolean [][] visited = new boolean[h][l];
System.out.println("Depth-First Search: ");
for( int i =0; i< ROW ; i++){
for(int j = 0 ;j<COLUMN; j++){
if(!visited[i][j]) {
DFSUtil(grid, i, j, visited, win_clusters);
}
}
}
}
static Cluster global_cluster= new Cluster();
static int cluster_length =0;
public static void DFSUtil(int[][]grid, int row, int col, boolean[][] visited, List<Cluster>win_clusters){
if (row < 0 || col < 0 || row >= ROW|| col >= COLUMN || visited[row][col] ) {
if(global_cluster.getCount()>=2) win_clusters.add(global_cluster);
return;
}
int symbol = grid[row][col];
visited[row][col] = true;
cluster_length++;
global_cluster.add_to_cluster(row,col);
global_cluster.setSymbol(symbol);
if(isValid(visited, row+1, col) && grid[row+1][col]==symbol){
DFSUtil(grid, row+ 1, col,visited,win_clusters); // go down
}
if(isValid(visited, row-1, col) && grid[row-1][col]==symbol) {
DFSUtil(grid, row - 1, col, visited, win_clusters); //go up
}
if(isValid(visited, row, col+1) && grid[row][col+1]==symbol){
DFSUtil(grid, row, col + 1,visited,win_clusters); //go right
}
if(isValid(visited, row, col-1) && grid[row][col-1]==symbol){
DFSUtil(grid, row, col - 1,visited,win_clusters); // go left
}
}
public static int getReelPositionNumber(int row, int col) {
return (row*COLUMN) + col;
}
public static List<Integer> getReelPositionsIndex(int positionNumber) {
List<Integer> tempData = new ArrayList<Integer>();
int numReels =COLUMN;
int display = ROW;
if(positionNumber >= numReels*display)
throw new RuntimeException( positionNumber+" is out of range "+ numReels*display +"(rows*cols) in the game." );
if(positionNumber < numReels) {
tempData.add(0);
tempData.add(positionNumber);
} else if(positionNumber == (numReels*display)) {
tempData.add(display - 1);
tempData.add(numReels - 1);
} else {
int row = positionNumber / numReels;
int col = positionNumber % numReels;
tempData.add(row);
tempData.add(col);
}
return tempData;
}
public static void main(String args[]){
System.out.println("Modified function for cluster win ");
List<Cluster> win_clusters = new ArrayList<Cluster>();
DFS(grid,win_clusters);
print_matrix(grid);
System.out.println(win_clusters.size());
}
}

How to DFS a 2D array to record paths from leftmost column to rightmost column?

Here I want to use DFS to traverse in a 2D array from leftmost column to rightmost column, each element can go to its upper right element or right element or lower right element. I need to record each possible path. For example, here I have:
1 2 3
4 5 6
7 8 9
Then the possible paths will be 123, 126, 153, 156, 159, 423, 426, 453, 456, 459, 486, 489, 753, 756, 759, 786, 789
Now my idea is straightforward backtrack:
public int findSolution(int[][] array) {
List<List<Integer>> availablePaths = new ArrayList<List<Integer>>();
for (int i = 0; i < array.length; i++) {
List<Integer> tempList = new ArrayList<Integer>();
dfs(array, availablePaths, tempList, 0, i);
}
int res = 0;
int min = Integer.MAX_VALUE;
for (List<Integer> path : availablePaths) {
min = Integer.MAX_VALUE;
for (Integer cur : path) {
if (cur < min) {
min = cur;
}
}
if (min > res) {
res = min;
}
}
return res;
}
public void dfs(int[][] array, List<List<Integer>> availablePaths, List<Integer> tempList, int curCol, int curRow) {
if (tempList.size() == array[0].length) {
availablePaths.add(new ArrayList<Integer>(tempList));
return;
}
tempList.add(array[curRow][curCol]);
int startRow;
int endRow;
// Next Column
if (curRow == 0) {
startRow = 0;
endRow = curRow+1;
} else if (curRow == array.length-1) {
startRow = curRow - 1;
endRow = curRow;
} else {
startRow = curRow - 1;
endRow = curRow + 1;
}
for (int i = startRow; i <= endRow; i++) {
dfs(array, availablePaths, tempList, curCol + 1, i);
tempList.remove(tempList.size()-1);
}
}
However, this can not work because of ArrayIndexOutOfBoundsException, so I guess my code has wrong idea.
Could someone give a solution to solve this problem?
The following DFS implementation solves your problem. I added your example as a test case as well.Basically, we start a new dfs on each cell on the first column. In each dfs call, as long as the current cell is in bound, we add it to the current path in a list. If the current cell is already the last column, add the path stored in the list to the final result.
The dx, dy arrays are a concise way of implementing the 3 possible moves.
import java.util.ArrayList;
import java.util.List;
public class Solution {
private static int[] dx = {-1,0,1}, dy = {1,1,1};
public static List<List<Integer>> dfsForAllPaths(int[][] grid) {
List<List<Integer>> res = new ArrayList<>();
if(grid == null) {
return res;
}
for(int i = 0; i < grid[0].length; i++) {
dfsHelper(grid, i, 0, res, new ArrayList<>());
}
return res;
}
private static void dfsHelper(int[][] grid, int x, int y, List<List<Integer>> res, List<Integer> list) {
if(!isInBound(grid, x, y)) {
return;
}
list.add(grid[x][y]);
if(y == grid[0].length - 1) {
res.add(new ArrayList<>(list));
}
for(int dir = 0; dir < 3; dir++) {
int newX = x + dx[dir], newY = y + dy[dir];
dfsHelper(grid, newX, newY, res, list);
}
list.remove(list.size() - 1);
}
private static boolean isInBound(int[][] grid, int x, int y) {
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length;
}
public static void main(String[] args) {
int[][] grid = {{1,2,3},{4,5,6},{7,8,9}};
List<List<Integer>> res = dfsForAllPaths(grid);
for(int i = 0; i < res.size(); i++) {
System.out.println(res.get(i));
}
}
}

Puzzle Game Android DFS algorithm

I have a android application called Islands and bridges also known as Hashiwokakero
The application uses A 2 Dimensional array that spawns the Islands randomly everytime the user restarts the game It form a Matrix with number from 0 to 4 where 0=null and 1-4 = Island There can be 2 bridges comming out of one Island to connect the other , The map at the moment is not solvable. To solve the game the user needs to connect the islands using bridges so if an island = 4 it needs 4 connection to it if an island = 2 it needs 2 connection and so on..
in my research i found out that the best algorithm to solve the game is to use Depth first search - article
I have looked at different question on here but can't seem to find a solution as my array is of type String rather than integer.
QUESTION how can apply a DFS algorithm to connect the islands?
here is a screenshot of my application.
This the function to create a easy map 4x4 matrix:
private void InitializeEasy() {
Random rand = new Random();
String[][] debug_board_state = new String[4][4];
setCurrentState(new State(WIDTH_EASY));
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
debug_board_state[row][column] = String.valueOf(rand.nextInt(5));
}
}
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
System.out.print(debug_board_state[row][column] + " ");
}
System.out.println();
}
for (int row = 0; row < WIDTH_EASY; ++row) {
for (int column = 0; column < WIDTH_EASY; ++column) {
for (int colNum = column - 1; colNum <= (column + 1); colNum += 1) {
getCurrentState().board_elements[row][column] = new BoardElement();
getCurrentState().board_elements[row][column].max_connecting_bridges = Integer.parseInt(debug_board_state[row][column]);
getCurrentState().board_elements[row][column].row = row;
getCurrentState().board_elements[row][column].col = column;
if (getCurrentState().board_elements[row][column].max_connecting_bridges > 0) {
getCurrentState().board_elements[row][column].is_island = true;
}
}
}
}
}
DFS could be applied to the game state.
Pseudo algorithm:
pick a random (or by some other criterium) island that still needs bridges
build a bridge between this island and one of its neighbors (obviously a neighbor that also needs a bridge)
push the new state of the game (for instance the connectivity matrix of this graph) on a stack
if the game contains inconsistencies, pop 1 item from the stack
go back to step 1, using the top of the stack as the current state
As I mentioned, this is a piece of pseudo-code.
You will need to refine it to handle edge-cases.
You should also think about strategies to prevent the branching factor from becoming too large.
example (not thoroughly tested, not thoroughly debugged):
int[][] STARTING_CLUES = {
{2, 0, 0, 3, 0, 3},
{0, 1, 4, 0, 4, 0},
{0, 0, 0, 0, 0, 0},
{3, 0, 3, 0, 2, 0},
{0, 0, 0, 1, 0, 2},
{2, 0, 4, 0, 2, 0}
};
void search(){
Map<Point, List<Direction>> remainingOptions = new HashMap<>();
Stack<Land> gameTree = new Stack<>();
gameTree.push(new Land(STARTING_CLUES));
while(true){
Land state = gameTree.peek();
int[] p = state.lowestTodo();
if (p == null)
System.out.println("solution found");
// move to next game state
int r = p[0];
int c = p[1];
System.out.println("expanding game state for node at (" + r + ", " + c + ")");
List<Direction> ds = null;
if(remainingOptions.containsKey(new Point(r,c)))
ds = remainingOptions.get(new Point(r,c));
else{
ds = new ArrayList<>();
for(Direction dir : Direction.values()) {
int[] tmp = state.nextIsland(r, c, dir);
if(tmp == null)
continue;
if(state.canBuildBridge(r,c,tmp[0], tmp[1]))
ds.add(dir);
}
remainingOptions.put(new Point(r,c), ds);
}
// if the node can no longer be expanded, and backtracking is not possible we quit
if(ds.isEmpty() && gameTree.isEmpty()){
System.out.println("no valid configuration found");
return;
}
// if the node can no longer be expanded, we need to backtrack
if(ds.isEmpty()){
gameTree.pop();
remainingOptions.remove(new Point(r,c));
System.out.println("going back to previous decision");
continue;
}
Direction dir = ds.remove(0);
System.out.println("connecting " + dir.name());
remainingOptions.put(new Point(r,c), ds);
Land nextState = new Land(state);
int[] tmp = state.nextIsland(r,c,dir);
nextState.connect(r,c, tmp[0], tmp[1]);
gameTree.push(nextState);
}
}
public static void main(String[] args) {
new Main().search();
}
I also wrote a utility class that handles the common operations on the piece of land on which bridges need to be built (like finding the next available island, checking whether a bridge can be built, etc)
public class Land {
private int[][] BRIDGES_TO_BUILD;
private boolean[][] IS_ISLAND;
private Direction[][] BRIDGES_ALREADY_BUILT;
public Land(int[][] bridgesToDo){
BRIDGES_TO_BUILD = copy(bridgesToDo);
int R = bridgesToDo.length;
int C = bridgesToDo[0].length;
BRIDGES_ALREADY_BUILT = new Direction[R][C];
IS_ISLAND = new boolean[R][C];
for(int i=0;i<R;i++) {
for (int j = 0; j < C; j++) {
BRIDGES_ALREADY_BUILT[i][j] = null;
IS_ISLAND[i][j] = bridgesToDo[i][j] > 0;
}
}
}
public Land(Land other){
BRIDGES_TO_BUILD = copy(other.BRIDGES_TO_BUILD);
int R = BRIDGES_TO_BUILD.length;
int C = BRIDGES_TO_BUILD[0].length;
BRIDGES_ALREADY_BUILT = new Direction[R][C];
IS_ISLAND = new boolean[R][C];
for(int i=0;i<R;i++) {
for (int j = 0; j < C; j++) {
BRIDGES_ALREADY_BUILT[i][j] = other.BRIDGES_ALREADY_BUILT[i][j];
IS_ISLAND[i][j] = other.IS_ISLAND[i][j];
}
}
}
public int[] next(int r, int c, Direction dir){
int R = BRIDGES_TO_BUILD.length;
int C = BRIDGES_TO_BUILD[0].length;
// out of bounds
if(r < 0 || r >=R || c < 0 || c >= C)
return null;
// motion vectors
int[][] motionVector = {{-1, 0},{0,1},{1,0},{0,-1}};
int i = Arrays.asList(Direction.values()).indexOf(dir);
// calculate next
int[] out = new int[]{r + motionVector[i][0], c + motionVector[i][1]};
r = out[0];
c = out[1];
// out of bounds
if(r < 0 || r >=R || c < 0 || c >= C)
return null;
// return
return out;
}
public int[] nextIsland(int r, int c, Direction dir){
int[] tmp = next(r,c,dir);
if(tmp == null)
return null;
while(!IS_ISLAND[tmp[0]][tmp[1]]){
tmp = next(tmp[0], tmp[1], dir);
if(tmp == null)
return null;
}
return tmp;
}
public boolean canBuildBridge(int r0, int c0, int r1, int c1){
if(r0 == r1 && c0 > c1){
return canBuildBridge(r0, c1, r1, c0);
}
if(c0 == c1 && r0 > r1){
return canBuildBridge(r1, c0, r0, c1);
}
if(r0 == r1){
int[] tmp = nextIsland(r0, c0, Direction.EAST);
if(tmp[0] != r1 || tmp[1] != c1)
return false;
if(BRIDGES_TO_BUILD[r0][c0] == 0)
return false;
if(BRIDGES_TO_BUILD[r1][c1] == 0)
return false;
for (int i = c0; i <= c1 ; i++) {
if(IS_ISLAND[r0][i])
continue;
if(BRIDGES_ALREADY_BUILT[r0][i] == Direction.NORTH)
return false;
}
}
if(c0 == c1){
int[] tmp = nextIsland(r0, c0, Direction.SOUTH);
if(tmp[0] != r1 || tmp[1] != c1)
return false;
if(BRIDGES_TO_BUILD[r0][c0] == 0 || BRIDGES_TO_BUILD[r1][c1] == 0)
return false;
for (int i = r0; i <= r1 ; i++) {
if(IS_ISLAND[i][c0])
continue;
if(BRIDGES_ALREADY_BUILT[i][c0] == Direction.EAST)
return false;
}
}
// default
return true;
}
public int[] lowestTodo(){
int R = BRIDGES_TO_BUILD.length;
int C = BRIDGES_TO_BUILD[0].length;
int[] out = {0, 0};
for (int i=0;i<R;i++) {
for (int j = 0; j < C; j++) {
if(BRIDGES_TO_BUILD[i][j] == 0)
continue;
if (BRIDGES_TO_BUILD[out[0]][out[1]] == 0)
out = new int[]{i, j};
if (BRIDGES_TO_BUILD[i][j] < BRIDGES_TO_BUILD[out[0]][out[1]])
out = new int[]{i, j};
}
}
if (BRIDGES_TO_BUILD[out[0]][out[1]] == 0) {
return null;
}
return out;
}
private int[][] copy(int[][] other){
int[][] out = new int[other.length][other.length == 0 ? 0 : other[0].length];
for(int r=0;r<other.length;r++)
out[r] = Arrays.copyOf(other[r], other[r].length);
return out;
}
public void connect(int r0, int c0, int r1, int c1){
if(r0 == r1 && c0 > c1){
connect(r0, c1, r1, c0);
return;
}
if(c0 == c1 && r0 > r1){
connect(r1, c0, r0, c1);
return;
}
if(!canBuildBridge(r0, c0, r1, c1))
return;
BRIDGES_TO_BUILD[r0][c0]--;
BRIDGES_TO_BUILD[r1][c1]--;
if(r0 == r1){
for (int i = c0; i <= c1 ; i++) {
if(IS_ISLAND[r0][i])
continue;
BRIDGES_ALREADY_BUILT[r0][i] = Direction.EAST;
}
}
if(c0 == c1){
for (int i = r0; i <= r1 ; i++) {
if(IS_ISLAND[i][c0])
continue;
BRIDGES_ALREADY_BUILT[i][c0] = Direction.NORTH;
}
}
}
}

An alternative way to write this recursive function?

I have a grid of colors (in a 2D ArrayList). I need to be able to count the number of cells that share the same color in a particular color block (they have to be adjacent on 4 edges). I can do this easily recursively, but the problem is that some images Overflow the stack since color blocks can be so big.
Here's the recursive function:
private int getBlockCount(PietCodel codel) {
if (codel.getValue() != PietCodel.DEFAULT && codel.getValue() != PietCodel.CHECKED) {
return codel.getValue();
}
ArrayList<PietCodel> list = blockCountHelper(codel);
list.add(codel);
// Use the array of codels in the block, and
// use the size to for each value in the array.
int result = list.size();
for (PietCodel item : list) item.setValue(result);
System.out.println("Block count: " + result);
return result;
}
private ArrayList<PietCodel> blockCountHelper(PietCodel codel) {
ArrayList<PietCodel> result = new ArrayList<>();
codel.setValue(PietCodel.CHECKED);
int col = codel.getCol();
int row = codel.getRow();
// Right
PietCodel ajac = get(col + 1, row);
if (ajac != null && codel.equals(ajac.getColor()) && ajac.getValue() == PietCodel.DEFAULT) {
ArrayList<PietCodel> nextCodels = blockCountHelper(ajac);
result.add(ajac);
result.addAll(nextCodels);
}
// Down
ajac = get(col, row + 1);
if (ajac != null && codel.equals(ajac.getColor()) && ajac.getValue() == PietCodel.DEFAULT) {
ArrayList<PietCodel> nextCodels = blockCountHelper(ajac);
result.add(ajac);
result.addAll(nextCodels);
}
// Left
ajac = get(col - 1, row);
if (ajac != null && codel.equals(ajac.getColor()) && ajac.getValue() == PietCodel.DEFAULT) {
ArrayList<PietCodel> nextCodels = blockCountHelper(ajac);
result.add(ajac);
result.addAll(nextCodels);
}
// Up
ajac = get(col, row - 1);
if (ajac != null && codel.equals(ajac.getColor()) && ajac.getValue() == PietCodel.DEFAULT) {
ArrayList<PietCodel> nextCodels = blockCountHelper(ajac);
result.add(ajac);
result.addAll(nextCodels);
}
return result;
}
Any thoughts on an alternative with loops or something?
The idea is to make the "stack/queue" explicit in your application code. Note that this doesn't use less memory then the recursive approach, it just
has more memory to play with by utilizing the heap. The following code is an example. Note that you can call queue.addFirst or queue.addLast, this will
not change the end result but will give you different traversals of the board which is something you may or may not care about.
private ArrayList<PietCodel> blockCountHelper(PietCodel codel) {
ArrayList<PietCodel> accumulator = new ArrayList<>();
LinkedList<PietCodel> queue = new LinkedList<>();
queue.add(codel);
while (!queue.isEmpty()) {
PietCodel ajac = queue.remove();
if (ajac != null && codel.equals(ajac.getColor()) .... ) {
accumulator.add(ajac);
}
if ( get(col + 1, row) != null ) {queue.addFirst(get(col + 1, row));}
if ( get(col , row + 1) != null ) {queue.addFirst(get(col, row + 1));}
if ( get(col - 1, row) != null ) {queue.addFirst(get(col - 1, row));}
if ( get(col , row - 1) != null ) {queue.addFirst(get(col, row- 1));}
}
return accumulator;
}
Standard way to get rid of recursion is to use Stack data structure, as recursion is essentially a stack manipulation. But in your concrete situation you can use breadth-first search. You can implement it using queue:
int rows = 10;
int cols = 10;
PietCodel codels[][] = new PietCodel[rows][cols];
boolean used[][] = new boolean[rows][cols];
private void test() {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < rows; ++j) {
int color = (int) (Math.random() * 3);
PietCodel codel = new PietCodel(i, j, color);
codels[i][j] = codel;
System.out.print(color + " ");
}
System.out.println();
}
System.out.println();
System.out.println(getBlockCount(get(0, 0)));
}
private int getBlockCount(PietCodel codel) {
used = new boolean[rows][cols];
Queue<PietCodel> q = new LinkedList<>();
q.add(codel);
used[codel.getRow()][codel.getCol()] = true;
int color = codel.getColor();
int count = 0;
while (!q.isEmpty()) {
PietCodel ajacent = q.poll();
int col = ajacent.getCol();
int row = ajacent.getRow();
++count;
addColored(q, col + 1, row, color);
addColored(q, col - 1, row, color);
addColored(q, col, row + 1, color);
addColored(q, col, row - 1, color);
}
return count;
}
private PietCodel get(int col, int row) {
return col < 0 || col >= cols || row < 0 || row >= rows ? null : codels[row][col];
}
private void addColored(Queue<PietCodel> q, int col, int row, int color) {
if (col < 0 || col >= cols || row < 0 || row >= rows) {
return;
}
PietCodel codel = codels[row][col];
if (codel.getColor() != color || used[row][col]) {
return;
}
used[row][col] = true;
q.add(codel);
}
static class PietCodel {
static final int DEFAULT = 0;
static final int CHECKED = -1;
static final int USED = -2;
final int row;
final int col;
final int color;
int value;
public PietCodel(int row, int col, int color) {
this.col = col;
this.row = row;
this.color = color;
}
public int getCol() {
return col;
}
public int getRow() {
return row;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getColor() {
return color;
}
public boolean same(PietCodel ajac) {
return color == ajac.getColor();
}
}

Searching a Matrix and Returning Coordinates of a Value

I need to search a matrix for a certain value and return its coordinates; I have made the following script/function to do so. However, the function is not working because apparently when my if statement in findIndexWithValue runs it looks for a coordinate that is not in the array (to high). Could anyone help me out or give a more efficient method of doing what I am trying to do?
package main;
public class SolveMaze {
Pos start = new Pos(0,0);
Pos end = new Pos(0,0);
public static int getMazeWidth(int[][] maze){
if (maze == null){
System.out.println("Entered Maze Has Returned Null For Width");
return 0;
} else {
return maze.length;
}
}
public static int getMazeHeight(int[][] maze){
if (maze == null){
System.out.println("Entered Maze Has Returned Null For Height");
return 0;
} else {
return maze[0].length;
}
}
public static Pos findIndexWithValue(int[][] maze, int value){
if (maze == null){
System.out.println("Maze is NULL! (FindIndexWithValue)");
return null;
} else {
for (int i1 = 0; i1 < getMazeWidth(maze) - 1; i1++){ //1
int cordX = 0;
int cordY = 0;
cordY = 0;
for (int i2 = 0; i2 < getMazeHeight(maze) - 1; i2++){ //9
if (maze[cordX][cordY] == value){
Pos returnPos = new Pos(cordX, cordY);
return returnPos;
}
cordY++;
}
cordX++;
}
}
System.out.println("The Value You Are Looking For is not Present (findIndexWithValue)");
return null;
}
}
and the main class is:
package main;
public class MazeSolver {
final static int[][] maze = {
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 1,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0,-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0, 0, 0, 0, 0, 0, 0, 1,-1},
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};
public static void main(String args[]){
Pos test = new Pos(0,0);
test = SolveMaze.findIndexWithValue(maze, 1);
System.out.println(test.getX() + " " + test.getY());
}
}
You are doing weird things in your for-for loop :-)
This should fix it:
public static Pos findIndexWithValue(int[][] maze, int value) {
if (maze == null) {
System.out.println("Maze is NULL! (FindIndexWithValue)");
return null;
} else {
for (int x = 0; x < getMazeWidth(maze); x++) {
for (int y = 0; y < getMazeHeight(maze); y++) {
if (maze[x][y] == value) {
Pos returnPos = new Pos(x, y);
return returnPos;
}
}
}
}
System.out.println("The Value You Are Looking For is not Present (findIndexWithValue)");
return null;
}
Also, just a tip: NEVER name your variables i1 or i2. Whoever reads your code will have a hard time understanding it.

Categories

Resources