import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; /** * * @author geoffreytowell * Holds and solves a maze */ public class Maze { /** The starting point */ public static final char START = 's'; /** The exit */ public static final char FINISH = 'e'; /** A wall you cant go through walls */ public static final char WWALL = '|'; /** A floor, you cant go through floors either */ public static final char FLOOR = '='; /** A pathway */ public static final char PATH = ' '; /** A pathway that leads to the solution */ public static final char SUCCESS_PATH = 'A'; /** A pathway that was tried and then backtracked */ public static final char FAIL_PATH = 'z'; /** * The internal representation of the maze * A 2d array of char */ char[][] mazeRep; /** * The legal move directions. In this case * up down, right and left. One space only. */ Coordinate[] moves = { new Coordinate(1, 0), new Coordinate(0, 1), new Coordinate(0, -1), new Coordinate(-1, 0) }; /** * Maze constructor. This takes the name of a file containing a maze and reads it into * the internal represenation. * @param fileName the name of the file containing the maze * @throws FileNotFoundException * @throws ImproperMazeException * @throws IOException */ public Maze(String fileName) throws IOException, FileNotFoundException, ImproperMazeException { // first read the file into an array list to get the dimensions of the maze ArrayList tmaz = new ArrayList<>(); int wid=-1; try (BufferedReader br = new BufferedReader(new FileReader(fileName)); ) { String lin; while ((lin=br.readLine())!=null) { if (wid>0 && lin.length()!=wid) { throw new ImproperMazeException("Maze must be a rectangle current width="+wid+" new line width="+lin.length()); } if (wid<0) wid=lin.length(); tmaz.add(lin); } } catch (FileNotFoundException fnf) { throw fnf; } catch (IOException ioe) { throw ioe; } // with the file read complete, fill in the internal representation mazeRep = new char[tmaz.size()][wid]; for (int i=0; i= mazeRep.length || c.getD2() >= mazeRep[c.getD1()].length) { //System.out.println(indt+" Off Grid"); return false; } // are we at the solution? if (mazeRep[c.getD1()][c.getD2()]==FINISH) { setCoordValue(c, SUCCESS_PATH); System.out.println(indt+" Solved"); return true; } // Are we at a floor or wall? if (mazeRep[c.getD1()][c.getD2()]==WWALL || mazeRep[c.getD1()][c.getD2()]==FLOOR) { //System.out.println(indt+" Wall"); return false; } // have we been here before (via some other path) if (mazeRep[c.getD1()][c.getD2()]==FAIL_PATH) { //System.out.println(indt+" Been here"); return false; } // We are at a valid path (we must be because we have checked for everything else) if (mazeRep[c.getD1()][c.getD2()]==PATH) { setCoordValue(c, SUCCESS_PATH); // Since we just moved, let make another move // try each of the possible moves unless one works. for (Coordinate mv : moves) { if (solve(new Coordinate(c, mv), depth+1)) return true; } // no path worked. so backtrack. Before doing do, put down a breadcrumb saying // I have been here. setCoordValue(c, FAIL_PATH); } //System.out.println(indt+" No way forward"); // only get here if have tried everythign and failed return false; } /** * Find the location of the starting point * @return the location of the starting point (or null if there is no start) */ public Coordinate getStart() { for (int i=0; i