import java.awt.Graphics; import java.awt.Color; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseMotionListener; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Scanner; import java.util.Set; import java.util.TreeSet; /** * This class creates and solves mazes. * It is intended to show instances of where recursive backtracking * can be helpful. * * @author Adam Blank * */ public class Maze { public static final int HEIGHT = 8; public static final int WIDTH = 8; public static DrawingPanel panel; /** This method does a "flood fill" of the DrawingPanel. * Every white cell that is reachable from (x, y) is * filled in with Color.GREEN. */ public static void paintbucket(int x, int y, Color toFill) { if (x >= 0 && y >= 0 && x < HEIGHT && y < WIDTH && panel.getColor(x, y).equals(toFill)) { pencil(x, y); panel.sleep(120); paintbucket(x - 1, y, toFill); paintbucket(x, y - 1, toFill); paintbucket(x + 1, y, toFill); paintbucket(x, y + 1, toFill); } } /** This method does a "flood fill" of the DrawingPanel. * Every white cell that is reachable from (x, y) is * filled in with Color.GREEN. * * This method is intended to demonstrate the difference * between using a Point and standard x, y coordinates. * In this case, it results in shorter code. */ public static void paintbucket(Point p) { if (!p.isOOB() && p.isPassage()) { pencil(p); panel.sleep(120); paintbucket(p.getAbove()); paintbucket(p.getBelow()); paintbucket(p.getLeft()); paintbucket(p.getRight()); } } /** This method solves the maze in the DrawingPanel * (if one exists). It fills the actual, correct path * in with Color.GREEN and any explored squares that are * not part of the solution path with Color.BLUE. * * Returns true when the maze is solvable and false otherwise. */ public static boolean solveMaze(Point p) { if (p.isGoal()) { p.makeVisited(); panel.sleep(300); return true; } if (!p.isOOB() && p.isPassage()) { p.makeVisited(); panel.sleep(300); if (solveMaze(p.getAbove()) || solveMaze(p.getBelow()) || solveMaze(p.getLeft()) || solveMaze(p.getRight())) { return true; } panel.sleep(300); p.makeDeadEnd(); return false; } return false; } /** This method colors the point p in the DrawingPanel * Color.GREEN. */ public static void pencil(Point p) { int x = p.getX(); int y = p.getY(); Graphics g = panel.getGraphics(); g.setColor(Color.GREEN); g.fillRect(x, y, 1, 1); } /** This method colors the coordinates (x, y) in the * DrawingPanel Color.GREEN. */ public static void pencil(int x, int y) { Graphics g = panel.getGraphics(); g.setColor(Color.GREEN); g.fillRect(x, y, 1, 1); } public static void main(String[] args) { panel = new DrawingPanel(WIDTH, HEIGHT); Graphics g = panel.getGraphics(); g.setColor(Color.BLACK); g.fillRect(0, 0, WIDTH, HEIGHT); g.fillRect(WIDTH - 1, HEIGHT - 1, 1, 1); panel.zoom(50); /* Draw a maze so we have something to solve */ generateMaze(new Point(0, 0), new TreeSet()); /* * Make the DrawingPanel solve the maze * when the user drags on a pixel. */ panel.addMouseListener((MouseListener) new MouseAdapter() { public void mouseClicked(MouseEvent e) { int x = e.getX() / panel.getZoom(); int y = e.getY() / panel.getZoom(); if (e.getButton() == MouseEvent.BUTTON3) { solveMaze(new Point(x, y)); } else { pencil(x, y); } } }); /* * Make the DrawingPanel figure out if the maze is * solvable when the user drags across pixels. */ panel.addMouseMotionListener((MouseMotionListener) new MouseAdapter() { public void mouseDragged(MouseEvent e) { int x = e.getX() / panel.getZoom(); int y = e.getY() / panel.getZoom(); paintbucket(new Point(x, y)); } }); } /** This method generates a maze in the DrawingPanel. */ private static void generateMaze(Point p, Set seen) { if (seen.contains(p)) { return; } seen.add(p); p.makePassage(); String[] dirs = new String[]{"left", "right", "up", "down"}; Collections.shuffle(Arrays.asList(dirs)); for (String dir : dirs) { Point newLocation = null; if (dir.equals("left")) {newLocation = p.getLeft();} if (dir.equals("right")) {newLocation = p.getRight();} if (dir.equals("up")) {newLocation = p.getAbove();} if (dir.equals("down")) {newLocation = p.getBelow();} if (!newLocation.isOOB() && !seen.contains(newLocation)) { if (dir.equals("left") || dir.equals("right")) { seen.add(p.getAbove()); seen.add(p.getBelow()); } if (dir.equals("up") || dir.equals("down")) { seen.add(p.getLeft()); seen.add(p.getRight()); } generateMaze(newLocation, seen); } } } }