The robot can move on the plane in 4 directions: U - up, D - down, L - left, R - right. Traffic example is UUDLR, DLRUD. I have to implement the "walk" method so that it returns the robot position after passing the indicated path. So I do this:
class Main {
static int[] walk(String path) {
int[] A = {0,0};
char charFromPath;
for (int i = 0 ; i < path.length() ; i++) {
charFromPath = path.charAt(i);
if(charFromPath == 'U')
{
A[1]++;
}
if(charFromPath == 'D')
{
A[1]--;
}
if(charFromPath == 'L')
{
A[0]--;
}
if(charFromPath == 'R')
{
A[0]++;
}
}
return A;
}
public static void main(String[] args) {
{
String path="UUDLR";
int[] position = walk(path);
System.out.println("case 1 - path "+path+ " position 0,1");
if(position[0]==0 && position[1]==1)
System.out.println("the robot went right");
else
System.out.println("the robot smashed");
}
{
String path="DLRUD";
int[] position = walk(path);
System.out.println("\ncase 2 - path "+path+ " position 0,-1");
if(position[0]==0 && position[1]==-1)
System.out.println("the robot went right");
else
System.out.println("the robot smashed");
}
}}
Now in version 2 according to logic U, D, L, R, commands are UP DOWN LEFT RIGHT. Traffic example is UPUPLEFTRIGHTUP.
Now in version 3 commands are for instance 3xUP 2xLEFT DOWN RIGHT. 3xUP means move three times up and 2xLEFT 2 times left. Add a restriction in movement for the robot, he cant go outside the 10x10 area (item 10.10 or -10, -10 is the last valid value).
I have no idea how to write it. How to count the number of repetitions string in string?
You can try something like
String str = "UPUPLEFTRIGHTUP";
int countUP = ( str.split("UP", -1).length ) - 1;
int countLEFT = ( str.split("LEFT", -1).length ) - 1;
int countRIGHT = ( str.split("RIGHT", -1).length ) - 1;
int countDOWN = ( str.split("DOWN", -1).length ) - 1;
The restriction can be verified by comparing the int values to the limits of the box (10*10 in your case).
For the position, if we suppose each movement is 1 unit then :
int x = 0; //starting point in Ox axis
int y = 0; //starting point in Oy axis
x = countRIGHT - CountLeft;
y = countUP - CountDOWN;
The couple (x,y) is the position of your robot.
move function :
int[] walk(String path) {
int[] position = {0,0};
int countUP = ( path.split("UP", -1).length ) - 1; //Counts how many UP command
int countLEFT = ( path.split("LEFT", -1).length ) - 1; //Counts how many LEFT command
int countRIGHT = ( path.split("RIGHT", -1).length ) - 1; //Counts how many RIGHT command
int countDOWN = ( path.split("DOWN", -1).length ) - 1; //Counts how many DOWN command
position[0] = countRIGHT - countLEFT;
position[1] = countUP - countDown;
return position;
}
for version 2 you could split your original string and put it in an array with a method you can call on a string String [] tmpsplit = tmp.split(" ");. That way your array has inside each cell one direction (UP or DOWN or LEFT or RIGHT).
Then you can put this array in a similar for with the one that you have for version 1. Replace the charFromPath == 'U' with tmpsplit[i].equals("UP")
Related
currently my program is only always giving me 4, how can I determine how many steps the ant took to cover the whole board? The ant can walk up down left right, but can't walk off the board, and then do this simulation 4 times.
public static void main(String args[]) {
int[][] grid = new int[8][8];
int count = 0;
int x = 0;
int y = 0; // arrays are 0 based
while(true)
{
int random = (int)Math.random()*4+1;
if (random == 1)
{
x--; // move left
}
else if (random == 2)
{
x++; // move right
}
else if (random == 3)
{
y--; // move down
}
else if (random == 4)
{
y++; // move up
}
if(x < 0 || y < 0 || x >= grid.length || y >= grid[x].length) break;
count++;
grid[x][y]++;
}
System.out.println("Number of Steps in this simulation: " + count); // number of moves before it fell
}
}
The problem is this expression:
int random = (int)Math.random()*4+1;
Through the explicit cast, only Math.random() ist casted to int. But since Math.random() returns a dobule < 1, it is casted to 0 and thus random is always 1 and the method always returns 0.
The problem can be fixed by casting Math.random() * 4:
int random = (int) (Math.random() * 4) + 1;
The parenthesis enforce that the value of Math.random() * 4 (which will be a value in the interval [0, 3)) will be casted to int.
Two remarks on your code:
I would recommend introducing an enum Direction with four values (one for each direction) and choose a random Direction by calling Direction.values()[(int) (Math.random() * 4)];
I would recommend to use a switch instead of the if-else-if cascade.
Ideone demo
The program will exit the while(true) loop once one of the 4 conditions is true. My suggestion is to move these conditions in your if(random == value) checks like this:
if( random == 1 )
{
x--;
if (x < 0 )
{
x++;
}
}
Now to exit your while(true) loop you need to have an extra condition. I would suggest to think about your board in terms of 0's and 1's. Everytime the ant cross a cell, you set the grid[x][y] = 1.
int stepsTaken = 0;
int cellsToCover = grid.length * grid[0].length ;
int coveredCells = 0;
while(true)
{
//your code here
if( random == 1 )
{
stepsTaken++;
x--;
if (x < 0 )
{
x++;
}
}
// the other if's with "stepsTaken" incremented too.
if ( grid[x][y] == 0 )
{
grid[x][y] = 1;
coveredCells++;
}
if (coveredCells == cellsToCover )
break;
}
But please notice the many ifs statements inside a while(true) loop. If you have to fill a board of 10 rows x 10 columns it would take too much until the board is filled. Instead I would suggest you to use some more efficient algorithms like backtracking, dynamic programming etc.
Edit : Added step counter.
I know that there's a lot of other maze solver here. Though I would like to have my own approach and I think my problem is a bit different from the others.
As of now, here's what I've started and hopefully I can achieve what I have in mind at the moment.
private static int getPossiblePaths(File f) throws IOException {
int counts = 0; // hope to return all possible paths
// read input file then put it on list string
List<String> lines = Files.lines(f.toPath()).collect(Collectors.toList());
// get the row and column (dimensions)
String[] dimensions = lines.get(0).split(",");
//initalize sub matrix of the maze dimensions and ignoring the top and bottom walls
int[][] mat = new int[Integer.valueOf(dimensions[0]) - 2 ][Integer.valueOf(dimensions[1]) - 2];
//for each line in the maze excluding the boundaries (top and bottom)
for( int i = 2 ; i < lines.size() - 1 ; i++) {
String currLine = lines.get(i);
int j = 0;
for(char c : currLine.toCharArray()) {
mat[i-2][j] = (c=='*' ? 'w' : c=='A' ? 'a' : c=='B' ? 'b' : 's');
// some conditional statements here
}
}
// or maybe some conditional statements here outside of the loop
return counts;
}
And the maze from a text file is look like this. Please note that the A could be anywhere and same as B. The only movements allowed is to right and down.
5,5
*****
*A *
* *
* B*
*****
Expected output for the maze above is 6 (possible paths from A to B).
EDIT: Also the maze from the text file could be like this:
8,5
********
* A *
* B*
* *
********
So with my current code, it is getting the dimensions (first line) and removing the top and bottom part of the maze (boundaries). So there's only 3 lines of characters currently stored in the mat array. And some encoding of each characters of the text file (#=w(wall), A=a(start), B=b(end), else s(space))
I would like to have some conditional statements inside of the foreach to probably store the each of characters inside of an ArrayList. Though I'm not sure if this approach will just make my life harder.
Any suggestions, tips, advice or other easier approach from you guys will greatly appreciated! Thank you
The idea to create mat is fine. I would not bother to strip off the first and last line, as in fact it will be easier to work with when you keep them. That way a row reference like i-1 will not go out of range when you are at a non-wall location.
I would also not store characters like w in there, but specific numbers, like -1 for wall, 0 for free. Also store 0 for "A" and "B". When encountering those two letters, you could store their coordinates in specific variables (e.g. rowA, colA, rowB, colB). You may need to check whether B is down-right from A, as otherwise B is certainly not reachable from A.
So I would define mat as follows (note that I reversed the dimensions, because your second example demonstrates that the first line of the input has them in that order):
int[][] mat = new int[Integer.valueOf(dimensions[1])]
[Integer.valueOf(dimensions[0])];
int colA = mat[0].length;
int rowA = 0;
int colB = colA;
int rowB = 0;
for (int i = 0; i < mat.length; i++) {
String currLine = lines.get(i+1);
int j = 0;
for (char c : currLine.toCharArray()) {
mat[i][j] = c == '*' ? -1 : 0;
if (c == 'B') {
if (colA > j) return 0; // B unreachable from A
rowB = i;
colB = j;
} else if (c == 'A') {
if (colB < j) return 0; // B unreachable from A
rowA = i;
colA = j;
}
j++;
}
}
With this setup you can reuse mat to store the number of paths from A to the current position. The value 0 at A should be set to 1 (there is one path from A to A), and then it is a matter of adding up the value from the cell above and left, making sure that -1 is treated as a 0.
mat[rowA][colA] = 1;
for (int i = rowA; i <= rowB; i++) {
for (int j = colA; j <= colB; j++) {
if (mat[i][j] == 0) { // not a wall?
// count the number of paths that come from above,
// plus the number of paths that come from the left
mat[i][j] = Math.max(0, mat[i-1][j]) + Math.max(0, mat[i][j-1]);
}
}
}
return mat[rowB][colB]; // now this has the number of paths we are looking for
Although a recursive method will also work, I would suggest the above dynamic programming approach, since that way you avoid to recalculate counts for a certain cell several times (when coming there via different DFS paths). This solution has a linear time complexity.
I propose a simple recursion with 2 calls: down and right.
This is the code:
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class JavaMazeInsideOfWallsAndGetAllPossiblePaths {
public static void main(String[] args) throws IOException, URISyntaxException {
Path mazePath = Paths.get( MethodHandles.lookup().lookupClass().getClassLoader()
.getResource("maze.txt").toURI());
File mazeFile = mazePath.toFile();
System.out.println(getPossiblePaths(mazeFile));
}
private static int getPossiblePaths(File f) throws IOException {
// read input file then put it on list string
List<String> lines = Files.lines(f.toPath()).collect(Collectors.toList());
// get the row and column (dimensions)
String[] dimensions = lines.get(0).split(",");
//initalize sub matrix of the maze dimensions and ignoring the top and bottom walls
int[][] mat = new int[Integer.valueOf(dimensions[0]) - 2 ][Integer.valueOf(dimensions[1]) - 2];
int fromRow = -1, fromCol = -1, toRow = -1, toCol = -1;
for( int i = 2 ; i < lines.size() - 1 ; i++) {
String currLine = lines.get(i);
int j = 0;
for(char c : currLine.toCharArray()) {
switch(c) {
case '*':
continue; // for loop
case 'A':
mat[i-2][j] = 0;
fromRow = i-2;
fromCol = j;
break;
case 'B':
mat[i-2][j] = 2;
toRow = i-2;
toCol = j;
break;
default:
mat[i-2][j] = 1;
}
j++;
}
}
return getPossiblePathsRecursive(mat, fromRow, fromCol, toRow, toCol);
}
private static int getPossiblePathsRecursive(int[][] mat, int i, int j, int rows, int columns) throws IOException {
if(i > rows || j > columns) {
return 0;
}
if(mat[i][j] == 2) {
return 1;
}
return getPossiblePathsRecursive(mat, i+1, j, rows, columns) +
getPossiblePathsRecursive(mat, i, j + 1, rows, columns);
}
}
Notes:
1. The validation step is skipped (assuming that the input data is in a valid format)
2. The walls are ignored (assuming that there are always 4 walls - first row, last row, first column, last column. These walls are assumed to be represented as '*')
I'm trying to traverse through a maze recursively and im getting a stack overflow error, i understand the problem but am unable to fix it. Would i need to create a separate array to hold all the values that have been visited in the array or is there other ways that would be more efficient that use less lines of code?
Any suggestions would be greatly appreciated.
Here is the input;
5 6 // Row,Col
1 1 // Start Pos
3 4 // End Pos
1 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 0 1
1 1 1 1 1
Current code:
public class Solve {
private static int [][] MazeArray;
private static int Rows;
private static int Cols;
private static Point end = new Point();
private static Point start = new Point();
public static void ReadFileMakeMaze() {
Scanner in = new Scanner(System.in);
System.out.print("Select File: "); // Choose file
String fileName = in.nextLine();
fileName = fileName.trim();
String Buffer = "";
String[] Buffer2;
String[] MazeBuffer;
int Counter = 0;
try {
// Read input file
BufferedReader ReadFileContents = new BufferedReader(new FileReader(fileName+".txt"));
Buffer = ReadFileContents.readLine();
MazeBuffer = Buffer.split(" ");
// Creating MazeArray according to rows and columns from input file.
Rows = Integer.parseInt(MazeBuffer[0]);
Cols = Integer.parseInt(MazeBuffer[1]);
MazeArray = new int[Rows][Cols];
// Retrieving start locations and adding them to an X and Y coordinate.
String[] StartPoints = ReadFileContents.readLine().split(" ");
start.x = Integer.parseInt(StartPoints[0]);
start.y = Integer.parseInt(StartPoints[1]);
// Retrieving end locations and adding them to an X and Y coordinate.
String[] EndPoints = ReadFileContents.readLine().split(" ");
end.x = Integer.parseInt(EndPoints[0]);
end.y = Integer.parseInt(EndPoints[1]);
while(ReadFileContents.ready()) {
Buffer = ReadFileContents.readLine();
Buffer2 = Buffer.split(" ");
for(int i = 0; i < Buffer2.length; i++) {
MazeArray[Counter][i] = Integer.parseInt(Buffer2[i]); // Adding file Maze to MazeArray.
}
Counter ++;
}
}
catch(Exception e){
System.out.println(e); // No files found.
}
System.out.println(SolveMaze(start.x, start.y));
}
public static boolean SolveMaze(int x,int y) {
Print(); // Printing the maze
if(ReachedEnd(x,y)) {
MazeArray[x][y] = 5; // 5 represents the end
System.out.println(Arrays.deepToString(MazeArray));
return true;
}else if(MazeArray[x][y] == 1 || MazeArray[x][y] == 8){
return false;
}else {
MazeArray[x][y] = 8; // Marking the path with 8's
start.x = x;
start.y = y;
// Checking all directions
if(MazeArray[x][y - 1] == 0 ) {
System.out.println("Left");
SolveMaze(x, y - 1);
}else if(MazeArray[x + 1][y] == 0) {
System.out.println("Down");
SolveMaze(x + 1, y);
}else if(MazeArray[x - 1][y] == 0 ) {
System.out.println("Up");
SolveMaze(x - 1, y);
}else if(MazeArray[x][y + 1] == 0 ) {
System.out.println("Right");
SolveMaze(x, y + 1);
}else {
System.out.println("Debug");
MazeArray[x][y] = 0;
start.x = x;
start.y = y;
}
}
return false;
}
public static boolean DeadEnd(int x, int y) {
return true; // Solution needed
}
public static boolean ReachedEnd(int x, int y) {
if(x == end.x && y == end.y) { // Check if the end has been reached.
return true;
}else {
return false;
}
}
public static void Print() {
System.out.println(Arrays.deepToString(MazeArray));
}
public static void main(String[] args) {
ReadFileMakeMaze();
}
}
Firstly, like you mentioned in the question, creating a static Collection outside of SolveMaze which keeps a list of "visited" nodes would certainly help. If the node has being visited before then no need to check again.
Secondly, I believe there are a few mistakes within the above code. The table isn't generated correctly into the MazeArray[][], swap Rows and Cols around underneath "// Creating MazeArray according to rows and columns from input file."
The code also doesn't "find" a path, Arrays get defined as int[] array = new int[5] but to access it you have to use array[0] --> array[4] , what happens when I fix the maze is that you start on element 1,1 which is the '0' one row and column in from top left. Then you traverse down the list due to the ordering of the if else statements. After visiting each node you turn the nodes value to an 8. After 4 iterations the code is looking at the bottom 0 in the 2nd row, aka [4][1] above you is now and 8 and since 0's are the only elements you can move to, the node looks left, right and down and sees 1's, then turns and looks up and sees an 8. Thus finishing.
Thirdly, don't make checking up, down, left, right a set of "if else"'s, just a selection of "if's". This way the code will travel all paths. Then you can leave your 8's in and it will de facto not re-run the same node twice, rendering the 'visited' array unneeded. (Although as a general rule, mutating state when traversing through is unadvised)
Fourthly, I cannot get a stack overflow error from the above code so cannot answer the actual question.
On a side note - use tests and things like this become trivial, start small and build it up :) If unsure just checkout junit.
When I say efficient I mean code that isn't cpu intensive.
The Problem:
I have a field of blocks. Like in the following image:
Every single one of these blocks represents an instance of a self-made Block class. This block class has a List<Block> neighBours, where the neighbours of the block are stored. So every single block in the image knows which blocks are next to it.
What I want to do is to pick any block from this image, and compute how many "steps" away this block is. For example if I pick the block in the top left, I want to have a Map<Block, Integer> representing how many "steps" away each block is from the picked block. Like this:
Now before you say "Just store it's position X and Y in the block class and calculate the difference X + difference Y", that wouldn't work because the field can have gaps(represented by red color) between them like the following image:
And as you might notice, the block next to the gap that was first 4 steps away, is now 6 steps away. Thus the best way(I presume) to get how many steps away the other blocks are is by using a recursive algorith that makes use of the neighbour info. I couldn't make an efficient one myself and I was hoping someone might know something that works well.
Several problems I came across are the fact that because all blocks know their neighbours, the recursive algorithm would go indefinately back and forth between the first and second block. Or the fact that when using the algorithm on a 11x11 field, there were 3284 method calls, which seems waaay too high for an 11x11 field.
Question:
So the question I have is: What is an efficient way, using the knowledge of what neighbours each block has, to get how many steps away each block is.
Code:
This is the current code that I have incase anyone wants to see it.
public class Block
{
List<Block> neighBours;
public Block(List<Block> neighBours)
{
this.neighBours = neighBours;
}
public Map<Block, Integer> getStepsAway()
{
Map<Block, Integer> path = new HashMap<Block, Integer>();
getPaths(path, 0, 100);
return path;
}
public void getPaths(Map<Block, Integer> path, int pathNumber, int maxPathNumber)
{
if(pathNumber <= maxPathNumber)
{
for(Block block : neighBours)
{
Integer thePathNumber = path.get(block);
if(thePathNumber != null)
{
if(pathNumber < thePathNumber)
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
else
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
}
}
}
Recursive algorithms are doomed to fail on a large grid. Java is not designed for deep recursions and can only withstand a few thousands recursive calls before failing with a StackOverflowException. Only iterative solutions are a reasonible approach for large pathfinding problems in Java.
Of course you can always use a classic pathfinding algorithm such as A*, but you would have to apply it for each cell, which would be extremely expensive.
Indeed, your problem is a bit particular in the sense you want to calculate the minimum distance to all cells and not only just one. Therefore, you can do it in a more clever way.
One property of your problem is that given A and B, if the minimal path from A to B contains C then this path is also minimal from A to C and from C to B. That's what my intuition tells me, but it would need to be proven before implementing my suggestion.
The algorithm I propose is efficient, uses O(n) memory and has O(n^2) runtime complexity (cannot be faster since you need to set this many cells in the array):
start with your first point and set the distance of all its valid neighbours to 1. Doing so, you will record the border, which is all the cells at distance 1 from the first cell.
then, you iterate over the border and take all their neighbours which have not already been assigned a distance and assign them distance 2. All cells of distance 2 become your new border.
iterate until the border is empty
Below is a full working solution. The code may be improved in various ways using more convenience methods for initializing and printing matrices of objects and primitive integers, but you get the idea:
public class Solution {
public enum Cell { FREE, BLOCKED }
// assuming cells is a rectangular array with non-empty columns
public static int[][] distances(Cell[][] cells, ArrayCoordinate startingPoint) {
int[][] distances = new int[cells.length][cells[0].length];
// -1 will mean that the cell is unreachable from the startingPoint
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
distances[i][j] = -1;
}
}
distances[startingPoint.i][startingPoint.j] = 0;
Set<ArrayCoordinate> border = startingPoint.validNeighbours(cells);
for (int currentDistance = 1; !border.isEmpty(); currentDistance++) {
Set<ArrayCoordinate> newBorder = new HashSet<>();
for (ArrayCoordinate coord : border) {
distances[coord.i][coord.j] = currentDistance;
for (ArrayCoordinate neighbour : coord.validNeighbours(cells)) {
if (distances[neighbour.i][neighbour.j] < 0) {
newBorder.add(neighbour);
}
}
}
border = newBorder;
}
return distances;
}
private static class ArrayCoordinate {
public ArrayCoordinate(int i, int j) {
if (i < 0 || j < 0) throw new IllegalArgumentException("Array coordinates must be positive");
this.i = i;
this.j = j;
}
public final int i, j;
public Set<ArrayCoordinate> validNeighbours(Cell[][] cells) {
Set<ArrayCoordinate> neighbours = new HashSet<>();
// inlining for not doing extra work in a loop iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a loop
addIfValid(cells, neighbours, 1, 0);
addIfValid(cells, neighbours, -1, 0);
addIfValid(cells, neighbours, 0, 1);
addIfValid(cells, neighbours, 0, -1);
return neighbours;
}
private void addIfValid(Cell[][] cells, Set<ArrayCoordinate> neighbours, int dx, int dy) {
int x = i + dx, y = j + dy;
if (0 <= x && 0 <= y && x < cells.length && y < cells[0].length && cells[x][y] == Cell.FREE) {
neighbours.add(new ArrayCoordinate(i + dx, j + dy));
}
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArrayCoordinate point = (ArrayCoordinate) o;
if (i != point.i) return false;
if (j != point.j) return false;
return true;
}
#Override
public int hashCode() {
int result = i;
result = 31 * result + j;
return result;
}
}
public static void main(String[] args) {
int n = 11, m = 5;
Cell[][] cells = new Cell[n][m];
cells[1][1] = Cell.BLOCKED;
cells[1][2] = Cell.BLOCKED;
cells[2][1] = Cell.BLOCKED;
ArrayCoordinate startingPoint = new ArrayCoordinate(5, 2);
System.out.println("Initial matrix:");
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
if (cells[i][j] == null) {
cells[i][j] = Cell.FREE;
}
if (startingPoint.i == i && startingPoint.j == j) {
System.out.print("S ");
} else {
System.out.print(cells[i][j] == Cell.FREE ? ". " : "X ");
}
}
System.out.println();
}
int[][] distances = distances(cells, startingPoint);
System.out.println("\nDistances from starting point:");
for (int i = 0; i < distances.length; i++) {
for (int j = 0; j < distances[0].length; j++) {
System.out.print((distances[i][j] < 0 ? "X" : distances[i][j]) + " ");
}
System.out.println();
}
}
}
Output:
Initial matrix:
. . . . .
. X X . .
. X . . .
. . . . .
. . . . .
. . S . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Distances from starting point:
7 8 7 6 7
6 X X 5 6
5 X 3 4 5
4 3 2 3 4
3 2 1 2 3
2 1 0 1 2
3 2 1 2 3
4 3 2 3 4
5 4 3 4 5
6 5 4 5 6
7 6 5 6 7
Bonus
I almost cried when I saw all this boilerplate in my Java solution, so I wrote a shorter (perhaps slightly less efficient) version in Scala:
object ScalaSolution {
sealed abstract class Cell
object Free extends Cell
object Blocked extends Cell
// assuming cells is a rectangular array with non-empty columns
def distances(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// -1 will mean that the cell is unreachable from the startingPoint
val distances = Array.fill[Int](cells.length, cells(0).length)(-1)
distances(startingPoint._1)(startingPoint._2) = 0
var (currentDistance, border) = (1, validNeighbours(cells, startingPoint))
while (border.nonEmpty) {
border.foreach { case (i, j) => distances(i)(j) = currentDistance }
border = border.flatMap(validNeighbours(cells, _)).filter { case (i, j) => distances(i)(j) < 0 }
currentDistance += 1
}
distances
}
private def validNeighbours(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// inlining for not doing extra work in a for yield iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a for yield
Set(neighbourIfValid(cells, startingPoint, ( 1, 0)),
neighbourIfValid(cells, startingPoint, (-1, 0)),
neighbourIfValid(cells, startingPoint, ( 0, 1)),
neighbourIfValid(cells, startingPoint, ( 0, -1)))
.flatten
}
private def neighbourIfValid(cells: Array[Array[Cell]], origin: (Int, Int), delta: (Int, Int)) = {
val (x, y) = (origin._1 + delta._1, origin._2 + delta._2)
if (0 <= x && 0 <= y && x < cells.length && y < cells(0).length && cells(x)(y) == Free) {
Some(x, y)
} else None
}
def main (args: Array[String]): Unit = {
val (n, m) = (11, 5)
val cells: Array[Array[Cell]] = Array.fill(n, m)(Free)
cells(1)(1) = Blocked
cells(1)(2) = Blocked
cells(2)(1) = Blocked
val startingPoint = (5, 2)
println("Initial matrix:")
printMatrix(cells)((i, j, value) => if ((i, j) == startingPoint) "S" else if (value == Free) "." else "X")
val distancesMatrix = distances(cells, startingPoint)
println("\nDistances from starting point:")
printMatrix(distancesMatrix)((i, j, value) => if (value < 0) "X" else value.toString)
}
private def printMatrix[T](matrix: Array[Array[T]])(formatter: (Int, Int, T) => String) = {
for (i <- 0 until matrix.length) {
for (j <- 0 until matrix(0).length) {
print(formatter(i, j, matrix(i)(j)) + " ")
}
println()
}
}
}
I believe there is a DP (dynamic programming) solution to this problem, looking at this, code below. I realize this is for finding all possible paths to a cell but it can give insight on your condition about 'blanks' or 'walls'
#include <iostream>
using namespace std;
// Returns count of possible paths to reach cell at row number m and column
// number n from the topmost leftmost cell (cell at 1, 1)
int numberOfPaths(int m, int n)
{
// Create a 2D table to store results of subproblems
int count[m][n];
// Count of paths to reach any cell in first column is 1
for (int i = 0; i < m; i++)
count[i][0] = 1;
// Count of paths to reach any cell in first column is 1
for (int j = 0; j < n; j++)
count[0][j] = 1;
// Calculate count of paths for other cells in bottom-up manner using
// the recursive solution
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
// By uncommenting the last part the code calculatest he total
// possible paths if the diagonal Movements are allowed
count[i][j] = count[i-1][j] + count[i][j-1]; //+ count[i-1][j-1];
}
return count[m-1][n-1];
}
In an attempt to write a brute force maze solving C program, I've written this java program first to test an idea. I'm very new to C and intend to convert it after getting this right in java. As a result, I'm trying stick away from arraylists, fancy libraries, and such to make it easier to convert to C. The program needs to generate a single width path of shortest steps to solve a maze. I think my problem may be in fragmenting a path-storing array passed through each recursion. Thanks for looking at this. -Joe
maze:
1 3 3 3 3
3 3 3 3 3
3 0 0 0 3
3 0 3 3 3
0 3 3 3 2
Same maze solved by this program:
4 4 4 4 4
4 4 4 4 4
4 0 0 0 4
3 0 3 3 4
0 3 3 3 2
number notation are explained in code
public class javamaze {
static storage[] best_path;
static int best_count;
static storage[] path;
//the maze - 1 = start; 2 = finish; 3 = open path
static int maze[][] = {{1, 3, 3, 3, 3},
{3, 3, 3, 3, 3},
{0, 0, 0, 0, 3},
{0, 0, 3, 3, 3},
{3, 3, 3, 3, 2}};
public static void main(String[] args) {
int count1;
int count2;
//declares variables used in the solve method
best_count = 0;
storage[] path = new storage[10000];
best_path = new storage[10000];
int path_count = 0;
System.out.println("Here is the maze:");
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
System.out.print(maze[count1][count2] + " ");
}
System.out.println("");
}
//solves the maze
solve(findStart()/5, findStart()%5, path, path_count);
//assigns an int 4 path to the maze to visually represent the shortest path
for(int count = 0; count <= best_path.length - 1; count++)
if (best_path[count] != null)
maze[best_path[count].getx()][best_path[count].gety()] = 4;
System.out.print("Here is the solved maze\n");
//prints the solved maze
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++){
System.out.print(maze[count1][count2] + " ");
}
System.out.print("\n");
}
}
//finds maze start marked by int 1 - this works perfectly and isn't related to the problem
public static int findStart() {
int count1, count2;
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
if (maze[count1][count2] == 1)
return (count1 * 5 + count2);
}
}
return -1;
}
//saves path coordinate values into a new array
public static void save_storage(storage[] old_storage) {
int count;
for(count = 0; count < old_storage.length; count++) {
best_path[count] = old_storage[count];
}
}
//solves the maze
public static Boolean solve(int x, int y, storage[] path, int path_count) {
//checks to see if grid squares are valid (3 = open path; 0 = wall
if (x < 0 || x > 4) { //array grid is a 5 by 5
//System.out.println("found row end returning false");
return false;
}
if (y < 0 || y > 4) {
//System.out.println("Found col end returning false");
return false;
}
//when finding finish - records the number of moves in static int best_count
if (maze[x][y] == 2) {
if (best_count == 0 || best_count > path_count) {
System.out.println("Found end with this many moves: " + path_count);
best_count = path_count;
save_storage(path); //copies path counting array into a new static array
}
}
//returns false if it hits a wall
if (maze[x][y] == 0)
return false;
//checks with previously crossed paths to prevent an unnecessary repeat in steps
for(storage i: path)
if (i != null)
if (i.getx() == x && i.gety() == y)
return false;
//saves current recursive x, y (row, col) coordinates into a storage object which is then added to an array.
//this array is supposed to fragment per each recursion which doesn't seem to - this may be the issue
storage storespoints = new storage(x, y);
path[path_count] = storespoints;
//recurses up, down, right, left
if (solve((x-1), y, path, path_count++) == true || solve((x+1), y, path, path_count++) == true ||
solve(x, (y+1), path, path_count++) == true || solve(x, (y-1), path, path_count++) == true) {
return true;
}
return false;
}
}
//stores (x, y) aka row, col coordinate points
class storage {
private int x;
private int y;
public storage(int x, int y) {
this.x = x;
this.y = y;
}
public int getx() {
return x;
}
public int gety() {
return y;
}
public String toString() {
return ("storage coordinate: " + x + ", " + y + "-------");
}
}
This wasn't originally intended to be an answer but it sort of evolved into one. Honestly, I think starting in Java and moving to C is a bad idea because the two languages are really nothing alike, and you won't be doing yourself any favors because you will run into serious issues porting it if you rely on any features java has that C doesn't (i.e. most of them)
That said, I'll sketch out some algorithmic C stuff.
Support Structures
typedef
struct Node
{
int x, y;
// x and y are array indices
}
Node;
typedef
struct Path
{
int maxlen, head;
Node * path;
// maxlen is size of path, head is the index of the current node
// path is the pointer to the node array
}
Path;
int node_compare(Node * n1, Node * n2); // returns true if nodes are equal, else false
void path_setup(Path * p, Node * n); // allocates Path.path and sets first node
void path_embiggen(Path * p); // use realloc to make path bigger in case it fills up
int path_toosmall(Path * p); // returns true if the path needs to be reallocated to add more nodes
Node * path_head(Path * p); // returns the head node of the path
void path_push(Path * p, Node * n); // pushes a new head node onto the path
void path_pop(Path * p); // pops a node from path
You might to change your maze format into an adjacency list sort of thing. You could store each node as a mask detailing which nodes you can travel to from the node.
Maze Format
const int // these constants indicate which directions of travel are possible from a node
N = (1 << 0), // travel NORTH from node is possible
S = (1 << 1), // travel SOUTH from node is possible
E = (1 << 2), // travel EAST from node is possible
W = (1 << 3), // travel WEST from node is possible
NUM_DIRECTIONS = 4; // number of directions (might not be 4. no reason it has to be)
const int
START = (1 << 4), // starting node
FINISH = (1 << 5); // finishing node
const int
MAZE_X = 4, // maze dimensions
MAZE_Y = 4;
int maze[MAZE_X][MAZE_Y] =
{
{E, S|E|W, S|E|W, S|W },
{S|FINISH, N|S, N|START, N|S },
{N|S, N|E, S|E|W, N|S|W },
{N|E, E|W, N|W, N }
};
Node start = {1, 2}; // position of start node
Node finish = {1, 0}; // position of end node
My maze is different from yours: the two formats don't quite map to each other 1:1. For example, your format allows finer movement, but mine allows one-way paths.
Note that your format explicitly positions walls. With my format, walls are conceptually located anywhere where a path is not possible. The maze I created has 3 horizontal walls and 5 vertical ones (and is also enclosed, i.e. there is a continuous wall surrounding the whole maze)
For your brute force traversal, I would use a depth first search. You can map flags to directions in a number of ways, like maybe the following. Since you are looping over each one anyway, access times are irrelevant so an array and not some sort of faster associative container will be sufficient.
Data Format to Offset Mappings
// map directions to array offsets
// format is [flag], [x offset], [y offset]
int mappings[][] =
{
{N, -1, 0},
{S, 1, 0},
{E, 0, 1},
{W, 0, -1}
}
Finally, your search. You could implement it iteratively or recursively. My example uses recursion.
Search Algorithm Pseudocode
int search_for_path(int ** maze, char ** visited, Path * path)
{
Node * head = path_head(path);
Node temp;
int i;
if (node_compare(head, &finish)) return 1; // found finish
if (visited[head->x][head->y]) return 0; // don't traverse again, that's pointless
visited[head->x][head->y] = 1;
if (path_toosmall(path)) path_embiggen(path);
for (i = 0; i < NUM_DIRECTIONS; ++i)
{
if (maze[head->x][head->y] & mappings[i][0]) // path in this direction
{
temp = {head->x + mappings[i][1], head->y + mappings[i][2]};
path_push(path, &temp);
if (search_for_path(maze, visited, path)) return 1; // something found end
path_pop(path);
}
}
return 0; // unable to find path from any unvisited neighbor
}
To call this function, you should set everything up like this:
Calling The Solver
// we already have the maze
// int maze[MAZE_X][MAZE_Y] = {...};
// make a visited list, set to all 0 (unvisited)
int visited[MAZE_X][MAZE_Y] =
{
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
// setup the path
Path p;
path_setup(&p, &start);
if (search_for_path(maze, visited, &path))
{
// succeeded, path contains the list of nodes containing coordinates from start to end
}
else
{
// maze was impossible
}
It's worth noting that because I wrote this all in the edit box, I haven't tested any of it. It probably won't work on the first try and might take a little fiddling. For example, unless start and finish are declared globally, there will be a few issues. It would be better to pass the target node to the search function instead of using a global variable.