• Tidak ada hasil yang ditemukan

Finding a Path Through a Maze

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 161-165)

Recursion

5.9 Finding a Path Through a Maze

findOrg(W...) //returns immediately since G[W] is outside grid findOrg(W...) //returns immediately since G[W] is outside grid findOrg(W...) //returns immediately since G[W] is outside grid

When the call findOrg(2, 0, ...) finally returns, G would be changed to this:

0 2 0 3 3 3 0 0 0 3 3 0 0 0 4 4 0 3 0 0 1 4 0 1 0 0 1 1 4 4 0 0 0 1 0

The third organism (labeled 4) has been identified. Note that each cell in the organism gave rise to four calls to findOrg.

Whenever we go to an open space, we repeat this strategy. So, for instance, when we go east, if there is a space, we mark it and try the four directions from this new position.

Eventually, we will get out of the maze, or we will reach a dead-end position. For example, suppose we get to the position marked C:

##########

#C# # # #B# # ## # #A # # #x###### # #x# #x##

#xxxxx## # ##########

There are walls in all directions except south, from which we came. In this situation, we go back to the previous position and try the next possibility from there. In this example, we go back to the position south of C (call this B).

When we were at B, we would have got to C by trying the north direction. Since this failed, when we go back to B, we will try the “next” possibility, that is, east. This fails since there is a wall. So, we try south; this fails since we have already been there. Finally, we try west, which fails since there is a wall.

So, from B, we go back (we say backtrack) to the position from which we moved to B (call this A).

When we backtrack to A, the “next” possibility is east. There is a space, so we move into it, mark it with x, and try the first direction (north) from there.

When we backtrack from a failed position, we must “unmark” that position; that is, we must erase the x. This is necessary since a failed position will not be part of the solution path.

How do we backtrack? The recursive mechanism will take care of that for us, in a similar manner to the “counting organisms” problem. The following pseudocode shows how:

boolean findPath(P) {

//find a path from position P

if P is outside the maze, at a wall or considered already, return false //if we get here, P is a space we can move into

mark P with x

if P is on the border of the maze, we are out of the maze; return true //try to extend the path to the North; if successful, return true if (findPath(N)) return true;

//if North fails, try East, then South, then West if (findPath(E)) return true;

if (findPath(S)) return true;

if (findPath(W)) return true;

//if all directions fail, we must unmark P and backtrack mark P with space

return false; //we have failed to find a path from P } //end findPath

5.9.1 Writing the Program

First we must determine how the maze data will be supplied. In the example just discussed, the maze consists of eight rows and ten columns. If we represent each wall by 1 and each space by 0, the maze is represented by the following:

1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 0 1 1 0 0 0 1 0 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1

The start position, S, is at row 6, column 6. The first line of data will specify the number of rows and columns of the maze and the coordinates of S. Thus, the first line of data will be this:

8 10 6 6

This will be followed by the maze data, above.

When we need to mark a position with an x, we will use the value 2.

Our program will read data from the file maze.in and send output to maze.out. The complete program is shown as Program P5.3.

Program P5.3

import java.io.*;

import java.util.*;

public class Maze {

static int[][]G; //known to all methods static int m, n, sr, sc; //known to all methods

public static void main(String[] args) throws IOException { Scanner in = new Scanner(new FileReader("maze.in"));

PrintWriter out = new PrintWriter(new FileWriter("maze.out"));

getData(in);

if (findPath(sr, sc)) printMaze(out);

else out.printf("\nNo solution\n");

in.close(); out.close();

} // end main

public static void getData(Scanner in) { m = in.nextInt(); n = in.nextInt();

G = new int[m+1][n+1];

sr = in.nextInt(); sc = in.nextInt();

for (int r = 1; r <= m; r++) for (int c = 1; c <= n; c++) G[r][c] = in.nextInt();

} //end getData

public static boolean findPath(int r, int c) {

if (r < 1 || r > m || c < 1 || c > n) return false;

if (G[r][c] == 1) return false; //into a wall if (G[r][c] == 2) return false; //already considered // else G[r][c] = 0;

G[r][c] = 2; //mark the path

if (r == 1 || r == m || c == 1 || c == n) return true;

//path found - space located on the border of the maze

if (findPath(r-1, c)) return true;

if (findPath(r, c+1)) return true;

if (findPath(r+1, c)) return true;

if (findPath(r, c-1)) return true;

G[r][c] = 0; //no path found; unmark return false;

} //end findPath

public static void printMaze(PrintWriter out) { int r, c;

for (r = 1; r <= m; r++) { for (c = 1; c <= n; c++)

if (r == sr && c == sc) out.printf("S");

else if (G[r][c] == 0) out.printf(" ");

else if (G[r][c] == 1) out.printf("#");

else out.printf("x");

out.printf("\n");

}

} //end printMaze } //end class Maze

Suppose the file maze.in contains the following:

8 10 6 6

1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 0 1 1 0 0 0 1 0 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1

Program P5.3 will write the following output to the file, maze.out:

##########

# #xxx# # # #x#x## # #xxx#xxxx#

#x######x#

#x# #S##xx #xxxxx## # ##########

EXERCISES 5

1. Write an iterative function to return the nth Fibonacci number.

2. Print an integer with commas separating the thousands. For example, given 12058, print 12,058.

3. A

is an array containing n integers. Write a recursive function to find the number of times a

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 161-165)