The problem is to find the shortest path on a grid from a start point to a finish point. the grid is a 2 dimensional array filled with 0's and 1's. 1's are the path. I have a method that checks the neighbors of a given coordinate to see if its a path. The problem im having is with the boundaries of the grid. The right and bottom boundary can just be checked using the arrays length and the length of a column. But how would i check to make sure that i dont try to check a point thats to the left of the grid or above the grid?
This is my method
public static void neighbors(coordinate current, int[][] grid, Queue q)
{
int row = current.getRow();
int col = current.getCol();
if(grid[row-1][col] == 1)
{
if(grid[row][col] == -1)
{
grid[row-1][col] = grid[row][col] + 2;
}
else
{
grid[row-1][col] = grid[row][col] + 1;
}
coordinate x = new coordinate(row-1,col);
q.enqueue(x);
}
else if(grid[row+1][col] == 1)
{
if(grid[row][col] == -1)
{
grid[row+1][col] = grid[row][col] + 2;
}
else
{
grid[row+1][col] = grid[row][col] + 1;
}
coordinate x = new coordinate(row+1,col);
q.enqueue(x);
}
else if(grid[row][col-1] == 1)
{
if(grid[row][col] == -1)
{
grid[row][col-1] = grid[row][col] + 2;
}
else
{
grid[row][col-1] = grid[row][col] + 1;
}
coordinate x = new coordinate(row, col - 1);
q.enqueue(x);
}
else if(grid[row][col+1] == 1)
{
if(grid[row][col+1] == -1)
{
grid[row][col+1] = grid[row][col] + 1;
}
else
{
grid[row][col+1] = grid[row][col] + 1;
}
coordinate x = new coordinate(row, col + 1);
q.enqueue(x);
}
else
{
}
q.dequeue();
}
I assume that the leftmost and topmost indexes are 0 in your arrays, so just make sure that index-1 >= 0 before indexing into the appropriate array.
Related
Update
I was able to get my algorithm working by increasing the thread size to a few gigabytes and was able to solve a 1803x1803 maze in a second or two.
---------------
I started teaching myself recursion yesterday in Java. I created an algorithm that takes a photo of a maze and solves it. However, I get a stack overflow answer when doing mazes that are larger than about 200x200 px because I think the stacks of this algorithm get too long. How can I better this algorithm so that I can input images up to possibly 1000x1000?
Additionally, can you tell me what kind of algorithm I am currently using? I believe this is either DFS, but I am unsure.
Please explain why your solution is more efficient and the idea that it uses.
This is the main class for solving
public class BlackWhiteSolver {
static int[][] solutionSet = new int[203][203];
static int width, height;
static String originalImage;
static int correctX, correctY;
public static void convert() {
try {
BufferedImage original = ImageIO.read(new File(originalImage));
int red;
int threshold = 2;
width = original.getWidth();
height = original.getHeight();
for(int i=0; i<original.getWidth(); i++) {
for(int j=0; j<original.getHeight(); j++) {
red = new Color(original.getRGB(i, j)).getRed();
// 1 = white, 0 = black, 9 = tried, 5 = solved
if(red > threshold) { solutionSet[i][j] = 1; }
else { solutionSet[i][j] = 0; }
}
}
} catch (IOException e) {e.printStackTrace();}
}
public BlackWhiteSolver(int solvedX, int solvedY, String pic) {
correctX = solvedX;
correctY = solvedY;
originalImage = pic;
}
public boolean solve (int row, int column) {
boolean completed = false;
if (validPoint(row, column)) {
solutionSet[row][column] = 9;
if (row == correctX && column == correctY) {
completed = true;
} else {
completed = solve (row+1, column);
if (!completed) {
completed = solve (row, column+1);
}
if (!completed) {
completed = solve (row-1, column);
}
if (!completed) {
completed = solve (row, column-1);
}
}
if (completed) {
solutionSet[row][column] = 5;
}
}
return completed;
}
private boolean validPoint (int row, int column) {
boolean isValid = false;
if (row < height-1 && column < width-1 && row >= 1 && column >= 1 ) {
if (solutionSet[row][column] == 1) {
isValid = true;
}
}
return isValid;
}
public static void solvedFile() {
BufferedImage binarized = new BufferedImage(width, height,BufferedImage.TYPE_3BYTE_BGR);
int newPixel = 0;
int rgb = new Color(255, 0, 0).getRGB();
for(int i=0; i<width; i++){
for(int j=0; j<height; j++)
{
if (solutionSet[i][j] == 0) {
newPixel = 0;
newPixel = colorToRGB(1, newPixel, newPixel, newPixel);
} else if (solutionSet[i][j] == 1 || solutionSet[i][j] == 9) {
newPixel = 255;
newPixel = colorToRGB(1, newPixel, newPixel, newPixel);
} else if (solutionSet[i][j] == 5) {
newPixel = 16711680;
}
binarized.setRGB(i, j, newPixel);
}
}
try { ImageIO.write(binarized, "gif",new File("maze-complete") );} catch (IOException e) {e.printStackTrace();}
}
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
}
This is the class that runs the maze
public class BlackWhiteInterface
{
public static void main (String[] args) {
BlackWhiteSolver puzzle = new BlackWhiteSolver(60, 202, "maze-4.gif");
System.out.println();
puzzle.convert();
if (puzzle.solve(0,34)) {
System.out.println("completed");
puzzle.solvedFile();
} else {
System.out.println("not possible");
}
}
}
Generates correct maze with start and end point
public class MazeBuilder {
static String start = "left";
static String end = "down";
public static void main(String[] args)
{
try
{
BufferedImage original = ImageIO.read(new File("mazeInput1.gif"));
BufferedImage binarized = new BufferedImage(original.getWidth(), original.getHeight(),BufferedImage.TYPE_BYTE_BINARY);
int red;
int redRightPixel;
int redUpPixel;
int newPixel;
int threshold = 2;
for(int i=0; i<original.getWidth(); i++)
{
for(int j=0; j<original.getHeight(); j++)
{
red = new Color(original.getRGB(i, j)).getRed();
int alpha = new Color(original.getRGB(i, j)).getAlpha();
if(red > threshold) { newPixel = 255; }
else { newPixel = 0; }
if (i == 0 || j == 0 || i == original.getWidth()-1 || j == original.getHeight() - 1){
newPixel = 0;
if (end == "left") {
} else if (end == "right") {
} else if (end == "up") {
} else if (end == "down") {
}
/*if (i == 1 || j == 1 || i == original.getWidth()-2 || j == original.getHeight() - 2 && red > 2) {
System.out.println("Start Point: (" + i + ", " + j + ")");
}
if (i == 0 && j > 0 && j < original.getHeight()-1) {
redRightPixel = new Color(original.getRGB(i+1, j)).getRed();
if (i == 0 && redRightPixel > 2) {
System.out.println("Start Point: (" + i + ", " + j + ")");
newPixel = 255;
}
}*/
/*if (j == original.getHeight()-1 && i > 0 && i < original.getWidth()-1) {
redUpPixel = new Color(original.getRGB(i, j-1)).getRed();
if (redUpPixel > 2) {
System.out.println("End Point: (" + i + ", " + j + ")");
newPixel = 255;
}
}*/
}
if (start == "left") {
if (i == 1 && j != 0 && j != original.getHeight()-1 && red > 2) {
System.out.println("Start Point: (" + i + ", " + j + ")");
}
} else if (start == "right") {
if (i == original.getHeight()-2 && j != 0 && j != original.getHeight()-1 && red > threshold) {
System.out.println("Start Point: (" + i + ", " + j + ")");
}
} else if (start == "up") {
if (j == 1 && i != 0 && i != original.getWidth()-1 && red > threshold) {
System.out.println("Start Point: (" + i + ", " + j + ")");
}
} else if (start == "down") {
if (j == original.getHeight()-2 && i != 0 && i != original.getWidth()-1 && red > threshold) {
System.out.println("Start Point: (" + i + ", " + j + ")");
}
}
if (end == "left") {
if (i == 1 && j != 0 && j != original.getHeight()-1 && red > 2) {
System.out.println("End Point: (" + i + ", " + j + ")");
}
} else if (end == "right") {
if (i == original.getHeight()-2 && j != 0 && j != original.getHeight()-1 && red > threshold) {
System.out.println("End Point: (" + i + ", " + j + ")");
}
} else if (end == "up") {
if (j == 1 && i != 0 && i != original.getWidth()-1 && red > threshold) {
System.out.println("End Point: (" + i + ", " + j + ")");
}
} else if (end == "down") {
if (j == original.getHeight()-2 && i != 0 && i != original.getWidth()-1 && red > threshold) {
System.out.println("End Point: (" + i + ", " + j + ")");
}
}
newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
binarized.setRGB(i, j, newPixel);
}
}
ImageIO.write(binarized, "gif",new File("maze-4") );
}
catch (IOException e)
{
e.printStackTrace();
}
}
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
}
Example output of a 203 x 203 maze
One simple way that's only slightly more efficient is to not store the path you've followed so far in the stack with recursion. Instead store the path you've followed so far in either a java.util.BitSet (where you store each path pixel in element y*width + x of the BitSet) or you can simply use the red area of the picture that you've colored in to store the path.
This avoids stack overflows.
The basic algorithm is to start at the start point and go in one of the four cardinal directions unless you've already visited that direction (either trying it and finding it a dead end or having come from that direction to get here). When you go in a direction, you do the same thing there. It's a simple nonrecursive loop.
When you hit a dead end, you figure out how you got there originally by checking all four directions from where you are to see where the path came from. You remove the red from the spot where you're standing and go back in the direction you came from. If there is no red path in any direction, you're at the starting point again and you've tried everything, so there's no solution to the maze.
When you backtrack, you try the next direction you haven't tried yet at the older square on the path until all directions are dead ends.
If you ever reach the end point, you're done.
Here's some pseudocode that can't generally handle cycles (paths that go in a "circle"), that's grossly inefficient (for example, it should use a BitSet instead of a boolean[][]), and that probably has some bugs, but it gives the general idea:
public class MazeSolver {
private static enum Direction { UP, RIGHT, DOWN, LEFT }
// Return array's element is true if that's part of the path
public static boolean[][] solve(final boolean[][] mazeWallHere,
int x, int y,
final int endX, final int endY) {
final int width = mazeWallHere.length;
final int height = mazeWallHere[0].length;
final boolean[][] path = new boolean[width][height];
Direction nextDirection = Direction.UP;
boolean backtrack = false;
while (true) {
// If this spot is a dead end in all new directions, head back
if (backtrack) {
backtrack = false;
// Unmark where we are
path[x][y] = false;
// Find where we came from and what direction we took to get here
// Then switch to the next direction
// If all directions have been tried, backtrack again
// If we can't backtrack, return null because there's no solution
// If we went up to get here, go back down and try going right.
if (y != 0 && path[x][y - 1]) {
y--;
nextDirection = Direction.RIGHT;
continue;
}
// If we went right to get here, go back left and try going down.
else if (x != 0 && path[x - 1][y]) {
x--;
nextDirection = Direction.DOWN;
continue;
}
// If we went down to get here, go back up and try going left.
else if (y < height && path[x][y + 1]) {
y++;
nextDirection = Direction.LEFT;
continue;
}
// If we went left to get here, go back right and backtrack again.
else if (x < width && path[x + 1][y]) {
x++;
backtrack = true;
continue;
}
// If we didn't come from anywhere, we're at the starting point
// All possible paths are dead ends
else return null;
}
// Mark where we are
path[x][y] = true;
// If we've solved it, return the solution
if (x == endX && y == endY) return path;
// Move unless we:
// * hit the edge of the maze
// * it's the direction we originally got here from
// * hit a wall
// If we can't go a certain direction, try the next direction
// If we're out of directions to try, backtrack
switch (nextDirection) {
case UP: if (y == height
|| path[x][y + 1]
|| mazeWallHere[x][y + 1]) {
nextDirection = Direction.RIGHT;
continue;
}
else y++;
break;
case RIGHT: if (x == width
|| path[x + 1][y]
|| mazeWallHere[x + 1][y]) {
nextDirection = Direction.DOWN;
continue;
}
else x++;
break;
case DOWN: if (y == 0
|| path[x][y - 1]
|| mazeWallHere[x][y - 1]) {
nextDirection = Direction.LEFT;
continue;
}
else y--;
break;
case LEFT: if (x == 0
|| path[x - 1][y]
|| mazeWallHere[x - 1][y]) {
backtrack = true;
continue;
}
else x--;
break;
}
}
}
}
If you want to handle cycles properly, make path an int[][] and store the move number instead of true so that you know which path is older.
In our assignment we are only allowed to use one method. I didn't know about that and I wrote two. So I wanted to ask, if its somehow possible to integrate the function of my neighbourconditions method into the life method. I tried, but I don't know how to initialize my int neighbors. Look at the following code:
public static String[] life(String[] dish) {
String[] newGen = new String[dish.length];
//TODO: implement this function
for (int line = 0; line < dish.length; line++) { // for loop going through each line
newGen[line] = "";
for (int i = 0; i < dish[line].length(); i++) { // loops through every character in the line
String top = ""; // neighbours on the top
String middle = ""; // neighbors on the same line
String down = ""; // neighbors down
if (i == 0){
if(line == 0){
top = null;
} else {
top = dish[line-1].substring(i, i+2);
}
middle = dish[line].substring(i + 1, i +2);
if(line == dish.length -1){
down = null;
} else {
down = dish[line + 1].substring(i, i + 2);
}
} else if (i == dish[line].length() - 1){
if(line == 0){
top = null;
} else {
top = dish[line - 1].substring(i - 1, i + 1);
}
middle = dish[line].substring(i - 1, i);
if(line == dish.length - 1){
down = null;
} else {
down = dish [line + 1].substring(i - 1, i + 1);
}
} else {
if (line == 0){
top = null;
} else {
top = dish[line - 1].substring(i - 1, i + 2);
}
middle = dish[line].substring(i - 1, i) + dish[line].substring(i+1, i+2);
if (line == dish.length - 1){
down = null;
} else {
down = dish[line + 1].substring(i - 1, i + 2);
}
}
int neighbors = neighbourconditions(top, middle, down);
if (neighbors < 2 || neighbors > 3){ // neighbours < 2 or >3 neighbors -> they die
newGen[line] += "o";
} else if (neighbors == 3){
newGen[line] += "x"; // neighbours exactly 3 -> they spawn/live
} else {
newGen[line] += dish[line].charAt(i); // 2 neighbours -> stay
}
}
}
return newGen;
}
// helpmethod with three arguments and the conditions
public static int neighbourconditions(String top, String middle, String down) {
int counter = 0;
if (top != null) { // if no one's on top
for (int x = 0; x < top.length(); ++x) {
if (top.charAt(x) == 'x') {
counter++; // count if an organism's here
}
}
}
for (int x = 0; x < middle.length(); ++x) {
if (middle.charAt(x) == 'x') { // two organisms, one on each side
counter++; // count if an organism's here
}
}
if (down != null) { // if no one's down
for (int x = 0; x < down.length(); ++x) {
if (down.charAt(x) == 'x') { // each neighbour down
counter++; // count if an organism's here
}
}
}
return counter;
}
Everything you do inside the second function will have to be done in the first function. So just copy the code from function 2 into function 1:
public static String[] life(String[] dish){
String[] newGen= new String[dish.length];
//TODO: implement this functions
for(int row = 0; row < dish.length; row++){ // each row
newGen[row]= "";
for(int i = 0; i < dish[row].length(); i++){ // each char in the row
String above = ""; // neighbors above
String same = ""; // neighbors in the same row
String below = ""; // neighbors below
if(i == 0){ // all the way on the left
// no one above if on the top row
// otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i, i + 2);
same = dish[row].substring(i + 1, i + 2);
// no one below if on the bottom row
// otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i, i + 2);
}else if(i == dish[row].length() - 1){//right
// no one above if on the top row
// otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i - 1, i + 1);
same = dish[row].substring(i - 1, i);
// no one below if on the bottom row
// otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i - 1, i + 1);
}else{ // anywhere else
// no one above if on the top row
//otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i - 1, i + 2);
same = dish[row].substring(i - 1, i) + dish[row].substring(i + 1, i + 2);
//no one below if on the bottom row
//otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i - 1, i + 2);
}
// here is the interesting part for you:
int neighbors = 0;
if(above != null){//no one above
for(char x: above.toCharArray()){ //each neighbor from above
if(x == 'x') neighbors++; //count it if someone is here
}
}
for(char x: same.toCharArray()){ //two on either side
if(x == 'x') neighbors++;//count it if someone is here
}
if(below != null){ //no one below
for(char x: below.toCharArray()){//each neighbor below
if(x == 'x') neighbors++;//count it if someone is here
}
};
//here ends the interesting part for you
if(neighbors < 2 || neighbors > 3){
newGen[row]+= "o"; // If the amount of neighbors is < 2 or >3 neighbors -> they die
}else if(neighbors == 3){
newGen[row]+= "x"; // If the amount of neighbors is exactly 3 neighbors -> they spawn/live
}else{
newGen[row]+= dish[row].charAt(i); // 2 neighbors -> stay
}
}
}
return newGen;
}
The trivial answer to this question is to copy and paste the code from the method into the body of the other method. If you're using an IDE, you can use the in-built refactoring tools to inline the method (e.g. ctrl-alt-n, in intellij).
But this is the sort of behavior that makes future generations curse your name. It makes for nasty, unreadable, unmaintainable code. Don't do it. As GhostCat pointed out in comments, you should be looking to make methods smaller, not bigger.
Take a step back, and consider whether you're approaching the problem in the right way. Look for repeating patterns in the existing code, to see if you can simplify it. Or, sometimes, consider that you've just taken the wrong approach in the first place, and so you need to find an alternative approach.
As far as I can work out, all you're trying to do is to count the number of xs in the 8 cells immediately surrounding the current position.
You don't need all of this code to do that. You could simply do:
for(int row = 0; row < dish.length; row++){ // each row
for(int col = 0; col < dish[row].length(); col++){ // each char in the row
int neighbors = 0;
for (int r = Math.max(row - 1, 0); r < Math.min(row + 2, dish.length); ++r) {
for (int c = Math.max(col - 1, 0); c < Math.min(col + 2, dish[row].length()); ++c) {
// Don't count (row, col).
if (r == row && c == col) continue;
if (dish[r].charAt(c) == 'x') ++neighbors;
}
}
//here ends the interesting part for you
if(neighbors < 2 || neighbors > 3){
// etc.
Way less code, no need for an auxiliary method. Also a lot more efficient, because it avoids unnecessarily creating strings.
I'm trying to create a dungeon generator. First, I place the rooms randomly, then I grow a maze in the empty space between them. But I got a problem, everytime I run my maze algorithm, it creates sometimes strange unreachable corridors:
Take a look at the red squares there. These corridors are unreachable for the player. How to avoid them? Here's some code:
public void createMaze(byte[][] dungeon) {
for (int y = 1; y < dungeon.length; y += 2) {
for (int x = 1; x < dungeon[0].length; x += 2) {
Vector2 pos = new Vector2(x, y);
if (dungeon[y][x] != 2 && dungeon[y][x] != 1){
growMaze(pos, dungeon);
}
}
}
}
public void growMaze(Vector2 pos, byte[][] dungeon) {
// Initialize some Lists and Vars
int lastDir = 0;
ArrayList<Vector2> cells = new ArrayList<Vector2>();
// Adding the startPosition to the cell list.
cells.add(pos);
// When the position is in the Grid
if(pos.y < dungeon.length - 2 && pos.y > 0 + 2 && pos.x < dungeon[0].length - 2 && pos.x > 0 + 2){
// And no walls or floors are around it
if(isPlaceAble(dungeon , pos)){
// Then place a corridor tile
dungeon[(int) pos.y][(int) pos.x] = 4;
}
}
// Here comes the algorithm.
while(!cells.isEmpty()){
// choose the latest cell
Vector2 choosedCell = cells.get(cells.size() - 1);
// Check again if the cell is in the grid.
if(choosedCell.y < dungeon.length - 2 && choosedCell.y > 0 + 2 && choosedCell.x < dungeon[0].length - 2 && choosedCell.x > 0 + 2){
// When that's true, then check in which directions the cell is able to move
boolean canGoNorth = dungeon[(int) (choosedCell.y + 1)][(int) choosedCell.x] == 0 && dungeon[(int) (choosedCell.y + 2)][(int) choosedCell.x] == 0;
boolean canGoSouth = dungeon[(int) (choosedCell.y - 1)][(int) choosedCell.x] == 0 && dungeon[(int) (choosedCell.y - 2)][(int) choosedCell.x] == 0;
boolean canGoEast = dungeon[(int) (choosedCell.y)][(int) choosedCell.x + 1] == 0 && dungeon[(int) (choosedCell.y)][(int) choosedCell.x + 2] == 0;
boolean canGoWest = dungeon[(int) (choosedCell.y)][(int) choosedCell.x - 1] == 0 && dungeon[(int) (choosedCell.y)][(int) choosedCell.x - 2] == 0;
// When there's no available direction, then remove the cell and break the loop...
if(!canGoNorth && !canGoSouth && !canGoEast && !canGoWest ){
cells.remove(cells.size() - 1);
break;
}
else{
// But if there's a available direction, then remove the cell from the list.
Vector2 savedCell = cells.get(cells.size() - 1);
cells.remove(cells.get(cells.size() - 1));
boolean placed = false;
// And place a new one into a new direction. This will happen as long as one is placed.
while(!placed){
// pick a random direction
int randomDirection = MathUtils.random(0,3);
int rdm = randomDirection;
// Init the length of the cells.
int length = 2;
// And now begin, if the direction and the random number fits, then dig the corridor. If no direction/number fits, then redo this until it works.
if(canGoNorth && rdm == 0 ){
int ycoord = 0;
for(int y = (int) choosedCell.y; y < choosedCell.y + length; y++){
dungeon[(int) y][(int) choosedCell.x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x, choosedCell.y + length);
cells.add(newCell);
lastDir = 0;
placed = true;
}
if(canGoSouth && rdm == 1 ){
int ycoord = 0;
for(int y = (int) choosedCell.y; y > choosedCell.y - length; y--){
dungeon[(int) y][(int) choosedCell.x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x, choosedCell.y - length);
cells.add(newCell);
lastDir = 1;
placed = true;
}
if(canGoEast && rdm == 2 ){
int xcoord = 0;
for(int x = (int) choosedCell.x; x < choosedCell.x + length; x++){
dungeon[(int) choosedCell.y][x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x + length, choosedCell.y );
cells.add(newCell);
lastDir = 2;
placed = true;
}
if(canGoWest && rdm == 3 ){
int xcoord = 0;
for(int x = (int) choosedCell.x; x > choosedCell.x - length; x--){
dungeon[(int) choosedCell.y][x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x - length, choosedCell.y );
cells.add(newCell);
lastDir = 3;
placed = true;
}
}
}
}
else{
cells.remove(cells.size() - 1);
}
}
// And finally delete dead end cells :) (Those who only got 3 Wall/Floor neighbours or 4)
killDeadEnds(dungeon);
}
So how to avoid these unreachable mazes?
You can use a union-find structure to quickly find and remove all the cells that aren't connected to rooms. See: https://en.wikipedia.org/wiki/Disjoint-set_data_structure
You initially create a disjoint set for each corridor or room cell, and then union every pair of sets for adjacent rooms or cells. Finally, delete all the corridor cells that aren't in the same set as a room.
Union-find is also the basis for a nice maze generation algorithm, which is just Kruskal's algorithm for finding spanning trees in a graph ( https://en.wikipedia.org/wiki/Kruskal%27s_algorithm ) applied to a grid. See: http://weblog.jamisbuck.org/2011/1/3/maze-generation-kruskal-s-algorithm
You could use this algorithm to generate your maze in the first place, before applying your dead end removal. It would change the character of your maze, though, so maybe you don't want to.
I keep receiving an ArrayIndexOutOfBounds on the line directly after the for loop. I would also wondering how I could continue to loop the matrix to iterate the row or column until the target is reached.
In the given matrix, I want to start in the bottom left hand corner. If the target value is less than the selected number then the row moves up. If the target value is greater than the selected number then column moves one to the right.
public static void optimizedSearch(int matrix[][], int array_size, int target) {
int row = 0;
int col = array_size-1;
boolean found = false;
int comparison_counter = 0;
int end = array_size * 2;
//while (!found) {
for (int i = 0; i < 100 && !found; i++) {
if (matrix[row][col] < target ) {
row++;
comparison_counter++;
} else if (matrix[row][col] > target) {
col--;
comparison_counter++;
} else if (matrix[row][col] == target) {
found = true;
} else if ((i == end) && (found == false)) {
found=false;
}
}// end for loop
if (found == true) {
System.out.println(target + " found in " + comparison_counter + " number of comparisons using optimized search");
} else
System.out.println(target + " not found in " + comparison_counter + " number of comparisons using optimized search");
} //end optimizedSearch
To clarify I only wanted one or two for loops to help me on my way, preferably in the same style as I had used in the vertical :)
I'm making a game using a 2D array, and I need a check that tests if at the current position (indicated by a green square) the character there is part of a diagonal sequence of "l" more of the character.
public static boolean diagonals(char[][] b, int row, int col, int l) {
int counter = 1; // because we start from the current position
char charAtPosition = b[row][col];
int numRows = b.length;
int numCols = b[0].length;
int topleft = 0;
int topright = 0;
int bottomleft = 0;
int bottomright = 0;
for (int i=row-1,j=col-1;i>=0 && j>=0;i--,j--) {
if (b[i][j]==charAtPosition) {
topleft++;
} else {
break;
}
}
for (int i=row-1,j=col+1;i>=0 && j<=numCols;i--,j++) {
if (b[i][j]==charAtPosition) {
topright++;
} else {
break;
}
}
for (int i=row+1,j=col-1;i<=numRows && j>=0;i++,j--) {
if (b[i][j]==charAtPosition) {
bottomleft++;
} else {
break;
}
}
for (int i=row+1,j=col+1;i<=numRows && j<=numCols;i++,j++) {
if (b[i][j]==charAtPosition) {
bottomright++;
} else {
break;
}
}
return topleft + bottomright + 1 >= l || topright + bottomleft + 1 >= l; //in this case l is 5
}
The idea is that we walk in four directions and count the steps. This may not be the most efficient implementation, but at least it looks neat and easy to understand.
Here's the function, it works. The explanation is in the comments in the code, but if you find anything confusing let me know and I'll explain it.
public static boolean diagonals(char[][] b, int row, int col, int l) {
int forwardCounter = 1; // this counts top right to bottom left
int backCounter = 1; // this counts top left to bottom right
int distance = 1;
// 0 = topleft, 1 = topright, 2 = bottomleft, 3 = bottomright
boolean[] checks = new boolean[]{true, true, true, true};
char charAtPosition = b[row][col];
while(checks[0] || checks[1] || checks[2] || checks[3]) {
for(int i = 0; i < 4; i++) {
if(checks[i]) {
// This looks confusing but it's simply just converting i into
// The four different directions
checks[i] = checkSquare(b, row + (i < 2 ? -distance : distance),
col + (i % 2 == 0 ? -distance : distance), charAtPosition);
if(checks[i]) {
// If top left or bottom right
if(i % 3 == 0) {
backCounter++;
} else {
forwardCounter++;
}
}
}
}
if (forwardCounter >= l || backCounter >= l) return true;
distance++;
}
return false;
}
private static boolean checkSquare(char[][] b, int row, int col, char check) {
if(row < 0 || row >= b.length) return false;
if(col < 0 || col >= b[0].length) return false;
return check == b[row][col];
}