Maze solve and shortest path with Java BFS
Date : November 28 2020, 03:01 PM
|
I think the issue was by ths following , Please review the following code. It lets you printout all paths found, as well as the shortest one found. I did not change nor checked the search algorithm. I think it needs more work because I think it does not find the shortest path possible to each exit. I will look into it later. class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node start;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeWidth, mazeHeight, startH, startW; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeWidth = 21;//use meaningful names
mazeHeight = 21;
startH = 9; startW = 10;
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
List<Node> result = new ArrayList<>();
paths = new ArrayList<>();
findExits(start, nodes, visited, mazeWidth, mazeHeight, result, paths);
if (!result.isEmpty()) {
Collections.sort(result, new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
if (Integer.compare(o1.x, o2.x) == 0) {
return Integer.compare(o1.y, o2.y);
} else {
return Integer.compare(o1.x, o2.x);
}
}
});
}
drawAllPaths(); // see all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("***************************************************");
System.out.println("Maze as defined by input");
System.out.println("***************************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("***************************************************");
System.out.println("Path to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("***************************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
if ((path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeHeight][mazeWidth];
visited = new boolean[mazeHeight][mazeWidth];
for (int height = 0; height < mazeHeight; height++) {
String row = mazeData[height];
for (int width = 0; width < mazeWidth; width++) {
Node node = new Node(height, width);
node.blocked = row.charAt(width) == NUMBER_SIGN;
visited[width][height] = false;
node.exit = (!node.blocked) && ((height == (mazeHeight - 1)) ||
(width == (mazeWidth - 1)) || (height == 0) || (width == 0));
nodes[height][width] = node;
}
}
start = nodes[startH][startW];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node start, Node[][] nodes,
boolean[][] visited, int W, int H, List<Node> result, List<List<Node>> paths) {
int x = start.x;
int y = start.y;
visited[x][y] = true;
if (start.exit) {
result.add(start);
visited[x][y] = false;
List<Node> path = new ArrayList<>();
while (start.parent != null) {
path.add(start);
start = start.parent;
}
path.add(start);
paths.add(path);
}
//TOP
if ((y - 1) >= 0) {
if (!visited[x][y - 1] && (!nodes[x][y - 1].blocked)) {
nodes[x][y - 1].parent = start;
findExits(nodes[x][y - 1], nodes, visited, W, H, result, paths);
}
}
//BOT
if ((y + 1) < H) {
if (!visited[x][y + 1] && (!nodes[x][y + 1].blocked)) {
nodes[x][y + 1].parent = start;
findExits(nodes[x][y + 1], nodes, visited, W, H, result, paths);
}
}
//LEFT
if ((x - 1) >= 0) {
if (!visited[x - 1][y] && (!nodes[x - 1][y].blocked)) {
nodes[x - 1][y].parent = start;
findExits(nodes[x - 1][y], nodes, visited, W, H, result, paths);
}
}
//RIGHT
if ((x + 1) < W) {
if (!visited[x + 1][y] && (!nodes[x + 1][y].blocked)) {
nodes[x + 1][y].parent = start;
findExits(nodes[x + 1][y], nodes, visited, W, H, result, paths);
}
}
}
public static class Node {
public int x, y;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (x != other.x) {
return false;
}
if (y != other.y) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(start)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node startNode;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeRows, mazeCols, startRow, startCol; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeCols = 21; mazeRows = 21;//use meaningful and consistent names
startRow = 9; startCol = 10; //better keep h,w or height,width all over
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
paths = new ArrayList<>();
findExits(startNode);
drawAllPaths(); // print all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("*****************************************");
System.out.println("Maze as defined by input");
System.out.println("*****************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("*****************************************");
System.out.println("Path to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("*****************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
//overwrite c if node is in path
if ( (c != EXIT) && ( c != START ) &&
(path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeRows][mazeCols];
visited = new boolean[mazeRows][mazeCols];
for (int rowIndex = 0; rowIndex < mazeRows; rowIndex++) {
String row = mazeData[rowIndex];
for (int colIndex = 0; colIndex < mazeCols; colIndex++) {
Node node = new Node(rowIndex, colIndex);
node.blocked = row.charAt(colIndex) == NUMBER_SIGN;
visited[rowIndex][colIndex] = false;
node.exit = (!node.blocked) && ((rowIndex == (mazeRows - 1)) ||
(colIndex == (mazeCols - 1)) || (rowIndex == 0) || (colIndex == 0));
nodes[rowIndex][colIndex] = node;
}
}
startNode = nodes[startRow][startCol];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node node) {
int row = node.row;
int col = node.col;
if(visited[row][col]) { return; }
if (node.exit) {
List<Node> path = new ArrayList<>();
while (node.parent != null) {
path.add(node);
node = node.parent;
}
path.add(node);
paths.add(path);
return; //do not continue to check exit neighbors
}
//LEFT
if ((col - 1) >= 0) {
Node testNode = nodes[row][col - 1];
//the following if statement repeats for all directions
//better put in a method
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node; //parent ! null indicates that cell is tested
findExits(testNode);
testNode.parent = null; //set back to null: test finished
}
}
//RIGHT
if ((col + 1) < mazeCols) {
Node testNode = nodes[row][col + 1];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//TOP
if ((row - 1) >= 0) {
Node testNode = nodes[row-1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//BOTTOM
if ((row + 1) < mazeRows) {
Node testNode = nodes[row+1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
visited[row][col] = true; //mark as visited after all directions explored
node.parent = null;
}
public static class Node {
public int row, col;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (row != other.row) {
return false;
}
if (col != other.col) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(startNode)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
@Override
public String toString() {
return "Node " + row +"-"+ col +" ("+ getGraphics() + ")";
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
Boards Message : |
You Must Login
Or Sign Up
to Add Your Comments . |
Share :
|
How do I start making a shortest path maze solver from a maze matrix in Java?
Date : March 29 2020, 07:55 AM
Hope this helps One of the most widely used and effective pathfinding algorithms is the A* Pathfinding Algorithm Whilst this is probably surplus to your needs, it is a often used in games and other forms of computer science, and is scalable to your needs.
|
Java Maze shortest path 2d int array
Date : March 29 2020, 07:55 AM
This might help you I just looked at the wikipedia article on Dijkstra's Algorithm. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all other nodes. Mark all nodes unvisited. Set the initial node as current. Create a set of the unvisited nodes called the unvisited set consisting of all the nodes except the initial node. For the current node, consider all of its unvisited neighbors and calculate their tentative distances. For example, if the current node A is marked with a distance of 6, and the edge connecting it with a neighbor B has length 2, then the distance to B (through A) will be 6+2=8. If this distance is less than the previously recorded distance, then overwrite that distance. Even though a neighbor has been examined, it is not marked as visited at this time, and it remains in the unvisited set. When we are done considering all of the neighbors of the current node, mark the current node as visited and remove it from the unvisited set. A visited node will never be checked again; its distance recorded now is final and minimal. If the unvisited set is empty, then stop. The algorithm has finished. Set the unvisited node marked with the smallest tentative distance as the next "current node" and go back to step 3.
|
Kth shortest path in a given MAZE c++
Date : March 29 2020, 07:55 AM
like below fixes the issue I have a dynamic programming solution for this. Use a 3D matrix cost[M][N][K] where cost[x][y][i] will represent the ith shortest path to reach cell (x, y) from the top right hand corner. for (int x = 0; x < m; x++) {
for (int y = 0; y < n; y++) {
//Process
}
}
|
Java Maze Shortest Path misunderstanding
Date : March 29 2020, 07:55 AM
I think the issue was by ths following , Here is code, using recursion, I am trying to solve maze with shortest pathing, but it is getting solved with a longer way and I don't really understand why. Here is code of recursion : , Try this, it should work and go straight to finish: public boolean findPath(int row, int col) {
board[row][col].visit();
if ((col == 7) && (row == 7)) {
board[row][col].selectCell();
return true;
}
if ((row < 7) && !board[row + 1][col].marked() &&
!board[row + 1][col].blocked() && !board[row + 1][col].visited()) {
block(row, col);
if (findPath(row + 1, col)) {
board[row][col].selectCell();
return true;
}
unblock(row, col);
}
if ((col > 0) && !board[row][col - 1].marked() &&
!board[row][col - 1].blocked() && !board[row][col - 1].visited()) {
block(row,col);
if (findPath(row, col - 1)) {
board[row][col].selectCell();
return true;
}
unblock(row,col);
}
if ((col < 7) && !board[row][col + 1].marked() &&
!board[row][col + 1].blocked() && !board[row][col + 1].visited()) {
block(row,col);
if (findPath(row, col + 1)) {
board[row][col].selectCell();
return true;
}
unblock(row,col);
}
if ((row > 0) && !board[row - 1][col].marked() &&
!board[row - 1][col].blocked() && !board[row - 1][col].visited()) {
block(row, col);
if (findPath(row - 1, col)) {
board[row][col].selectCell();
return true;
}
unblock(row, col);
}
return false;
}
|
shortest path through a maze
Tag : java , By : John Phipps
Date : March 29 2020, 07:55 AM
|
|
|
Related QUESTIONS :
|